aboutsummaryrefslogtreecommitdiff
path: root/src/fs/gnunet-fs-gtk_main-window-namespace-dropdown.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs/gnunet-fs-gtk_main-window-namespace-dropdown.c')
-rw-r--r--src/fs/gnunet-fs-gtk_main-window-namespace-dropdown.c363
1 files changed, 156 insertions, 207 deletions
diff --git a/src/fs/gnunet-fs-gtk_main-window-namespace-dropdown.c b/src/fs/gnunet-fs-gtk_main-window-namespace-dropdown.c
index 47f48f8d..8093ba2d 100644
--- a/src/fs/gnunet-fs-gtk_main-window-namespace-dropdown.c
+++ b/src/fs/gnunet-fs-gtk_main-window-namespace-dropdown.c
@@ -27,13 +27,27 @@
27#include "gnunet-fs-gtk.h" 27#include "gnunet-fs-gtk.h"
28 28
29/** 29/**
30 * How long until we automatically hide the drop-down if the cursor is outside the bounds?
31 */
32#define AUTO_HIDE_TIMEOUT_MS 100
33
34
35/**
36 * ID of a timeout task which we schedule to close the drop-down automatically
37 * if the mouse leaves the area for a while. 0 for no such task.
30 * 38 *
39 * FIXME: this task is not cancelled if the main window is closed while
40 * the drop-down is down.
31 */ 41 */
32static guint namespace_selector_window_leave_timeout_source; 42static guint namespace_selector_window_leave_timeout_source;
33 43
34 44
35/** 45/**
46 * The mouse has re-entered the dropdown window. Stop the
47 * timeout task that would hide the dropdown.
36 * 48 *
49 * @param widget the dropdown widget
50 * @param event the mouse-enter event
37 * @param user_data the builder for the main window 51 * @param user_data the builder for the main window
38 */ 52 */
39gboolean 53gboolean
@@ -43,13 +57,16 @@ GNUNET_FS_GTK_search_namespace_dropdown_button_enter_notify_event_cb (GtkWidget
43{ 57{
44 if (namespace_selector_window_leave_timeout_source > 0) 58 if (namespace_selector_window_leave_timeout_source > 0)
45 g_source_remove (namespace_selector_window_leave_timeout_source); 59 g_source_remove (namespace_selector_window_leave_timeout_source);
60 namespace_selector_window_leave_timeout_source = 0;
46 return FALSE; 61 return FALSE;
47} 62}
48 63
49 64
50/** 65/**
66 * Run when the timeout has expired. Hides the drop down window.
51 * 67 *
52 * @param user_data the builder for the main window 68 * @param user_data the toggle button which we will use to hide the dropdown
69 * @return FALSE
53 */ 70 */
54static gboolean 71static gboolean
55namespace_selector_window_leave_timeout_cb (gpointer user_data) 72namespace_selector_window_leave_timeout_cb (gpointer user_data)
@@ -57,12 +74,16 @@ namespace_selector_window_leave_timeout_cb (gpointer user_data)
57 GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (user_data); 74 GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (user_data);
58 75
59 /* This will eventually hide the namespace selector */ 76 /* This will eventually hide the namespace selector */
77 namespace_selector_window_leave_timeout_source = 0;
60 gtk_toggle_button_set_active (toggle_button, FALSE); 78 gtk_toggle_button_set_active (toggle_button, FALSE);
61 return FALSE; 79 return FALSE;
62} 80}
63 81
64 82
65/** 83/**
84 * The cursor has left the window. Place a timeout to hide the
85 * window. It will be cancelled if the cursor re-enters the namespace
86 * selector window or the toggle button within 100ms
66 * 87 *
67 * @param user_data the builder for the main window 88 * @param user_data the builder for the main window
68 */ 89 */
@@ -71,230 +92,166 @@ GNUNET_FS_GTK_search_namespace_selector_window_leave_notify_event_cb (GtkWidget
71 GdkEvent * event, 92 GdkEvent * event,
72 gpointer user_data) 93 gpointer user_data)
73{ 94{
74 GtkBuilder *builder; 95 GtkBuilder *builder = GTK_BUILDER (user_data);
75 GtkToggleButton *toggle_button; 96 GtkToggleButton *toggle_button;
76 guint timeout_id;
77
78 builder = GTK_BUILDER (user_data);
79 97
80 toggle_button = 98 toggle_button =
81 GTK_TOGGLE_BUTTON (gtk_builder_get_object 99 GTK_TOGGLE_BUTTON (gtk_builder_get_object
82 (builder, 100 (builder,
83 "main_window_search_namespace_dropdown_button")); 101 "main_window_search_namespace_dropdown_button"));
84
85 /* Place a timeout to hide the window. It will be cancelled if the cursor
86 * enters the namespace selector window or the toggle button within 100ms.
87 */
88 timeout_id =
89 g_timeout_add (100, &namespace_selector_window_leave_timeout_cb,
90 toggle_button);
91 if (namespace_selector_window_leave_timeout_source > 0) 102 if (namespace_selector_window_leave_timeout_source > 0)
92 g_source_remove (namespace_selector_window_leave_timeout_source); 103 g_source_remove (namespace_selector_window_leave_timeout_source);
93 namespace_selector_window_leave_timeout_source = timeout_id; 104 namespace_selector_window_leave_timeout_source
94 105 = g_timeout_add (AUTO_HIDE_TIMEOUT_MS,
106 &namespace_selector_window_leave_timeout_cb,
107 toggle_button);
95 return FALSE; 108 return FALSE;
96} 109}
97 110
98 111
99/** 112/**
100 * 113 * Given a tree view, find out which row is currently selected.
114 *
115 * @param tree a tree view instance
116 * @return a reference to the currently selected row, or NULL for none
101 */ 117 */
102static gboolean 118static GtkTreeRowReference *
103get_selected_namespace_treepath_iter_model_widget (GtkBuilder * builder, 119get_selected_row_from_treeview (GtkTreeView * tree)
104 GtkTreePath ** p_treepath,
105 GtkTreeIter * p_iter,
106 GtkTreeModel ** p_model,
107 GtkWidget ** p_widget)
108{ 120{
109 GtkTreeSelection *selection; 121 GtkTreeSelection *sel;
110 GtkTreeModel *model; 122 GtkTreeModel *model;
111 GList *selected; 123 GtkTreePath *path;
112 GtkTreePath *treepath; 124 GtkTreeIter iter;
113 GtkWidget *widget; 125 GtkTreeRowReference *ref;
114
115 widget =
116 GTK_WIDGET (gtk_builder_get_object
117 (builder, "namespace_selector_treeview"));
118 if (!widget)
119 return FALSE;
120
121 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
122 model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
123 if (!selection || !model)
124 return FALSE;
125
126 selected = gtk_tree_selection_get_selected_rows (selection, NULL);
127 if (!selected)
128 return FALSE;
129 if (selected->data == NULL)
130 {
131 g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
132 g_list_free (selected);
133 return FALSE;
134 }
135 /* Free everything except the first path, keep it */
136 treepath = (GtkTreePath *) selected->data;
137 selected = g_list_remove (selected, selected->data);
138 g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
139 g_list_free (selected);
140 126
141 if (p_iter && !gtk_tree_model_get_iter (model, p_iter, treepath)) 127 sel = gtk_tree_view_get_selection (tree);
142 { 128 if (! gtk_tree_selection_get_selected (sel, &model, &iter))
143 gtk_tree_path_free (treepath); 129 return NULL;
144 return FALSE; 130 path = gtk_tree_model_get_path (model, &iter);
145 } 131 ref = gtk_tree_row_reference_new (model, path);
146 *p_treepath = treepath; 132 gtk_tree_path_free (path);
147 if (p_model) 133 return ref;
148 *p_model = model;
149 if (p_widget)
150 *p_widget = widget;
151 return TRUE;
152} 134}
153 135
154 136
155/** 137/**
138 * Changes were made to the selected entry in the tree view and the
139 * user clicked to confirm. Hide the drop down and display the
140 * selected entry as the new namespace label.
156 * 141 *
157 * @param user_data the builder for the main window 142 * @param builder the builder for the main window
143 * @param tv the tree view that was updated
158 */ 144 */
159static void 145static void
160namespace_selector_treeview_cursor_changed_cb (GtkWidget * widget, 146commit_changes (GtkBuilder *builder,
161 gpointer user_data) 147 GtkTreeView *tv)
162{ 148{
163 GtkBuilder *builder = GTK_BUILDER (user_data);
164 GtkToggleButton *toggle_button; 149 GtkToggleButton *toggle_button;
165 GtkLabel *sel_namespace_label; 150 GtkTreeRowReference *ref;
166 GtkTreeModel *model;
167 gchar *value;
168 GtkTreePath *treepath; 151 GtkTreePath *treepath;
169 GtkEntry *search_entry; 152 gchar *value;
170 GtkTreeRowReference *ref, *old; 153
171
172 toggle_button = 154 toggle_button =
173 GTK_TOGGLE_BUTTON (gtk_builder_get_object 155 GTK_TOGGLE_BUTTON (gtk_builder_get_object
174 (builder, 156 (builder,
175 "main_window_search_namespace_dropdown_button")); 157 "main_window_search_namespace_dropdown_button"));
176 if (!toggle_button) 158 ref = g_object_get_data (G_OBJECT (toggle_button), "selected-row-reference");
177 return; 159 if (NULL != ref)
178 160 gtk_tree_row_reference_free (ref);
179 search_entry = 161 ref = get_selected_row_from_treeview (tv);
180 GTK_ENTRY (gtk_builder_get_object (builder, "main_window_search_entry"));
181 if (!search_entry)
182 return;
183
184 if (!get_selected_namespace_treepath_iter_model_widget
185 (builder, &treepath, NULL, &model, NULL))
186 return;
187 ref = gtk_tree_row_reference_new (model, treepath);
188 old = g_object_get_data (G_OBJECT (toggle_button), "selected-row-reference");
189 if (old)
190 gtk_tree_row_reference_free (old);
191 g_object_set_data (G_OBJECT (toggle_button), "selected-row-reference", ref); 162 g_object_set_data (G_OBJECT (toggle_button), "selected-row-reference", ref);
192 163
164 treepath = gtk_tree_row_reference_get_path (ref);
165 if (GNUNET_GTK_get_tree_string (tv, treepath, 0, &value))
166 {
167 GtkLabel *sel_namespace_label;
193 168
194 sel_namespace_label = 169 sel_namespace_label =
195 GTK_LABEL (gtk_builder_get_object 170 GTK_LABEL (gtk_builder_get_object
196 (builder, "main_window_search_selected_namespace_label")); 171 (builder, "main_window_search_selected_namespace_label"));
197 if (!sel_namespace_label) 172 gtk_label_set_text (sel_namespace_label, (NULL != value) ? value : "");
198 return;
199
200 if (GNUNET_GTK_get_tree_string (GTK_TREE_VIEW (widget), treepath, 0, &value)
201 && value != NULL)
202 {
203 gtk_label_set_text (sel_namespace_label, value);
204 g_free (value); 173 g_free (value);
205 } 174 }
206 if (GNUNET_GTK_get_tree_string (GTK_TREE_VIEW (widget), treepath, 2, &value) 175 if (GNUNET_GTK_get_tree_string (tv, treepath, 2, &value))
207 && value != NULL)
208 { 176 {
209 gtk_entry_set_text (search_entry, value); 177 GtkEntry *search_entry;
178
179 search_entry = GTK_ENTRY (gtk_builder_get_object (builder, "main_window_search_entry"));
180 gtk_entry_set_text (search_entry, (NULL != value) ? value : "");
210 g_free (value); 181 g_free (value);
211 } 182 }
212
213 gtk_tree_path_free (treepath); 183 gtk_tree_path_free (treepath);
214 184
215 /* This will eventually hide the namespace selector */ 185 /* hide the namespace selector */
216 gtk_toggle_button_set_active (toggle_button, FALSE); 186 gtk_toggle_button_set_active (toggle_button, FALSE);
217}
218
219
220/**
221 *
222 */
223static GtkTreeRowReference *
224get_ns_selected_row (GtkTreeView * tree)
225{
226 GtkTreeSelection *sel;
227 GList *rows, *row;
228 GtkTreeModel *model;
229 GtkTreeRowReference *ref = NULL;
230
231 sel = gtk_tree_view_get_selection (tree);
232 rows = gtk_tree_selection_get_selected_rows (sel, &model);
233 for (row = rows; row; row = row->next)
234 {
235 ref = gtk_tree_row_reference_new (model, row->data);
236 if (ref != NULL)
237 break;
238 }
239 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
240 g_list_free (rows);
241 return ref;
242} 187}
243 188
244 189
245/** 190/**
191 * User pushed the button in the treeview. Get the selected entry
192 * and remember it in the "pushed-rowreference" of the widget.
193 * This way, we can use it when the button is released.
246 * 194 *
195 * @param widget the tree view widget
196 * @param event the push event
247 * @param user_data the builder for the main window 197 * @param user_data the builder for the main window
198 * @return FALSE
248 */ 199 */
249gboolean 200gboolean
250GNUNET_FS_GTK_namespace_selector_treeview_button_press_event_cb (GtkWidget * widget, 201GNUNET_FS_GTK_namespace_selector_treeview_button_press_event_cb (GtkWidget * widget,
251 GdkEvent * event, 202 GdkEvent * event,
252 gpointer user_data) 203 gpointer user_data)
253{ 204{
254 GtkTreeRowReference *ref = NULL; 205 GtkTreeRowReference *ref;
255 206 gpointer old = g_object_get_data (G_OBJECT (widget), "pushed-rowreference");
256 ref = get_ns_selected_row (GTK_TREE_VIEW (widget));
257 if (ref != NULL)
258 {
259 gpointer old = g_object_get_data (G_OBJECT (widget), "pushed-rowreference");
260 207
261 if (old) 208 if (NULL != old)
262 gtk_tree_row_reference_free (old); 209 gtk_tree_row_reference_free (old);
263 g_object_set_data (G_OBJECT (widget), "pushed-rowreference", ref); 210 ref = get_selected_row_from_treeview (GTK_TREE_VIEW (widget));
264 } 211 g_object_set_data (G_OBJECT (widget), "pushed-rowreference", ref);
265 return FALSE; 212 return FALSE;
266} 213}
267 214
268 215
269/** 216/**
217 * User released the button in the treeview. Get the selected entry
218 * and update the cursor accordingly, but only if the user pushed the
219 * button down and released it in the same row. We have stored the
220 * row that the user selected when pushing the button down in the
221 * "pushed-rowreference" of the widget.
270 * 222 *
223 * @param widget the tree view widget
224 * @param event the release event
271 * @param user_data the builder for the main window 225 * @param user_data the builder for the main window
226 * @return FALSE
272 */ 227 */
273gboolean 228gboolean
274GNUNET_FS_GTK_namespace_selector_treeview_button_release_event_cb (GtkWidget * widget, 229GNUNET_FS_GTK_namespace_selector_treeview_button_release_event_cb (GtkWidget * widget,
275 GdkEvent * event, 230 GdkEvent * event,
276 gpointer user_data) 231 gpointer user_data)
277{ 232{
278 GtkTreeRowReference *ref = NULL; 233 GtkBuilder *builder = GTK_BUILDER (user_data);
234 GtkTreeRowReference *ref;
279 gpointer old = g_object_get_data (G_OBJECT (widget), "pushed-rowreference"); 235 gpointer old = g_object_get_data (G_OBJECT (widget), "pushed-rowreference");
280 236
281 ref = get_ns_selected_row (GTK_TREE_VIEW (widget)); 237 ref = get_selected_row_from_treeview (GTK_TREE_VIEW (widget));
282 if (ref && old) 238 if ( (NULL != ref) && (NULL != old))
283 { 239 {
284 GtkTreePath *path_ref, *path_old; 240 GtkTreePath *path_ref;
241 GtkTreePath *path_old;
285 242
286 path_ref = gtk_tree_row_reference_get_path (ref); 243 path_ref = gtk_tree_row_reference_get_path (ref);
287 path_old = gtk_tree_row_reference_get_path (old); 244 path_old = gtk_tree_row_reference_get_path (old);
288 if (gtk_tree_path_compare (path_ref, path_old) == 0) 245 if (0 == gtk_tree_path_compare (path_ref, path_old))
289 namespace_selector_treeview_cursor_changed_cb (widget, user_data); 246 commit_changes (builder, GTK_TREE_VIEW (widget));
290 if (path_ref) 247 if (path_ref)
291 gtk_tree_path_free (path_ref); 248 gtk_tree_path_free (path_ref);
292 if (path_old) 249 if (path_old)
293 gtk_tree_path_free (path_old); 250 gtk_tree_path_free (path_old);
294 } 251 }
295 if (ref) 252 if (NULL != ref)
296 gtk_tree_row_reference_free (ref); 253 gtk_tree_row_reference_free (ref);
297 if (old) 254 if (NULL != old)
298 gtk_tree_row_reference_free (old); 255 gtk_tree_row_reference_free (old);
299 g_object_set_data (G_OBJECT (widget), "pushed-rowreference", NULL); 256 g_object_set_data (G_OBJECT (widget), "pushed-rowreference", NULL);
300 return FALSE; 257 return FALSE;
@@ -302,6 +259,59 @@ GNUNET_FS_GTK_namespace_selector_treeview_button_release_event_cb (GtkWidget * w
302 259
303 260
304/** 261/**
262 * The toggle button that changes the visibility of the namespace dropdown
263 * list was toggled.
264 *
265 * @param togglebutton the button that toggles the namespace dropdown list
266 * @param user_data the builder for the main window
267 */
268void
269GNUNET_FS_GTK_search_namespace_dropdown_button_toggled_cb (GtkToggleButton *
270 togglebutton,
271 gpointer user_data)
272{
273 GtkBuilder *builder = GTK_BUILDER (user_data);
274 gboolean active;
275 GtkWidget *namespace_selector_window;
276 GtkWidget *namespace_selector_treeview;
277 GtkAllocation togglebutton_allocation;
278 GdkWindow *main_window_gdk;
279 gint mwg_x;
280 gint mwg_y;
281 gint tgb_x;
282 gint tgb_y;
283 gint popup_x;
284 gint popup_y;
285
286 namespace_selector_window =
287 GTK_WIDGET (gtk_builder_get_object
288 (builder, "namespace_selector_window"));
289 g_object_get (G_OBJECT (togglebutton), "active", &active, NULL);
290 if (! active)
291 {
292 gtk_widget_hide (namespace_selector_window);
293 gtk_widget_grab_focus (GTK_WIDGET (togglebutton));
294 return;
295 }
296 namespace_selector_treeview =
297 GTK_WIDGET (gtk_builder_get_object
298 (builder, "namespace_selector_treeview"));
299 gtk_widget_get_allocation (GTK_WIDGET (togglebutton),
300 &togglebutton_allocation);
301 main_window_gdk = gtk_widget_get_window (GTK_WIDGET (togglebutton));
302 gdk_window_get_origin (main_window_gdk, &mwg_x, &mwg_y);
303 /* show the window below the button */
304 tgb_x = mwg_x + togglebutton_allocation.x;
305 tgb_y = mwg_y + togglebutton_allocation.y;
306 popup_x = tgb_x;
307 popup_y = tgb_y + togglebutton_allocation.height;
308 gtk_window_move (GTK_WINDOW (namespace_selector_window), popup_x, popup_y);
309 gtk_widget_show_all (namespace_selector_window);
310 gtk_widget_grab_focus (namespace_selector_treeview);
311}
312
313
314/**
305 * Add pseudonym data to tree store 315 * Add pseudonym data to tree store
306 * 316 *
307 * @param cls closure (the 'GtkListStore') 317 * @param cls closure (the 'GtkListStore')
@@ -379,67 +389,6 @@ add_namespace_to_ts (void *cls, const GNUNET_HashCode * pseudonym,
379} 389}
380 390
381 391
382
383
384/**
385 * The toggle button that changes the visibility of the namespace dropdown
386 * list was toggled.
387 *
388 * @param togglebutton the button that toggles the namespace dropdown list
389 * @param user_data the builder for the main window
390 */
391void
392GNUNET_FS_GTK_search_namespace_dropdown_button_toggled_cb (GtkToggleButton *
393 togglebutton,
394 gpointer user_data)
395{
396 GtkBuilder *builder = GTK_BUILDER (user_data);
397 gboolean active;
398 GtkWidget *namespace_selector_window;
399 GtkWidget *namespace_selector_treeview;
400 GtkAllocation togglebutton_allocation;
401 GdkWindow *main_window_gdk;
402 gint mwg_x;
403 gint mwg_y;
404 gint tgb_x;
405 gint tgb_y;
406 gint popup_x;
407 gint popup_y;
408
409 namespace_selector_window =
410 GTK_WIDGET (gtk_builder_get_object
411 (builder, "namespace_selector_window"));
412 g_object_get (G_OBJECT (togglebutton), "active", &active, NULL);
413 if (! active)
414 {
415 gtk_widget_hide (namespace_selector_window);
416 gtk_widget_grab_focus (GTK_WIDGET (togglebutton));
417 return;
418 }
419 namespace_selector_treeview =
420 GTK_WIDGET (gtk_builder_get_object
421 (builder, "namespace_selector_treeview"));
422 gtk_widget_get_allocation (GTK_WIDGET (togglebutton),
423 &togglebutton_allocation);
424 main_window_gdk = gtk_widget_get_window (GTK_WIDGET (togglebutton));
425 gdk_window_get_origin (main_window_gdk, &mwg_x, &mwg_y);
426
427 /* FIXME: this might become a problem in other window managers,
428 * where reference point is not in the top-left corner.
429 * We want to show the window below the button.
430 */
431 tgb_x = mwg_x + togglebutton_allocation.x;
432 tgb_y = mwg_y + togglebutton_allocation.y;
433 popup_x = tgb_x;
434 popup_y = tgb_y + togglebutton_allocation.height;
435
436 gtk_window_move (GTK_WINDOW (namespace_selector_window), popup_x, popup_y);
437
438 gtk_widget_show_all (namespace_selector_window);
439 gtk_widget_grab_focus (namespace_selector_treeview);
440}
441
442
443/** 392/**
444 * Startup hook to initialize the namespace dropdown widget. 393 * Startup hook to initialize the namespace dropdown widget.
445 * 394 *