1 /*
2 * Copyright (C) 2011 Nick Schermer <nick@xfce.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #ifdef HAVE_STRING_H
24 #include <string.h>
25 #endif
26 #ifdef HAVE_ERRNO_H
27 #include <errno.h>
28 #endif
29
30 #include <libxfce4util/libxfce4util.h>
31 #include <libxfce4ui/libxfce4ui.h>
32 #include <gdk/gdkkeysyms.h>
33 #include <xfconf/xfconf.h>
34 #include <glib/gstdio.h>
35
36 #include <src/appfinder-window.h>
37 #include <src/appfinder-model.h>
38 #include <src/appfinder-category-model.h>
39 #include <src/appfinder-preferences.h>
40 #include <src/appfinder-actions.h>
41 #include <src/appfinder-private.h>
42
43 #ifdef GDK_WINDOWING_X11
44 #include <gdk/gdkx.h>
45 #define APPFINDER_WIDGET_XID(widget) ((guint) GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (widget))))
46 #else
47 #define APPFINDER_WIDGET_XID(widget) (0)
48 #endif
49
50
51
52 #define DEFAULT_WINDOW_WIDTH 400
53 #define DEFAULT_WINDOW_HEIGHT 400
54 #define DEFAULT_PANED_POSITION 180
55
56 #define XFCE_APPFINDER_LOCAL_PREFIX "file://"
57
58
59 static void xfce_appfinder_window_finalize (GObject *object);
60 static void xfce_appfinder_window_unmap (GtkWidget *widget);
61 static gboolean xfce_appfinder_window_key_press_event (GtkWidget *widget,
62 GdkEventKey *event);
63 static gboolean xfce_appfinder_window_window_state_event (GtkWidget *widget,
64 GdkEventWindowState *event);
65 static void xfce_appfinder_window_view (XfceAppfinderWindow *window);
66 static gboolean xfce_appfinder_window_popup_menu (GtkWidget *view,
67 XfceAppfinderWindow *window);
68 static void xfce_appfinder_window_set_padding (GtkWidget *entry,
69 GtkWidget *align);
70 static gboolean xfce_appfinder_window_completion_match_func (GtkEntryCompletion *completion,
71 const gchar *key,
72 GtkTreeIter *iter,
73 gpointer data);
74 static void xfce_appfinder_window_entry_changed (XfceAppfinderWindow *window);
75 static void xfce_appfinder_window_entry_activate (GtkEditable *entry,
76 XfceAppfinderWindow *window);
77 static gboolean xfce_appfinder_window_entry_key_press_event (GtkWidget *entry,
78 GdkEventKey *event,
79 XfceAppfinderWindow *window);
80 static void xfce_appfinder_window_entry_icon_released (GtkEntry *entry,
81 GtkEntryIconPosition icon_pos,
82 GdkEvent *event,
83 XfceAppfinderWindow *window);
84 static void xfce_appfinder_window_drag_begin (GtkWidget *widget,
85 GdkDragContext *drag_context,
86 XfceAppfinderWindow *window);
87 static void xfce_appfinder_window_drag_data_get (GtkWidget *widget,
88 GdkDragContext *drag_context,
89 GtkSelectionData *data,
90 guint info,
91 guint drag_time,
92 XfceAppfinderWindow *window);
93 static gboolean xfce_appfinder_window_treeview_key_press_event (GtkWidget *widget,
94 GdkEventKey *event,
95 XfceAppfinderWindow *window);
96 static void xfce_appfinder_window_category_changed (GtkTreeSelection *selection,
97 XfceAppfinderWindow *window);
98 static void xfce_appfinder_window_category_set_categories (XfceAppfinderModel *model,
99 XfceAppfinderWindow *window);
100 static void xfce_appfinder_window_preferences (GtkWidget *button,
101 XfceAppfinderWindow *window);
102 static void xfce_appfinder_window_property_changed (XfconfChannel *channel,
103 const gchar *prop,
104 const GValue *value,
105 XfceAppfinderWindow *window);
106 static gboolean xfce_appfinder_window_item_visible (GtkTreeModel *model,
107 GtkTreeIter *iter,
108 gpointer data);
109 static void xfce_appfinder_window_item_changed (XfceAppfinderWindow *window);
110 static void xfce_appfinder_window_row_activated (XfceAppfinderWindow *window);
111 static void xfce_appfinder_window_icon_theme_changed (XfceAppfinderWindow *window);
112 static void xfce_appfinder_window_launch_clicked (XfceAppfinderWindow *window);
113 static void xfce_appfinder_window_execute (XfceAppfinderWindow *window,
114 gboolean close_on_succeed);
115 static gint xfce_appfinder_window_sort_items (GtkTreeModel *model,
116 GtkTreeIter *a,
117 GtkTreeIter *b,
118 gpointer data);
119 static gboolean xfce_appfinder_should_sort_icon_view (void);
120 static void xfce_appfinder_window_update_frecency (XfceAppfinderWindow *window,
121 GtkTreeModel *model,
122 const gchar *uri);
123 static gint xfce_appfinder_window_sort_items_frecency (GtkTreeModel *model,
124 GtkTreeIter *a,
125 GtkTreeIter *b,
126 gpointer data);
127
128 struct _XfceAppfinderWindowClass
129 {
130 GtkWindowClass __parent__;
131 };
132
133 struct _XfceAppfinderWindow
134 {
135 GtkWindow __parent__;
136
137 XfceAppfinderModel *model;
138
139 GtkTreeModel *sort_model;
140 GtkTreeModel *filter_model;
141
142 XfceAppfinderCategoryModel *category_model;
143
144 XfceAppfinderActions *actions;
145
146 GtkIconTheme *icon_theme;
147
148 GtkEntryCompletion *completion;
149
150 XfconfChannel *channel;
151
152 GtkWidget *paned;
153 GtkWidget *entry;
154 GtkWidget *image;
155 GtkWidget *view;
156 GtkWidget *viewscroll;
157 GtkWidget *sidepane;
158
159 GdkPixbuf *icon_find;
160
161 GtkWidget *button_launch;
162
163 GarconMenuDirectory *filter_category;
164 gchar *filter_text;
165
166 guint idle_entry_changed_id;
167
168 gint last_window_height;
169
170 gulong property_watch_id;
171 gulong categories_changed_id;
172 };
173
174 static const GtkTargetEntry target_list[] =
175 {
176 { "text/uri-list", 0, 0 }
177 };
178
179
180
G_DEFINE_TYPE(XfceAppfinderWindow,xfce_appfinder_window,GTK_TYPE_WINDOW)181 G_DEFINE_TYPE (XfceAppfinderWindow, xfce_appfinder_window, GTK_TYPE_WINDOW)
182
183
184
185 static void
186 xfce_appfinder_window_class_init (XfceAppfinderWindowClass *klass)
187 {
188 GObjectClass *gobject_class;
189 GtkWidgetClass *gtkwidget_class;
190
191 gobject_class = G_OBJECT_CLASS (klass);
192 gobject_class->finalize = xfce_appfinder_window_finalize;
193
194 gtkwidget_class = GTK_WIDGET_CLASS (klass);
195 gtkwidget_class->unmap = xfce_appfinder_window_unmap;
196 gtkwidget_class->key_press_event = xfce_appfinder_window_key_press_event;
197 gtkwidget_class->window_state_event = xfce_appfinder_window_window_state_event;
198 }
199
200
201
202 static void
xfce_appfinder_window_init(XfceAppfinderWindow * window)203 xfce_appfinder_window_init (XfceAppfinderWindow *window)
204 {
205 GtkWidget *vbox;
206 GtkWidget *entry;
207 GtkWidget *pane;
208 GtkWidget *scroll;
209 GtkWidget *sidepane;
210 GtkWidget *image;
211 GtkWidget *hbox;
212 GtkTreeViewColumn *column;
213 GtkCellRenderer *renderer;
214 GtkTreeSelection *selection;
215 GtkWidget *button;
216 GtkEntryCompletion *completion;
217 GtkCellRenderer *cell;
218 gint integer;
219
220 window->channel = xfconf_channel_get ("xfce4-appfinder");
221 window->last_window_height = xfconf_channel_get_int (window->channel, "/last/window-height", DEFAULT_WINDOW_HEIGHT);
222
223 window->category_model = xfce_appfinder_category_model_new ();
224 xfconf_g_property_bind (window->channel, "/category-icon-size", G_TYPE_UINT,
225 G_OBJECT (window->category_model), "icon-size");
226
227 window->model = xfce_appfinder_model_get (xfconf_channel_get_bool (window->channel, "/sort-by-frecency", FALSE));
228 xfconf_g_property_bind (window->channel, "/item-icon-size", G_TYPE_UINT,
229 G_OBJECT (window->model), "icon-size");
230
231 gtk_window_set_title (GTK_WINDOW (window), _("Application Finder"));
232 integer = xfconf_channel_get_int (window->channel, "/last/window-width", DEFAULT_WINDOW_WIDTH);
233 gtk_window_set_default_size (GTK_WINDOW (window), integer, -1);
234 gtk_window_set_icon_name (GTK_WINDOW (window), "org.xfce.appfinder");
235
236 if (xfconf_channel_get_bool (window->channel, "/always-center", FALSE))
237 {
238 gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
239 }
240
241 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
242 gtk_container_add (GTK_CONTAINER (window), vbox);
243 gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
244 gtk_widget_show (vbox);
245
246 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
247 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
248 gtk_widget_show (hbox);
249
250 window->icon_find = xfce_appfinder_model_load_pixbuf (XFCE_APPFINDER_STOCK_FIND, XFCE_APPFINDER_ICON_SIZE_48);
251 window->image = image = gtk_image_new_from_pixbuf (window->icon_find);
252 gtk_widget_set_size_request (image, 48, 48);
253 gtk_widget_set_halign(image, GTK_ALIGN_CENTER);
254 gtk_container_add (GTK_CONTAINER (hbox), image);
255 gtk_widget_show (image);
256
257 window->entry = entry = gtk_entry_new ();
258 gtk_widget_set_halign(entry, GTK_ALIGN_FILL);
259 gtk_widget_set_valign (entry, GTK_ALIGN_CENTER);
260 gtk_widget_set_hexpand (entry, TRUE);
261 gtk_container_add (GTK_CONTAINER (hbox), entry);
262 g_signal_connect (G_OBJECT (entry), "icon-release",
263 G_CALLBACK (xfce_appfinder_window_entry_icon_released), window);
264 g_signal_connect (G_OBJECT (entry), "realize",
265 G_CALLBACK (xfce_appfinder_window_set_padding), entry);
266 g_signal_connect_swapped (G_OBJECT (entry), "changed",
267 G_CALLBACK (xfce_appfinder_window_entry_changed), window);
268 g_signal_connect (G_OBJECT (entry), "activate",
269 G_CALLBACK (xfce_appfinder_window_entry_activate), window);
270 g_signal_connect (G_OBJECT (entry), "key-press-event",
271 G_CALLBACK (xfce_appfinder_window_entry_key_press_event), window);
272 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
273 GTK_ENTRY_ICON_SECONDARY,
274 XFCE_APPFINDER_STOCK_GO_DOWN);
275 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (entry),
276 GTK_ENTRY_ICON_SECONDARY,
277 _("Toggle view mode"));
278 gtk_widget_show (entry);
279
280 window->completion = completion = gtk_entry_completion_new ();
281 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (window->model));
282 gtk_entry_completion_set_match_func (completion, xfce_appfinder_window_completion_match_func, window, NULL);
283 g_object_set (G_OBJECT (completion), "text-column", XFCE_APPFINDER_MODEL_COLUMN_COMMAND, NULL);
284 gtk_entry_completion_set_popup_single_match (completion, TRUE);
285 gtk_entry_completion_set_inline_completion (completion, TRUE);
286
287 cell = gtk_cell_renderer_text_new ();
288 g_object_set (G_OBJECT (cell), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
289 gtk_cell_renderer_set_fixed_size (cell, 1, -1);
290 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), cell, TRUE);
291 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (completion), cell, "text", XFCE_APPFINDER_MODEL_COLUMN_COMMAND);
292
293 if (xfconf_channel_get_bool (window->channel, "/disable-completion", FALSE))
294 gtk_entry_completion_set_popup_completion (completion, FALSE);
295
296 window->paned = pane = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
297 gtk_box_pack_start (GTK_BOX (vbox), pane, TRUE, TRUE, 0);
298 integer = xfconf_channel_get_int (window->channel, "/last/pane-position", DEFAULT_PANED_POSITION);
299 gtk_paned_set_position (GTK_PANED (pane), integer);
300 g_object_set (G_OBJECT (pane), "position-set", TRUE, NULL);
301
302 scroll = gtk_scrolled_window_new (NULL, NULL);
303 gtk_paned_add1 (GTK_PANED (pane), scroll);
304 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_ETCHED_IN);
305 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
306 gtk_widget_show (scroll);
307
308 if (xfconf_channel_get_bool (window->channel, "/hide-category-pane", FALSE))
309 gtk_widget_set_visible (scroll, FALSE);
310
311 sidepane = window->sidepane = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window->category_model));
312 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (sidepane), FALSE);
313 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (sidepane), FALSE);
314 g_signal_connect_swapped (G_OBJECT (sidepane), "start-interactive-search",
315 G_CALLBACK (gtk_widget_grab_focus), entry);
316 g_signal_connect (G_OBJECT (sidepane), "key-press-event",
317 G_CALLBACK (xfce_appfinder_window_treeview_key_press_event), window);
318 gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (sidepane),
319 xfce_appfinder_category_model_row_separator_func, NULL, NULL);
320 gtk_container_add (GTK_CONTAINER (scroll), sidepane);
321 gtk_widget_show (sidepane);
322
323 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sidepane));
324 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
325 g_signal_connect (G_OBJECT (selection), "changed",
326 G_CALLBACK (xfce_appfinder_window_category_changed), window);
327
328 column = gtk_tree_view_column_new ();
329 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
330 gtk_tree_view_append_column (GTK_TREE_VIEW (sidepane), GTK_TREE_VIEW_COLUMN (column));
331
332 renderer = gtk_cell_renderer_pixbuf_new ();
333 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer, FALSE);
334 gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer,
335 "pixbuf", XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_ICON, NULL);
336
337 renderer = gtk_cell_renderer_text_new ();
338 g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
339 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer, TRUE);
340 gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer,
341 "text", XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_NAME, NULL);
342
343 window->viewscroll = scroll = gtk_scrolled_window_new (NULL, NULL);
344 gtk_paned_add2 (GTK_PANED (pane), scroll);
345 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_ETCHED_IN);
346 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
347 gtk_widget_show (scroll);
348
349 /* set the icon or tree view */
350 xfce_appfinder_window_view (window);
351
352 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
353 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
354 gtk_widget_show (hbox);
355
356 button = gtk_button_new_with_mnemonic (_("_Preferences"));
357 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
358 g_signal_connect (G_OBJECT (button), "clicked",
359 G_CALLBACK (xfce_appfinder_window_preferences), window);
360 gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
361 gtk_button_set_always_show_image(GTK_BUTTON(button), TRUE);
362 gtk_widget_show (button);
363
364 image = gtk_image_new_from_icon_name (XFCE_APPFINDER_STOCK_PREFERENCES, GTK_ICON_SIZE_BUTTON);
365 gtk_button_set_image (GTK_BUTTON (button), image);
366
367 window->button_launch = button = gtk_button_new_with_mnemonic (_("La_unch"));
368 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
369 g_signal_connect_swapped (G_OBJECT (button), "clicked",
370 G_CALLBACK (xfce_appfinder_window_launch_clicked), window);
371 gtk_widget_set_sensitive (button, FALSE);
372 gtk_button_set_always_show_image(GTK_BUTTON(button), TRUE);
373 gtk_widget_show (button);
374
375 image = gtk_image_new_from_icon_name (XFCE_APPFINDER_STOCK_EXECUTE, GTK_ICON_SIZE_BUTTON);
376 gtk_button_set_image (GTK_BUTTON (button), image);
377
378 window->icon_theme = gtk_icon_theme_get_for_screen (gtk_window_get_screen (GTK_WINDOW (window)));
379 g_signal_connect_swapped (G_OBJECT (window->icon_theme), "changed",
380 G_CALLBACK (xfce_appfinder_window_icon_theme_changed), window);
381 g_object_ref (G_OBJECT (window->icon_theme));
382
383 /* load categories in the model */
384 xfce_appfinder_window_category_set_categories (NULL, window);
385 window->categories_changed_id =
386 g_signal_connect (G_OBJECT (window->model), "categories-changed",
387 G_CALLBACK (xfce_appfinder_window_category_set_categories),
388 window);
389
390 /* monitor xfconf property changes */
391 window->property_watch_id =
392 g_signal_connect (G_OBJECT (window->channel), "property-changed",
393 G_CALLBACK (xfce_appfinder_window_property_changed), window);
394
395 APPFINDER_DEBUG ("constructed window");
396 }
397
398
399
400 static void
xfce_appfinder_window_finalize(GObject * object)401 xfce_appfinder_window_finalize (GObject *object)
402 {
403 XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (object);
404
405 if (window->idle_entry_changed_id != 0)
406 g_source_remove (window->idle_entry_changed_id);
407
408 g_signal_handler_disconnect (window->channel, window->property_watch_id);
409 g_signal_handler_disconnect (window->model, window->categories_changed_id);
410
411 /* release our reference on the icon theme */
412 g_signal_handlers_disconnect_by_func (G_OBJECT (window->icon_theme),
413 xfce_appfinder_window_icon_theme_changed, window);
414 g_object_unref (G_OBJECT (window->icon_theme));
415
416 g_object_unref (G_OBJECT (window->model));
417 g_object_unref (G_OBJECT (window->category_model));
418 g_object_unref (G_OBJECT (window->filter_model));
419 g_object_unref (G_OBJECT (window->sort_model));
420 g_object_unref (G_OBJECT (window->completion));
421 g_object_unref (G_OBJECT (window->icon_find));
422
423 if (window->actions != NULL)
424 g_object_unref (G_OBJECT (window->actions));
425
426 if (window->filter_category != NULL)
427 g_object_unref (G_OBJECT (window->filter_category));
428 g_free (window->filter_text);
429
430 (*G_OBJECT_CLASS (xfce_appfinder_window_parent_class)->finalize) (object);
431 }
432
433
434
435 static void
xfce_appfinder_window_unmap(GtkWidget * widget)436 xfce_appfinder_window_unmap (GtkWidget *widget)
437 {
438 XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (widget);
439 gint width, height;
440 gint position;
441
442 position = gtk_paned_get_position (GTK_PANED (window->paned));
443 gtk_window_get_size (GTK_WINDOW (window), &width, &height);
444 if (!gtk_widget_get_visible (window->paned))
445 height = window->last_window_height;
446
447 (*GTK_WIDGET_CLASS (xfce_appfinder_window_parent_class)->unmap) (widget);
448
449 xfconf_channel_set_int (window->channel, "/last/window-height", height);
450 xfconf_channel_set_int (window->channel, "/last/window-width", width);
451 xfconf_channel_set_int (window->channel, "/last/pane-position", position);
452
453 return (*GTK_WIDGET_CLASS (xfce_appfinder_window_parent_class)->unmap) (widget);
454 }
455
456
457
458 static gboolean
xfce_appfinder_window_key_press_event(GtkWidget * widget,GdkEventKey * event)459 xfce_appfinder_window_key_press_event (GtkWidget *widget,
460 GdkEventKey *event)
461 {
462 XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (widget);
463 GtkWidget *entry;
464 XfceAppfinderIconSize icon_size = XFCE_APPFINDER_ICON_SIZE_DEFAULT_ITEM;
465
466 if (event->keyval == GDK_KEY_Escape)
467 {
468 gtk_widget_destroy (widget);
469 return TRUE;
470 }
471
472 if ((event->state & GDK_CONTROL_MASK) != 0)
473 {
474 switch (event->keyval)
475 {
476 case GDK_KEY_l:
477 entry = XFCE_APPFINDER_WINDOW (widget)->entry;
478
479 gtk_widget_grab_focus (entry);
480 gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
481
482 return TRUE;
483
484 case GDK_KEY_1:
485 case GDK_KEY_2:
486 /* toggle between icon and tree view */
487 xfconf_channel_set_bool (window->channel, "/icon-view",
488 event->keyval == GDK_KEY_1);
489 return TRUE;
490
491 case GDK_KEY_plus:
492 case GDK_KEY_minus:
493 case GDK_KEY_KP_Add:
494 case GDK_KEY_KP_Subtract:
495 g_object_get (G_OBJECT (window->model), "icon-size", &icon_size, NULL);
496 if ((event->keyval == GDK_KEY_plus || event->keyval == GDK_KEY_KP_Add))
497 {
498 if (icon_size < XFCE_APPFINDER_ICON_SIZE_LARGEST)
499 icon_size++;
500 }
501 else if (icon_size > XFCE_APPFINDER_ICON_SIZE_SMALLEST)
502 {
503 icon_size--;
504 }
505 g_object_set (G_OBJECT (window->model), "icon-size", icon_size, NULL);
506 return TRUE;
507
508 case GDK_KEY_0:
509 case GDK_KEY_KP_0:
510 g_object_set (G_OBJECT (window->model), "icon-size", icon_size, NULL);
511 return TRUE;
512 }
513 }
514
515 return (*GTK_WIDGET_CLASS (xfce_appfinder_window_parent_class)->key_press_event) (widget, event);
516 }
517
518
519
520 static gboolean
xfce_appfinder_window_window_state_event(GtkWidget * widget,GdkEventWindowState * event)521 xfce_appfinder_window_window_state_event (GtkWidget *widget,
522 GdkEventWindowState *event)
523 {
524 XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (widget);
525 gint width;
526
527 if (!gtk_widget_get_visible (window->paned))
528 {
529 if ((event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0)
530 {
531 gtk_window_unmaximize (GTK_WINDOW (widget));
532
533 /* set sensible width instead of taking entire width */
534 width = xfconf_channel_get_int (window->channel, "/last/window-width", DEFAULT_WINDOW_WIDTH);
535 gtk_window_resize (GTK_WINDOW (widget), width, 100 /* should be corrected by wm */);
536 }
537
538 if ((event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0)
539 gtk_window_unfullscreen (GTK_WINDOW (widget));
540 }
541
542 if ((*GTK_WIDGET_CLASS (xfce_appfinder_window_parent_class)->window_state_event) != NULL)
543 return (*GTK_WIDGET_CLASS (xfce_appfinder_window_parent_class)->window_state_event) (widget, event);
544
545 return FALSE;
546 }
547
548
549
550 static void
xfce_appfinder_window_set_item_width(XfceAppfinderWindow * window)551 xfce_appfinder_window_set_item_width (XfceAppfinderWindow *window)
552 {
553 gint width = 0, padding = 0;
554 gint text_column_idx, column_idx = 0;
555 XfceAppfinderIconSize icon_size;
556 GtkOrientation item_orientation = GTK_ORIENTATION_VERTICAL;
557 GList *renderers;
558 GList *li;
559
560 appfinder_return_if_fail (GTK_IS_ICON_VIEW (window->view));
561
562 g_object_get (G_OBJECT (window->model), "icon-size", &icon_size, NULL);
563
564 /* some hard-coded values for the cell size that seem to work fine */
565 switch (icon_size)
566 {
567 case XFCE_APPFINDER_ICON_SIZE_SMALLEST:
568 padding = 2;
569 width = 16 * 3.75;
570 break;
571
572 case XFCE_APPFINDER_ICON_SIZE_SMALLER:
573 padding = 2;
574 width = 24 * 3;
575 break;
576
577 case XFCE_APPFINDER_ICON_SIZE_SMALL:
578 padding = 4;
579 width = 36 * 2.5;
580 break;
581
582 case XFCE_APPFINDER_ICON_SIZE_NORMAL:
583 padding = 4;
584 width = 48 * 2;
585 break;
586
587 case XFCE_APPFINDER_ICON_SIZE_LARGE:
588 padding = 6;
589 width = 64 * 1.5;
590 break;
591
592 case XFCE_APPFINDER_ICON_SIZE_LARGER:
593 padding = 6;
594 width = 96 * 1.75;
595 break;
596
597 case XFCE_APPFINDER_ICON_SIZE_LARGEST:
598 padding = 6;
599 width = 128 * 1.25;
600 break;
601 }
602
603 if (xfconf_channel_get_bool (window->channel, "/text-beside-icons", FALSE))
604 {
605 item_orientation = GTK_ORIENTATION_HORIZONTAL;
606 width *= 2;
607 }
608
609 gtk_icon_view_set_item_orientation (GTK_ICON_VIEW (window->view), item_orientation);
610 gtk_icon_view_set_item_padding (GTK_ICON_VIEW (window->view), padding);
611 gtk_icon_view_set_item_width (GTK_ICON_VIEW (window->view), width);
612
613 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (window->view));
614 text_column_idx = gtk_icon_view_get_text_column (GTK_ICON_VIEW (window->view));
615
616 for (li = renderers; li != NULL; li = li->next, column_idx++) {
617 /* work around the yalign = 0.0 gtk uses */
618 if (item_orientation == GTK_ORIENTATION_HORIZONTAL) {
619 g_object_set (li->data, "yalign", 0.5, NULL);
620 }
621
622 /* do not wrap when text beside icons is enabled */
623 if (column_idx == text_column_idx) {
624 g_object_set (li->data, "ellipsize",
625 item_orientation == GTK_ORIENTATION_HORIZONTAL ?
626 PANGO_ELLIPSIZE_END : PANGO_ELLIPSIZE_NONE, NULL);
627 }
628 }
629 g_list_free (renderers);
630 }
631
632
633
634 static gboolean
xfce_appfinder_window_view_button_press_event(GtkWidget * widget,GdkEventButton * event,XfceAppfinderWindow * window)635 xfce_appfinder_window_view_button_press_event (GtkWidget *widget,
636 GdkEventButton *event,
637 XfceAppfinderWindow *window)
638 {
639 gint x, y;
640 GtkTreePath *path;
641 gboolean have_selection = FALSE;
642
643 if (event->button == 3
644 && event->type == GDK_BUTTON_PRESS)
645 {
646 if (GTK_IS_TREE_VIEW (widget))
647 {
648 gtk_tree_view_convert_widget_to_bin_window_coords (GTK_TREE_VIEW (widget),
649 event->x, event->y, &x, &y);
650
651 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), x, y, &path, NULL, NULL, NULL))
652 {
653 gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, NULL, FALSE);
654 gtk_tree_path_free (path);
655 have_selection = TRUE;
656 }
657 }
658 else
659 {
660 path = gtk_icon_view_get_path_at_pos (GTK_ICON_VIEW (widget), event->x, event->y);
661 if (path != NULL)
662 {
663 gtk_icon_view_select_path (GTK_ICON_VIEW (widget), path);
664 gtk_icon_view_set_cursor (GTK_ICON_VIEW (widget), path, NULL, FALSE);
665 gtk_tree_path_free (path);
666 have_selection = TRUE;
667 }
668 }
669
670 if (have_selection)
671 return xfce_appfinder_window_popup_menu (widget, window);
672 }
673
674 return FALSE;
675 }
676
677
678
679 static void
xfce_appfinder_window_view(XfceAppfinderWindow * window)680 xfce_appfinder_window_view (XfceAppfinderWindow *window)
681 {
682 GtkTreeViewColumn *column;
683 GtkCellRenderer *renderer;
684 GtkTreeSelection *selection;
685 GtkWidget *view;
686 gboolean icon_view;
687
688 icon_view = xfconf_channel_get_bool (window->channel, "/icon-view", FALSE);
689 if (window->view != NULL)
690 {
691 if (icon_view && GTK_IS_ICON_VIEW (window->view))
692 return;
693 gtk_widget_destroy (window->view);
694 }
695
696 window->filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (window->model), NULL);
697 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (window->filter_model), xfce_appfinder_window_item_visible, window, NULL);
698
699 window->sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (window->filter_model));
700 if (xfconf_channel_get_bool (window->channel, "/sort-by-frecency", FALSE))
701 gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (window->sort_model), xfce_appfinder_window_sort_items_frecency, window->entry, NULL);
702 else
703 gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (window->sort_model), xfce_appfinder_window_sort_items, window->entry, NULL);
704
705 if (icon_view)
706 {
707 window->view = view = gtk_icon_view_new_with_model (
708 xfce_appfinder_should_sort_icon_view () ?
709 window->sort_model :
710 window->filter_model);
711
712 gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (view), GTK_SELECTION_SINGLE);
713 gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (view), XFCE_APPFINDER_MODEL_COLUMN_ICON);
714 gtk_icon_view_set_text_column (GTK_ICON_VIEW (view), XFCE_APPFINDER_MODEL_COLUMN_TITLE);
715 gtk_icon_view_set_tooltip_column (GTK_ICON_VIEW (view), XFCE_APPFINDER_MODEL_COLUMN_TOOLTIP);
716 gtk_icon_view_set_row_spacing (GTK_ICON_VIEW (view), 0);
717 xfce_appfinder_window_set_item_width (window);
718
719 g_signal_connect_swapped (G_OBJECT (view), "selection-changed",
720 G_CALLBACK (xfce_appfinder_window_item_changed), window);
721 g_signal_connect_swapped (G_OBJECT (view), "item-activated",
722 G_CALLBACK (xfce_appfinder_window_row_activated), window);
723 }
724 else
725 {
726 window->view = view = gtk_tree_view_new_with_model (window->sort_model);
727 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
728 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (view), FALSE);
729 gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (view), XFCE_APPFINDER_MODEL_COLUMN_TOOLTIP);
730 g_signal_connect_swapped (G_OBJECT (view), "row-activated",
731 G_CALLBACK (xfce_appfinder_window_row_activated), window);
732 g_signal_connect_swapped (G_OBJECT (view), "start-interactive-search",
733 G_CALLBACK (gtk_widget_grab_focus), window->entry);
734 g_signal_connect (G_OBJECT (view), "key-press-event",
735 G_CALLBACK (xfce_appfinder_window_treeview_key_press_event), window);
736
737 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
738 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
739 g_signal_connect_swapped (G_OBJECT (selection), "changed",
740 G_CALLBACK (xfce_appfinder_window_item_changed), window);
741
742 column = gtk_tree_view_column_new ();
743 gtk_tree_view_column_set_spacing (column, 2);
744 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
745 gtk_tree_view_append_column (GTK_TREE_VIEW (view), GTK_TREE_VIEW_COLUMN (column));
746
747 renderer = gtk_cell_renderer_pixbuf_new ();
748 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer, FALSE);
749 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer,
750 "pixbuf", XFCE_APPFINDER_MODEL_COLUMN_ICON, NULL);
751
752 renderer = gtk_cell_renderer_text_new ();
753 g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
754 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer, TRUE);
755 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column), renderer,
756 "markup", XFCE_APPFINDER_MODEL_COLUMN_ABSTRACT, NULL);
757 }
758
759 gtk_drag_source_set (view, GDK_BUTTON1_MASK, target_list,
760 G_N_ELEMENTS (target_list), GDK_ACTION_COPY);
761 g_signal_connect (G_OBJECT (view), "drag-begin",
762 G_CALLBACK (xfce_appfinder_window_drag_begin), window);
763 g_signal_connect (G_OBJECT (view), "drag-data-get",
764 G_CALLBACK (xfce_appfinder_window_drag_data_get), window);
765 g_signal_connect (G_OBJECT (view), "popup-menu",
766 G_CALLBACK (xfce_appfinder_window_popup_menu), window);
767 g_signal_connect (G_OBJECT (view), "button-press-event",
768 G_CALLBACK (xfce_appfinder_window_view_button_press_event), window);
769 gtk_container_add (GTK_CONTAINER (window->viewscroll), view);
770 gtk_widget_show (view);
771 }
772
773
774
775 static gboolean
xfce_appfinder_window_view_get_selected(XfceAppfinderWindow * window,GtkTreeModel ** model,GtkTreeIter * iter)776 xfce_appfinder_window_view_get_selected (XfceAppfinderWindow *window,
777 GtkTreeModel **model,
778 GtkTreeIter *iter)
779 {
780 GtkTreeSelection *selection;
781 gboolean have_iter;
782 GList *items;
783
784 appfinder_return_val_if_fail (XFCE_IS_APPFINDER_WINDOW (window), FALSE);
785 appfinder_return_val_if_fail (model != NULL, FALSE);
786 appfinder_return_val_if_fail (iter != NULL, FALSE);
787
788 if (GTK_IS_TREE_VIEW (window->view))
789 {
790 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->view));
791 have_iter = gtk_tree_selection_get_selected (selection, model, iter);
792 }
793 else
794 {
795 items = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (window->view));
796 appfinder_assert (g_list_length (items) <= 1);
797 if (items != NULL)
798 {
799 *model = gtk_icon_view_get_model (GTK_ICON_VIEW (window->view));
800 have_iter = gtk_tree_model_get_iter (*model, iter, items->data);
801
802 gtk_tree_path_free (items->data);
803 g_list_free (items);
804 }
805 else
806 {
807 have_iter = FALSE;
808 }
809 }
810
811 return have_iter;
812 }
813
814
815
816 static gboolean
xfce_appfinder_window_view_get_selected_path(XfceAppfinderWindow * window,GtkTreePath ** path)817 xfce_appfinder_window_view_get_selected_path (XfceAppfinderWindow *window,
818 GtkTreePath **path)
819 {
820 GtkTreeModel *model;
821 GtkTreeIter iter;
822
823 if (!xfce_appfinder_window_view_get_selected (window, &model, &iter))
824 return FALSE;
825
826 *path = gtk_tree_model_get_path (model, &iter);
827
828 return (*path != NULL);
829 }
830
831
832
833 static void
xfce_appfinder_window_popup_menu_toggle_bookmark(GtkWidget * mi,XfceAppfinderWindow * window)834 xfce_appfinder_window_popup_menu_toggle_bookmark (GtkWidget *mi,
835 XfceAppfinderWindow *window)
836 {
837 const gchar *uri;
838 GFile *gfile;
839 gchar *desktop_id;
840 GtkWidget *menu = gtk_widget_get_parent (mi);
841 GtkTreeModel *model;
842 GError *error = NULL;
843
844 uri = g_object_get_data (G_OBJECT (menu), "uri");
845 if (uri != NULL)
846 {
847 gfile = g_file_new_for_uri (uri);
848 desktop_id = g_file_get_basename (gfile);
849 g_object_unref (G_OBJECT (gfile));
850
851 /* toggle bookmarks */
852 model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (window->filter_model));
853 xfce_appfinder_model_bookmark_toggle (XFCE_APPFINDER_MODEL (model), desktop_id, &error);
854
855 g_free (desktop_id);
856
857 if (G_UNLIKELY (error != NULL))
858 {
859 g_printerr ("%s: failed to save bookmarks: %s\n", G_LOG_DOMAIN, error->message);
860 g_error_free (error);
861 }
862 }
863 }
864
865
866
867 static void
xfce_appfinder_window_popup_menu_execute(GtkWidget * mi,XfceAppfinderWindow * window)868 xfce_appfinder_window_popup_menu_execute (GtkWidget *mi,
869 XfceAppfinderWindow *window)
870 {
871 xfce_appfinder_window_execute (window, FALSE);
872 }
873
874
875
876 static void
xfce_appfinder_window_popup_menu_edit(GtkWidget * mi,XfceAppfinderWindow * window)877 xfce_appfinder_window_popup_menu_edit (GtkWidget *mi,
878 XfceAppfinderWindow *window)
879 {
880 GError *error = NULL;
881 gchar *cmd;
882 const gchar *uri;
883 GtkWidget *menu = gtk_widget_get_parent (mi);
884
885 appfinder_return_if_fail (GTK_IS_MENU (menu));
886 appfinder_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
887
888 uri = g_object_get_data (G_OBJECT (menu), "uri");
889 if (G_LIKELY (uri != NULL))
890 {
891 cmd = g_strdup_printf ("exo-desktop-item-edit --xid=0x%x '%s'",
892 APPFINDER_WIDGET_XID (window), uri);
893 if (!g_spawn_command_line_async (cmd, &error))
894 {
895 xfce_dialog_show_error (GTK_WINDOW (window), error,
896 _("Failed to launch desktop item editor"));
897 g_error_free (error);
898 }
899 g_free (cmd);
900 }
901 }
902
903
904
905 static void
xfce_appfinder_window_popup_menu_revert(GtkWidget * mi,XfceAppfinderWindow * window)906 xfce_appfinder_window_popup_menu_revert (GtkWidget *mi,
907 XfceAppfinderWindow *window)
908 {
909 const gchar *uri;
910 const gchar *name;
911 GError *error;
912 GtkWidget *menu = gtk_widget_get_parent (mi);
913
914 appfinder_return_if_fail (GTK_IS_MENU (menu));
915 appfinder_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
916
917 name = g_object_get_data (G_OBJECT (menu), "name");
918 if (name == NULL)
919 return;
920
921 if (xfce_dialog_confirm (GTK_WINDOW (window), XFCE_APPFINDER_STOCK_REVERT_TO_SAVED, NULL,
922 _("This will permanently remove the custom desktop file from your home directory."),
923 _("Are you sure you want to revert \"%s\"?"), name))
924 {
925 uri = g_object_get_data (G_OBJECT (menu), "uri");
926 if (uri != NULL)
927 {
928 if (g_unlink (uri + 7) == -1)
929 {
930 error = g_error_new (G_FILE_ERROR, g_file_error_from_errno (errno),
931 "%s: %s", uri + 7, g_strerror (errno));
932 xfce_dialog_show_error (GTK_WINDOW (window), error,
933 _("Failed to remove desktop file"));
934 g_error_free (error);
935 }
936 }
937 }
938 }
939
940
941
942 static void
xfce_appfinder_window_popup_menu_hide(GtkWidget * mi,XfceAppfinderWindow * window)943 xfce_appfinder_window_popup_menu_hide (GtkWidget *mi,
944 XfceAppfinderWindow *window)
945 {
946 const gchar *uri;
947 const gchar *name;
948 GtkWidget *menu = gtk_widget_get_parent (mi);
949 gchar *path;
950 gchar *message;
951 gchar **dirs;
952 guint i;
953 const gchar *relpath;
954 XfceRc *rc;
955
956 appfinder_return_if_fail (GTK_IS_MENU (menu));
957 appfinder_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
958
959 name = g_object_get_data (G_OBJECT (menu), "name");
960 if (name == NULL)
961 return;
962
963 path = xfce_resource_save_location (XFCE_RESOURCE_DATA, "applications/", FALSE);
964 /* I18N: the first %s will be replace with users' applications directory, the
965 * second with Hidden=true */
966 message = g_strdup_printf (_("To unhide the item you have to manually "
967 "remove the desktop file from \"%s\" or "
968 "open the file in the same directory and "
969 "remove the line \"%s\"."), path, "Hidden=true");
970
971 if (xfce_dialog_confirm (GTK_WINDOW (window), NULL, _("_Hide"), message,
972 _("Are you sure you want to hide \"%s\"?"), name))
973 {
974 uri = g_object_get_data (G_OBJECT (menu), "uri");
975 if (uri != NULL)
976 {
977 /* lookup the correct relative path */
978 dirs = xfce_resource_lookup_all (XFCE_RESOURCE_DATA, "applications/");
979 for (i = 0; dirs[i] != NULL; i++)
980 {
981 if (g_str_has_prefix (uri + 7, dirs[i]))
982 {
983 /* relative path to XFCE_RESOURCE_DATA */
984 relpath = uri + 7 + strlen (dirs[i]) - 13;
985
986 /* xfcerc can handle everything else */
987 rc = xfce_rc_config_open (XFCE_RESOURCE_DATA, relpath, FALSE);
988 xfce_rc_set_group (rc, G_KEY_FILE_DESKTOP_GROUP);
989 xfce_rc_write_bool_entry (rc, G_KEY_FILE_DESKTOP_KEY_HIDDEN, TRUE);
990 xfce_rc_close (rc);
991
992 break;
993 }
994 }
995 g_strfreev (dirs);
996 }
997 }
998
999 g_free (path);
1000 g_free (message);
1001 }
1002
1003
1004
1005 static gboolean
xfce_appfinder_window_popup_menu(GtkWidget * view,XfceAppfinderWindow * window)1006 xfce_appfinder_window_popup_menu (GtkWidget *view,
1007 XfceAppfinderWindow *window)
1008 {
1009 GtkWidget *menu;
1010 GtkTreeModel *model;
1011 GtkTreeIter iter;
1012 gchar *title;
1013 gchar *uri;
1014 GtkWidget *mi;
1015 GtkWidget *image;
1016 GtkWidget *box;
1017 GtkWidget *label;
1018 gchar *path;
1019 gboolean uri_is_local;
1020 gboolean is_bookmark;
1021
1022 if (xfce_appfinder_window_view_get_selected (window, &model, &iter))
1023 {
1024 gtk_tree_model_get (model, &iter,
1025 XFCE_APPFINDER_MODEL_COLUMN_TITLE, &title,
1026 XFCE_APPFINDER_MODEL_COLUMN_URI, &uri,
1027 XFCE_APPFINDER_MODEL_COLUMN_BOOKMARK, &is_bookmark,
1028 -1);
1029
1030 /* custom command don't have an uri */
1031 if (uri == NULL)
1032 {
1033 g_free (title);
1034 return FALSE;
1035 }
1036
1037 uri_is_local = g_str_has_prefix (uri, XFCE_APPFINDER_LOCAL_PREFIX);
1038
1039 menu = gtk_menu_new ();
1040 gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE);
1041 g_object_set_data_full (G_OBJECT (menu), "uri", uri, g_free);
1042 g_object_set_data_full (G_OBJECT (menu), "name", title, g_free);
1043 g_object_set_data (G_OBJECT (menu), "model", model);
1044 g_signal_connect (G_OBJECT (menu), "selection-done",
1045 G_CALLBACK (gtk_widget_destroy), NULL);
1046
1047 /* Title */
1048 mi = gtk_menu_item_new ();
1049 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1050 gtk_widget_set_sensitive (mi, FALSE);
1051
1052 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1053 label = gtk_label_new (title);
1054 image = gtk_image_new_from_icon_name ("", GTK_ICON_SIZE_MENU);
1055 gtk_container_add (GTK_CONTAINER (box), image);
1056 gtk_container_add (GTK_CONTAINER (box), label);
1057 gtk_container_add (GTK_CONTAINER (mi), box);
1058 gtk_widget_show_all (mi);
1059
1060 /* Separator */
1061 mi = gtk_separator_menu_item_new ();
1062 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1063 gtk_widget_show (mi);
1064
1065 /* Add/Remove from Bookmarks */
1066 mi = gtk_menu_item_new ();
1067 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1068 g_signal_connect (G_OBJECT (mi), "activate",
1069 G_CALLBACK (xfce_appfinder_window_popup_menu_toggle_bookmark), window);
1070
1071 if (is_bookmark)
1072 image = gtk_image_new_from_icon_name (XFCE_APPFINDER_STOCK_REMOVE, GTK_ICON_SIZE_MENU);
1073 else
1074 image = gtk_image_new_from_icon_name (XFCE_APPFINDER_STOCK_BOOKMARK_NEW, GTK_ICON_SIZE_MENU);
1075
1076 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1077 label = gtk_label_new (is_bookmark ? _("Remove From Bookmarks") : _("Add to Bookmarks"));
1078 gtk_container_add (GTK_CONTAINER (box), image);
1079 gtk_container_add (GTK_CONTAINER (box), label);
1080 gtk_container_add (GTK_CONTAINER (mi), box);
1081 gtk_widget_show_all (mi);
1082
1083 /* Separator */
1084 mi = gtk_separator_menu_item_new ();
1085 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1086 gtk_widget_show (mi);
1087
1088 /* Launch */
1089 mi = gtk_menu_item_new ();
1090 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1091 g_signal_connect (G_OBJECT (mi), "activate",
1092 G_CALLBACK (xfce_appfinder_window_popup_menu_execute), window);
1093
1094 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1095 label = gtk_label_new_with_mnemonic (_("La_unch"));
1096 image = gtk_image_new_from_icon_name (XFCE_APPFINDER_STOCK_EXECUTE, GTK_ICON_SIZE_MENU);
1097 gtk_container_add (GTK_CONTAINER (box), image);
1098 gtk_container_add (GTK_CONTAINER (box), label);
1099 gtk_container_add (GTK_CONTAINER (mi), box);
1100 gtk_widget_show_all (mi);
1101
1102 /* Edit */
1103 mi = gtk_menu_item_new ();
1104 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1105 g_signal_connect (G_OBJECT (mi), "activate",
1106 G_CALLBACK (xfce_appfinder_window_popup_menu_edit), window);
1107
1108 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1109 label = gtk_label_new_with_mnemonic (_("_Edit"));
1110 image = gtk_image_new_from_icon_name (XFCE_APPFINDER_STOCK_EDIT, GTK_ICON_SIZE_MENU);
1111 gtk_container_add (GTK_CONTAINER (box), image);
1112 gtk_container_add (GTK_CONTAINER (box), label);
1113 gtk_container_add (GTK_CONTAINER (mi), box);
1114 gtk_widget_show_all (mi);
1115
1116 /* Revert */
1117 mi = gtk_menu_item_new ();
1118 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1119 g_signal_connect (G_OBJECT (mi), "activate",
1120 G_CALLBACK (xfce_appfinder_window_popup_menu_revert), window);
1121 path = xfce_resource_save_location (XFCE_RESOURCE_DATA, "applications/", FALSE);
1122 gtk_widget_set_sensitive (mi, uri_is_local && g_str_has_prefix (uri + 7, path));
1123 g_free (path);
1124
1125 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1126 label = gtk_label_new_with_mnemonic (_("_Revert"));
1127 image = gtk_image_new_from_icon_name (XFCE_APPFINDER_STOCK_REVERT_TO_SAVED, GTK_ICON_SIZE_MENU);
1128 gtk_container_add (GTK_CONTAINER (box), image);
1129 gtk_container_add (GTK_CONTAINER (box), label);
1130 gtk_container_add (GTK_CONTAINER (mi), box);
1131 gtk_widget_show_all (mi);
1132
1133 /* Hide */
1134 mi = gtk_menu_item_new ();
1135 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1136 gtk_widget_set_sensitive (mi, uri_is_local);
1137 g_signal_connect (G_OBJECT (mi), "activate",
1138 G_CALLBACK (xfce_appfinder_window_popup_menu_hide), window);
1139
1140 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1141 label = gtk_label_new_with_mnemonic (_("_Hide"));
1142 image = gtk_image_new_from_icon_name ("", GTK_ICON_SIZE_MENU);
1143 gtk_container_add (GTK_CONTAINER (box), image);
1144 gtk_container_add (GTK_CONTAINER (box), label);
1145 gtk_container_add (GTK_CONTAINER (mi), box);
1146 gtk_widget_show_all (mi);
1147
1148 gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
1149
1150 return TRUE;
1151 }
1152
1153 return FALSE;
1154 }
1155
1156
1157
1158 static void
xfce_appfinder_window_update_image(XfceAppfinderWindow * window,GdkPixbuf * pixbuf)1159 xfce_appfinder_window_update_image (XfceAppfinderWindow *window,
1160 GdkPixbuf *pixbuf)
1161 {
1162 if (pixbuf == NULL)
1163 pixbuf = window->icon_find;
1164
1165 /* gtk doesn't check this */
1166 if (gtk_image_get_pixbuf (GTK_IMAGE (window->image)) != pixbuf)
1167 gtk_image_set_from_pixbuf (GTK_IMAGE (window->image), pixbuf);
1168 }
1169
1170
1171
1172 static void
xfce_appfinder_window_set_padding(GtkWidget * entry,GtkWidget * align)1173 xfce_appfinder_window_set_padding (GtkWidget *entry,
1174 GtkWidget *align)
1175 {
1176 gint padding;
1177 GtkAllocation alloc;
1178
1179 /* 48 is the icon size of XFCE_APPFINDER_ICON_SIZE_48 */
1180 gtk_widget_get_allocation (entry, &alloc);
1181 padding = (48 - alloc.height) / 2;
1182 // gtk_alignment_set_padding (GTK_ALIGNMENT (align), MAX (0, padding), 0, 0, 0);
1183 gtk_widget_set_margin_top (align, MAX (0, padding));
1184 }
1185
1186
1187
1188 static gboolean
xfce_appfinder_window_completion_match_func(GtkEntryCompletion * completion,const gchar * key,GtkTreeIter * iter,gpointer data)1189 xfce_appfinder_window_completion_match_func (GtkEntryCompletion *completion,
1190 const gchar *key,
1191 GtkTreeIter *iter,
1192 gpointer data)
1193 {
1194 const gchar *text;
1195
1196 XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (data);
1197
1198 appfinder_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), FALSE);
1199 appfinder_return_val_if_fail (XFCE_IS_APPFINDER_WINDOW (data), FALSE);
1200 appfinder_return_val_if_fail (GTK_TREE_MODEL (window->model)
1201 == gtk_entry_completion_get_model (completion), FALSE);
1202
1203 /* don't use the casefolded key generated by gtk */
1204 text = gtk_entry_get_text (GTK_ENTRY (window->entry));
1205
1206 return xfce_appfinder_model_get_visible_command (window->model, iter, text);
1207 }
1208
1209
1210
1211 static gboolean
xfce_appfinder_window_entry_changed_idle(gpointer data)1212 xfce_appfinder_window_entry_changed_idle (gpointer data)
1213 {
1214 XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (data);
1215 const gchar *text;
1216 GdkPixbuf *pixbuf;
1217 gchar *normalized;
1218 GtkTreePath *path;
1219 GtkTreeSelection *selection;
1220
1221 text = gtk_entry_get_text (GTK_ENTRY (window->entry));
1222
1223 if (gtk_widget_get_visible (window->paned))
1224 {
1225 g_free (window->filter_text);
1226
1227 if (IS_STRING (text))
1228 {
1229 normalized = g_utf8_normalize (text, -1, G_NORMALIZE_ALL);
1230 window->filter_text = g_utf8_casefold (normalized, -1);
1231 g_free (normalized);
1232 }
1233 else
1234 {
1235 window->filter_text = NULL;
1236 }
1237
1238 APPFINDER_DEBUG ("refilter entry");
1239
1240 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (window->filter_model));
1241 APPFINDER_DEBUG ("FILTER TEXT: %s\n", window->filter_text);
1242
1243 if (GTK_IS_TREE_VIEW (window->view))
1244 {
1245 gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (window->view), 0, 0);
1246
1247 if (window->filter_text == NULL)
1248 {
1249 /* if filter is empty, clear selection */
1250 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->view));
1251 gtk_tree_selection_unselect_all (selection);
1252
1253 /* reset cursor */
1254 path = gtk_tree_path_new_first ();
1255 gtk_tree_view_set_cursor (GTK_TREE_VIEW (window->view), path, NULL, FALSE);
1256 gtk_tree_path_free (path);
1257 }
1258 else if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (window->view), &path, NULL))
1259 {
1260 /* otherwise select the first match */
1261 gtk_tree_view_set_cursor (GTK_TREE_VIEW (window->view), path, NULL, FALSE);
1262 gtk_tree_path_free (path);
1263 }
1264 }
1265 else
1266 {
1267 if (window->filter_text == NULL)
1268 {
1269 /* if filter is empty, clear selection */
1270 gtk_icon_view_unselect_all (GTK_ICON_VIEW (window->view));
1271 }
1272 else if (gtk_icon_view_get_visible_range (GTK_ICON_VIEW (window->view), &path, NULL))
1273 {
1274 /* otherwise select the first match */
1275 gtk_icon_view_select_path (GTK_ICON_VIEW (window->view), path);
1276 gtk_icon_view_set_cursor (GTK_ICON_VIEW (window->view), path, NULL, FALSE);
1277 gtk_tree_path_free (path);
1278 }
1279 }
1280 }
1281 else
1282 {
1283 gtk_widget_set_sensitive (window->button_launch, IS_STRING (text));
1284
1285 /* Clear entry's error icon and tooltip */
1286 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (window->entry), GTK_ENTRY_ICON_PRIMARY, NULL);
1287 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (window->entry), GTK_ENTRY_ICON_PRIMARY, NULL);
1288
1289 pixbuf = xfce_appfinder_model_get_icon_for_command (window->model, text);
1290 xfce_appfinder_window_update_image (window, pixbuf);
1291 if (pixbuf != NULL)
1292 g_object_unref (G_OBJECT (pixbuf));
1293 }
1294
1295
1296 return FALSE;
1297 }
1298
1299
1300
1301 static void
xfce_appfinder_window_entry_changed_idle_destroyed(gpointer data)1302 xfce_appfinder_window_entry_changed_idle_destroyed (gpointer data)
1303 {
1304 XFCE_APPFINDER_WINDOW (data)->idle_entry_changed_id = 0;
1305 }
1306
1307
1308
1309 static void
xfce_appfinder_window_entry_changed(XfceAppfinderWindow * window)1310 xfce_appfinder_window_entry_changed (XfceAppfinderWindow *window)
1311 {
1312 if (window->idle_entry_changed_id != 0)
1313 g_source_remove (window->idle_entry_changed_id);
1314
1315 window->idle_entry_changed_id =
1316 gdk_threads_add_idle_full (G_PRIORITY_DEFAULT, xfce_appfinder_window_entry_changed_idle,
1317 window, xfce_appfinder_window_entry_changed_idle_destroyed);
1318 }
1319
1320
1321
1322 static void
xfce_appfinder_window_entry_activate(GtkEditable * entry,XfceAppfinderWindow * window)1323 xfce_appfinder_window_entry_activate (GtkEditable *entry,
1324 XfceAppfinderWindow *window)
1325 {
1326 GList *selected_items;
1327 GtkTreeSelection *selection;
1328 gboolean has_selection = FALSE;
1329
1330 if (gtk_widget_get_visible (window->paned))
1331 {
1332 if (GTK_IS_TREE_VIEW (window->view))
1333 {
1334 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->view));
1335 has_selection = gtk_tree_selection_count_selected_rows (selection) > 0;
1336 }
1337 else
1338 {
1339 selected_items = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (window->view));
1340 has_selection = (selected_items != NULL);
1341 g_list_free_full (selected_items, (GDestroyNotify) gtk_tree_path_free);
1342 }
1343
1344 if (has_selection)
1345 xfce_appfinder_window_execute (window, TRUE);
1346 }
1347 else if (gtk_widget_get_sensitive (window->button_launch))
1348 {
1349 gtk_button_clicked (GTK_BUTTON (window->button_launch));
1350 }
1351 }
1352
1353
1354
1355 static gboolean
xfce_appfinder_window_pointer_is_grabbed(GtkWidget * widget)1356 xfce_appfinder_window_pointer_is_grabbed (GtkWidget *widget)
1357 {
1358 GdkSeat *seat;
1359 GdkDevice *pointer;
1360 GdkDisplay *display;
1361
1362 display = gtk_widget_get_display (widget);
1363 seat = gdk_display_get_default_seat (display);
1364 pointer = gdk_seat_get_pointer (seat);
1365 return gdk_display_device_is_grabbed (display, pointer);
1366 }
1367
1368
1369
1370 static gboolean
xfce_appfinder_window_entry_key_press_event(GtkWidget * entry,GdkEventKey * event,XfceAppfinderWindow * window)1371 xfce_appfinder_window_entry_key_press_event (GtkWidget *entry,
1372 GdkEventKey *event,
1373 XfceAppfinderWindow *window)
1374 {
1375 gboolean expand;
1376 gboolean is_expanded;
1377 GtkTreePath *path;
1378
1379 if (event->keyval == GDK_KEY_Tab &&
1380 !gtk_widget_get_visible (window->paned) &&
1381 xfce_appfinder_window_pointer_is_grabbed (entry))
1382 {
1383 /* don't tab to the close button */
1384 return TRUE;
1385 }
1386
1387 if (event->keyval == GDK_KEY_Up ||
1388 event->keyval == GDK_KEY_Down)
1389 {
1390 expand = (event->keyval == GDK_KEY_Down);
1391 is_expanded = gtk_widget_get_visible (window->paned);
1392
1393 if (is_expanded != expand)
1394 {
1395 /* don't break entry completion navigation in collapsed mode */
1396 if (!is_expanded && xfce_appfinder_window_pointer_is_grabbed (entry))
1397 {
1398 /* window is still collapsed and the pointer is grabbed
1399 * by the popup menu, do nothing with the event */
1400 return FALSE;
1401 }
1402
1403 xfce_appfinder_window_set_expanded (window, expand);
1404 return TRUE;
1405 }
1406
1407 /* The first item is usually selected, so we should jump to 2nd one
1408 * when down key is pressed */
1409 if (is_expanded && expand &&
1410 GTK_IS_TREE_VIEW (window->view) && /* does not make sense for icon view */
1411 xfce_appfinder_window_view_get_selected_path (window, &path))
1412 {
1413 gtk_tree_path_next (path);
1414 gtk_tree_view_set_cursor (GTK_TREE_VIEW (window->view), path, NULL, FALSE);
1415 gtk_tree_path_free (path);
1416 }
1417 }
1418
1419 return FALSE;
1420 }
1421
1422
1423
1424 static void
xfce_appfinder_window_drag_begin(GtkWidget * widget,GdkDragContext * drag_context,XfceAppfinderWindow * window)1425 xfce_appfinder_window_drag_begin (GtkWidget *widget,
1426 GdkDragContext *drag_context,
1427 XfceAppfinderWindow *window)
1428 {
1429 GtkTreeModel *model;
1430 GtkTreeIter iter;
1431 GdkPixbuf *pixbuf;
1432
1433 if (xfce_appfinder_window_view_get_selected (window, &model, &iter))
1434 {
1435 gtk_tree_model_get (model, &iter, XFCE_APPFINDER_MODEL_COLUMN_ICON_LARGE, &pixbuf, -1);
1436 if (G_LIKELY (pixbuf != NULL))
1437 {
1438 gtk_drag_set_icon_pixbuf (drag_context, pixbuf, 0, 0);
1439 g_object_unref (G_OBJECT (pixbuf));
1440 }
1441 }
1442 else
1443 {
1444 gtk_drag_set_icon_name (drag_context, XFCE_APPFINDER_STOCK_DIALOG_ERROR, 0, 0);
1445 }
1446 }
1447
1448
1449
1450 static void
xfce_appfinder_window_drag_data_get(GtkWidget * widget,GdkDragContext * drag_context,GtkSelectionData * data,guint info,guint drag_time,XfceAppfinderWindow * window)1451 xfce_appfinder_window_drag_data_get (GtkWidget *widget,
1452 GdkDragContext *drag_context,
1453 GtkSelectionData *data,
1454 guint info,
1455 guint drag_time,
1456 XfceAppfinderWindow *window)
1457 {
1458 GtkTreeModel *model;
1459 GtkTreeIter iter;
1460 gchar *uris[2];
1461
1462 if (xfce_appfinder_window_view_get_selected (window, &model, &iter))
1463 {
1464 uris[1] = NULL;
1465 gtk_tree_model_get (model, &iter, XFCE_APPFINDER_MODEL_COLUMN_URI, &uris[0], -1);
1466 gtk_selection_data_set_uris (data, uris);
1467 g_free (uris[0]);
1468 }
1469 }
1470
1471
1472
1473 static gboolean
xfce_appfinder_window_treeview_key_press_event(GtkWidget * widget,GdkEventKey * event,XfceAppfinderWindow * window)1474 xfce_appfinder_window_treeview_key_press_event (GtkWidget *widget,
1475 GdkEventKey *event,
1476 XfceAppfinderWindow *window)
1477 {
1478 GdkEvent ev;
1479 GtkTreePath *path;
1480
1481 if (widget == window->view)
1482 {
1483 if (event->keyval == GDK_KEY_Control_L ||
1484 event->keyval == GDK_KEY_Control_R ||
1485 event->keyval == GDK_KEY_Shift_L ||
1486 event->keyval == GDK_KEY_Shift_R ||
1487 event->keyval == GDK_KEY_Alt_L ||
1488 event->keyval == GDK_KEY_Alt_R ||
1489 event->keyval == GDK_KEY_Right ||
1490 event->keyval == GDK_KEY_Down)
1491 return FALSE;
1492
1493 if (event->keyval == GDK_KEY_Left)
1494 {
1495 if (gtk_widget_get_realized (window->sidepane))
1496 gtk_widget_grab_focus (window->sidepane);
1497 return TRUE;
1498 }
1499
1500 if (event->keyval == GDK_KEY_Up)
1501 {
1502 if (xfce_appfinder_window_view_get_selected_path (window, &path))
1503 {
1504 if (!gtk_tree_path_prev (path))
1505 gtk_widget_grab_focus (window->entry);
1506 gtk_tree_path_free (path);
1507 }
1508
1509 return FALSE;
1510 }
1511
1512 gtk_widget_grab_focus (window->entry);
1513
1514 ev.key = *event;
1515 gtk_propagate_event (window->entry, &ev);
1516
1517 return TRUE;
1518 }
1519
1520 if (widget == window->sidepane)
1521 {
1522 if (event->keyval == GDK_KEY_Right)
1523 {
1524 gtk_widget_grab_focus (window->view);
1525 return TRUE;
1526 }
1527 }
1528
1529 return FALSE;
1530 }
1531
1532
1533
1534 static void
xfce_appfinder_window_entry_icon_released(GtkEntry * entry,GtkEntryIconPosition icon_pos,GdkEvent * event,XfceAppfinderWindow * window)1535 xfce_appfinder_window_entry_icon_released (GtkEntry *entry,
1536 GtkEntryIconPosition icon_pos,
1537 GdkEvent *event,
1538 XfceAppfinderWindow *window)
1539 {
1540 if (icon_pos == GTK_ENTRY_ICON_SECONDARY)
1541 xfce_appfinder_window_set_expanded (window, !gtk_widget_get_visible (window->paned));
1542 }
1543
1544
1545
1546 static void
xfce_appfinder_window_category_changed(GtkTreeSelection * selection,XfceAppfinderWindow * window)1547 xfce_appfinder_window_category_changed (GtkTreeSelection *selection,
1548 XfceAppfinderWindow *window)
1549 {
1550 GtkTreeIter iter;
1551 GtkTreeModel *model;
1552 GarconMenuDirectory *category;
1553 gchar *name;
1554
1555 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1556 {
1557 gtk_tree_model_get (model, &iter,
1558 XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_DIRECTORY, &category,
1559 XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_NAME, &name, -1);
1560
1561 if (window->filter_category != category)
1562 {
1563 if (window->filter_category != NULL)
1564 g_object_unref (G_OBJECT (window->filter_category));
1565
1566 if (category == NULL)
1567 window->filter_category = NULL;
1568 else
1569 window->filter_category = GARCON_MENU_DIRECTORY (g_object_ref (G_OBJECT (category)));
1570
1571 APPFINDER_DEBUG ("refilter category");
1572
1573 /* update visible items */
1574 if (GTK_IS_TREE_VIEW (window->view))
1575 model = gtk_tree_view_get_model (GTK_TREE_VIEW (window->view));
1576 else
1577 model = gtk_icon_view_get_model (GTK_ICON_VIEW (window->view));
1578 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (window->filter_model));
1579
1580 /* store last category */
1581 if (xfconf_channel_get_bool (window->channel, "/remember-category", FALSE))
1582 xfconf_channel_set_string (window->channel, "/last/category", name);
1583 }
1584
1585 g_free (name);
1586 if (category != NULL)
1587 g_object_unref (G_OBJECT (category));
1588 }
1589 }
1590
1591
1592
1593 static void
xfce_appfinder_window_category_set_categories(XfceAppfinderModel * signal_from_model,XfceAppfinderWindow * window)1594 xfce_appfinder_window_category_set_categories (XfceAppfinderModel *signal_from_model,
1595 XfceAppfinderWindow *window)
1596 {
1597 GSList *categories;
1598 GtkTreePath *path;
1599 gchar *name = NULL;
1600 GtkTreeModel *model;
1601 GtkTreeIter iter;
1602 GtkTreeSelection *selection;
1603
1604 appfinder_return_if_fail (GTK_IS_TREE_VIEW (window->sidepane));
1605
1606 if (signal_from_model != NULL)
1607 {
1608 /* reload from the model, make sure we restore the selected category */
1609 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->sidepane));
1610 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1611 gtk_tree_model_get (model, &iter, XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_NAME, &name, -1);
1612 }
1613
1614 /* update the categories */
1615 categories = xfce_appfinder_model_get_categories (window->model);
1616 if (categories != NULL)
1617 xfce_appfinder_category_model_set_categories (window->category_model, categories);
1618 g_slist_free (categories);
1619
1620 if (name == NULL && xfconf_channel_get_bool (window->channel, "/remember-category", FALSE))
1621 name = xfconf_channel_get_string (window->channel, "/last/category", NULL);
1622
1623 path = xfce_appfinder_category_model_find_category (window->category_model, name);
1624 if (path != NULL)
1625 {
1626 gtk_tree_view_set_cursor (GTK_TREE_VIEW (window->sidepane), path, NULL, FALSE);
1627 gtk_tree_path_free (path);
1628 }
1629
1630 g_free (name);
1631 }
1632
1633
1634
1635 static void
xfce_appfinder_window_preferences(GtkWidget * button,XfceAppfinderWindow * window)1636 xfce_appfinder_window_preferences (GtkWidget *button,
1637 XfceAppfinderWindow *window)
1638 {
1639 appfinder_return_if_fail (GTK_IS_WIDGET (button));
1640
1641 /* preload the actions, to make sure there are default values */
1642 if (window->actions == NULL)
1643 window->actions = xfce_appfinder_actions_get ();
1644
1645 xfce_appfinder_preferences_show (gtk_widget_get_screen (button));
1646 }
1647
1648
1649
1650 static void
xfce_appfinder_window_property_changed(XfconfChannel * channel,const gchar * prop,const GValue * value,XfceAppfinderWindow * window)1651 xfce_appfinder_window_property_changed (XfconfChannel *channel,
1652 const gchar *prop,
1653 const GValue *value,
1654 XfceAppfinderWindow *window)
1655 {
1656 appfinder_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
1657 appfinder_return_if_fail (window->channel == channel);
1658
1659 if (g_strcmp0 (prop, "/icon-view") == 0)
1660 {
1661 xfce_appfinder_window_view (window);
1662 }
1663 else if (g_strcmp0 (prop, "/item-icon-size") == 0)
1664 {
1665 if (GTK_IS_ICON_VIEW (window->view))
1666 xfce_appfinder_window_set_item_width (window);
1667 }
1668 else if (g_strcmp0 (prop, "/text-beside-icons") == 0)
1669 {
1670 if (GTK_IS_ICON_VIEW (window->view))
1671 xfce_appfinder_window_set_item_width (window);
1672 }
1673 else if (g_strcmp0 (prop, "/hide-category-pane") == 0)
1674 {
1675 gboolean hide = g_value_get_boolean (value);
1676 gtk_widget_set_visible (gtk_widget_get_parent (window->sidepane), !hide);
1677
1678 if (hide) {
1679 GtkTreePath *path = gtk_tree_path_new_from_string ("0");
1680 gtk_tree_view_set_cursor (GTK_TREE_VIEW (window->sidepane), path, NULL, FALSE);
1681 gtk_tree_path_free (path);
1682 }
1683 }
1684 }
1685
1686
1687
1688 static gboolean
xfce_appfinder_window_item_visible(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)1689 xfce_appfinder_window_item_visible (GtkTreeModel *model,
1690 GtkTreeIter *iter,
1691 gpointer data)
1692 {
1693 XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (data);
1694 const gchar *filter_string = gtk_entry_get_text (GTK_ENTRY (window->entry));
1695
1696 return xfce_appfinder_model_get_visible (XFCE_APPFINDER_MODEL (model),
1697 iter,
1698 window->filter_category,
1699 filter_string,
1700 window->filter_text);
1701 }
1702
1703
1704
1705 static void
xfce_appfinder_window_item_changed(XfceAppfinderWindow * window)1706 xfce_appfinder_window_item_changed (XfceAppfinderWindow *window)
1707 {
1708 GtkTreeIter iter;
1709 GtkTreeModel *model;
1710 gboolean can_launch;
1711 GdkPixbuf *pixbuf;
1712
1713 if (gtk_widget_get_visible (window->paned))
1714 {
1715 can_launch = xfce_appfinder_window_view_get_selected (window, &model, &iter);
1716 gtk_widget_set_sensitive (window->button_launch, can_launch);
1717
1718 if (can_launch)
1719 {
1720 gtk_tree_model_get (model, &iter, XFCE_APPFINDER_MODEL_COLUMN_ICON_LARGE, &pixbuf, -1);
1721 if (G_LIKELY (pixbuf != NULL))
1722 {
1723 xfce_appfinder_window_update_image (window, pixbuf);
1724 g_object_unref (G_OBJECT (pixbuf));
1725 }
1726 }
1727 else
1728 {
1729 xfce_appfinder_window_update_image (window, NULL);
1730 }
1731 }
1732 }
1733
1734
1735
1736 static void
xfce_appfinder_window_row_activated(XfceAppfinderWindow * window)1737 xfce_appfinder_window_row_activated (XfceAppfinderWindow *window)
1738 {
1739 if (gtk_widget_get_sensitive (window->button_launch))
1740 gtk_button_clicked (GTK_BUTTON (window->button_launch));
1741 }
1742
1743
1744
1745 static void
xfce_appfinder_window_icon_theme_changed(XfceAppfinderWindow * window)1746 xfce_appfinder_window_icon_theme_changed (XfceAppfinderWindow *window)
1747 {
1748 appfinder_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
1749
1750 if (window->icon_find != NULL)
1751 g_object_unref (G_OBJECT (window->icon_find));
1752 window->icon_find = xfce_appfinder_model_load_pixbuf (XFCE_APPFINDER_STOCK_FIND, XFCE_APPFINDER_ICON_SIZE_48);
1753
1754 /* drop cached pixbufs */
1755 if (G_LIKELY (window->model != NULL))
1756 xfce_appfinder_model_icon_theme_changed (window->model);
1757
1758 if (G_LIKELY (window->category_model != NULL))
1759 xfce_appfinder_category_model_icon_theme_changed (window->category_model);
1760
1761 /* update state */
1762 xfce_appfinder_window_entry_changed (window);
1763 xfce_appfinder_window_item_changed (window);
1764 }
1765
1766
1767
1768 static gboolean
xfce_appfinder_window_execute_command(const gchar * text,GdkScreen * screen,XfceAppfinderWindow * window,gboolean only_custom_cmd,gboolean * save_cmd,GError ** error)1769 xfce_appfinder_window_execute_command (const gchar *text,
1770 GdkScreen *screen,
1771 XfceAppfinderWindow *window,
1772 gboolean only_custom_cmd,
1773 gboolean *save_cmd,
1774 GError **error)
1775 {
1776 gboolean succeed = FALSE;
1777 gchar *action_cmd = NULL;
1778 gchar *expanded;
1779
1780 appfinder_return_val_if_fail (error != NULL && *error == NULL, FALSE);
1781 appfinder_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
1782
1783 if (!IS_STRING (text))
1784 return TRUE;
1785
1786 if (window->actions == NULL)
1787 window->actions = xfce_appfinder_actions_get ();
1788
1789 /* try to match a custom action */
1790 action_cmd = xfce_appfinder_actions_execute (window->actions, text, save_cmd, error);
1791 if (*error != NULL)
1792 return FALSE;
1793 else if (action_cmd != NULL)
1794 text = action_cmd;
1795 else if (only_custom_cmd)
1796 return FALSE;
1797
1798 if (IS_STRING (text))
1799 {
1800 /* expand variables */
1801 expanded = xfce_expand_variables (text, NULL);
1802
1803 /* spawn the command */
1804 APPFINDER_DEBUG ("spawn \"%s\"", expanded);
1805 #if LIBXFCE4UI_CHECK_VERSION (4, 15, 6)
1806 succeed = xfce_spawn_command_line (screen, expanded, FALSE, FALSE, TRUE, error);
1807 #else
1808 succeed = xfce_spawn_command_line_on_screen (screen, expanded, FALSE, FALSE, error);
1809 #endif
1810 g_free (expanded);
1811 }
1812
1813 g_free (action_cmd);
1814
1815 return succeed;
1816 }
1817
1818
1819
1820 static void
xfce_appfinder_window_launch_clicked(XfceAppfinderWindow * window)1821 xfce_appfinder_window_launch_clicked (XfceAppfinderWindow *window)
1822 {
1823 xfce_appfinder_window_execute (window, TRUE);
1824 }
1825
1826
1827
1828 static void
xfce_appfinder_window_execute(XfceAppfinderWindow * window,gboolean close_on_succeed)1829 xfce_appfinder_window_execute (XfceAppfinderWindow *window,
1830 gboolean close_on_succeed)
1831 {
1832 GtkTreeModel *model, *child_model;
1833 GtkTreeIter iter, child_iter;
1834 GError *error = NULL;
1835 gboolean result = FALSE;
1836 GdkScreen *screen;
1837 const gchar *text;
1838 gchar *cmd = NULL;
1839 gboolean regular_command = FALSE;
1840 gboolean save_cmd;
1841 gboolean only_custom_cmd = FALSE;
1842 const gchar *uri;
1843
1844 screen = gtk_window_get_screen (GTK_WINDOW (window));
1845 if (gtk_widget_get_visible (window->paned))
1846 {
1847 if (!gtk_widget_get_sensitive (window->button_launch))
1848 {
1849 only_custom_cmd = TRUE;
1850 goto entry_execute;
1851 }
1852
1853 if (xfce_appfinder_window_view_get_selected (window, &model, &iter))
1854 {
1855 child_model = model;
1856 gtk_tree_model_get (model, &iter, XFCE_APPFINDER_MODEL_COLUMN_URI, &uri, -1);
1857
1858 if (GTK_IS_TREE_MODEL_SORT (model) || xfce_appfinder_should_sort_icon_view ())
1859 {
1860 gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model), &child_iter, &iter);
1861 iter = child_iter;
1862 child_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
1863 }
1864
1865 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (child_model), &child_iter, &iter);
1866 result = xfce_appfinder_model_execute (window->model, &child_iter, screen, ®ular_command, &error);
1867
1868 xfce_appfinder_window_update_frecency (window, model, uri);
1869 if (!result && regular_command)
1870 {
1871 gtk_tree_model_get (model, &child_iter, XFCE_APPFINDER_MODEL_COLUMN_COMMAND, &cmd, -1);
1872 result = xfce_appfinder_window_execute_command (cmd, screen, window, FALSE, NULL, &error);
1873 g_free (cmd);
1874 }
1875 }
1876 }
1877 else
1878 {
1879 if (!gtk_widget_get_sensitive (window->button_launch))
1880 return;
1881
1882 entry_execute:
1883
1884 text = gtk_entry_get_text (GTK_ENTRY (window->entry));
1885 save_cmd = TRUE;
1886
1887 if (xfce_appfinder_window_execute_command (text, screen, window, only_custom_cmd, &save_cmd, &error))
1888 {
1889 if (save_cmd)
1890 result = xfce_appfinder_model_save_command (window->model, text, &error);
1891 else
1892 result = TRUE;
1893 }
1894 }
1895
1896 if (!only_custom_cmd)
1897 {
1898 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (window->entry), GTK_ENTRY_ICON_PRIMARY,
1899 result ? NULL : XFCE_APPFINDER_STOCK_DIALOG_ERROR);
1900 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (window->entry), GTK_ENTRY_ICON_PRIMARY,
1901 error != NULL ? error->message : NULL);
1902 }
1903
1904 if (error != NULL)
1905 {
1906 g_printerr ("%s: failed to execute: %s\n", G_LOG_DOMAIN, error->message);
1907 g_error_free (error);
1908 }
1909
1910 if (result && close_on_succeed)
1911 gtk_widget_destroy (GTK_WIDGET (window));
1912 }
1913
1914
1915
1916 static void
xfce_appfinder_window_update_frecency(XfceAppfinderWindow * window,GtkTreeModel * model,const gchar * uri)1917 xfce_appfinder_window_update_frecency (XfceAppfinderWindow *window,
1918 GtkTreeModel *model,
1919 const gchar *uri)
1920 {
1921 GFile *gfile;
1922 gchar *desktop_id;
1923 GError *error = NULL;
1924
1925 if (uri != NULL)
1926 {
1927 gfile = g_file_new_for_uri (uri);
1928 desktop_id = g_file_get_basename (gfile);
1929 g_object_unref (G_OBJECT (gfile));
1930 APPFINDER_DEBUG ("desktop : %s", desktop_id);
1931
1932 model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (window->filter_model));
1933 xfce_appfinder_model_update_frecency (XFCE_APPFINDER_MODEL (model), desktop_id, &error);
1934
1935 g_free (desktop_id);
1936 g_free (error);
1937 }
1938 }
1939
1940
1941
1942 void
xfce_appfinder_window_set_expanded(XfceAppfinderWindow * window,gboolean expanded)1943 xfce_appfinder_window_set_expanded (XfceAppfinderWindow *window,
1944 gboolean expanded)
1945 {
1946 GdkGeometry hints;
1947 gint width;
1948 GtkEntryCompletion *completion;
1949
1950 APPFINDER_DEBUG ("set expand = %s", expanded ? "true" : "false");
1951
1952 /* force window geomentry */
1953 if (expanded)
1954 {
1955 gtk_window_set_geometry_hints (GTK_WINDOW (window), NULL, NULL, 0);
1956 gtk_window_get_size (GTK_WINDOW (window), &width, NULL);
1957 gtk_window_resize (GTK_WINDOW (window), width, window->last_window_height);
1958 }
1959 else
1960 {
1961 if (gtk_widget_get_visible (GTK_WIDGET (window)))
1962 gtk_window_get_size (GTK_WINDOW (window), NULL, &window->last_window_height);
1963
1964 hints.max_height = -1;
1965 hints.max_width = G_MAXINT;
1966 gtk_window_set_geometry_hints (GTK_WINDOW (window), NULL, &hints, GDK_HINT_MAX_SIZE);
1967 }
1968
1969 /* show/hide pane with treeviews */
1970 gtk_widget_set_visible (window->paned, expanded);
1971
1972 /* toggle icon */
1973 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (window->entry), GTK_ENTRY_ICON_SECONDARY,
1974 expanded ? XFCE_APPFINDER_STOCK_GO_UP : XFCE_APPFINDER_STOCK_GO_DOWN);
1975 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (window->entry), GTK_ENTRY_ICON_PRIMARY, NULL);
1976
1977 /* update completion (remove completed text of restart completion) */
1978 completion = gtk_entry_get_completion (GTK_ENTRY (window->entry));
1979 if (completion != NULL)
1980 gtk_editable_delete_selection (GTK_EDITABLE (window->entry));
1981 gtk_entry_set_completion (GTK_ENTRY (window->entry), expanded ? NULL : window->completion);
1982 if (!expanded && gtk_entry_get_text_length (GTK_ENTRY (window->entry)) > 0)
1983 gtk_entry_completion_insert_prefix (window->completion);
1984
1985 /* update state */
1986 xfce_appfinder_window_entry_changed (window);
1987 xfce_appfinder_window_item_changed (window);
1988 }
1989
1990
1991
1992 static gint
xfce_appfinder_window_sort_items(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)1993 xfce_appfinder_window_sort_items (GtkTreeModel *model,
1994 GtkTreeIter *a,
1995 GtkTreeIter *b,
1996 gpointer data)
1997 {
1998 gchar *normalized, *casefold, *title_a, *title_b, *found;
1999 GtkWidget *entry = GTK_WIDGET (data);
2000 gint result = -1;
2001
2002 appfinder_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
2003
2004 normalized = g_utf8_normalize (gtk_entry_get_text (GTK_ENTRY (entry)), -1, G_NORMALIZE_ALL);
2005 casefold = g_utf8_casefold (normalized, -1);
2006 g_free (normalized);
2007
2008 gtk_tree_model_get (model, a, XFCE_APPFINDER_MODEL_COLUMN_TITLE, &title_a, -1);
2009 normalized = g_utf8_normalize (title_a, -1, G_NORMALIZE_ALL);
2010 g_free (title_a);
2011 title_a = g_utf8_casefold (normalized, -1);
2012 g_free (normalized);
2013
2014 gtk_tree_model_get (model, b, XFCE_APPFINDER_MODEL_COLUMN_TITLE, &title_b, -1);
2015 normalized = g_utf8_normalize (title_b, -1, G_NORMALIZE_ALL);
2016 g_free (title_b);
2017 title_b = g_utf8_casefold (normalized, -1);
2018 g_free (normalized);
2019
2020 if (g_strcmp0 (casefold, "") == 0)
2021 result = g_strcmp0 (title_a, title_b);
2022 else
2023 {
2024 found = g_strrstr (title_a, casefold);
2025 if (found)
2026 result -= (G_MAXINT - (found - title_a));
2027
2028 found = g_strrstr (title_b, casefold);
2029 if (found)
2030 result += (G_MAXINT - (found - title_b));
2031 }
2032
2033 g_free (casefold);
2034 g_free (title_a);
2035 g_free (title_b);
2036 return result;
2037 }
2038
2039
2040
2041 static gint
xfce_appfinder_window_sort_items_frecency(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)2042 xfce_appfinder_window_sort_items_frecency (GtkTreeModel *model,
2043 GtkTreeIter *a,
2044 GtkTreeIter *b,
2045 gpointer data)
2046 {
2047 guint a_freq, b_freq;
2048 guint64 a_rec, b_rec;
2049 guint a_res, b_res;
2050
2051 gtk_tree_model_get (model, a, XFCE_APPFINDER_MODEL_COLUMN_FREQUENCY, &a_freq, -1);
2052 gtk_tree_model_get (model, b, XFCE_APPFINDER_MODEL_COLUMN_FREQUENCY, &b_freq, -1);
2053
2054 gtk_tree_model_get (model, a, XFCE_APPFINDER_MODEL_COLUMN_RECENCY, &a_rec, -1);
2055 gtk_tree_model_get (model, b, XFCE_APPFINDER_MODEL_COLUMN_RECENCY, &b_rec, -1);
2056
2057 a_res = xfce_appfinder_model_calculate_frecency (a_freq, a_rec);
2058 b_res = xfce_appfinder_model_calculate_frecency (b_freq, b_rec);
2059
2060 /* Sort according the frecency */
2061 if (b_res - a_res != 0)
2062 return b_res - a_res;
2063
2064 /* If they have the same frecency, fallback to the alphabetical order */
2065 return xfce_appfinder_window_sort_items (model, a, b, data);
2066 }
2067
2068
2069
2070 /*
2071 * Checks for gtk => 3.22.27 during runtime.
2072 * This is necessary because sort model for icon view did not work as expected.
2073 */
2074 static gboolean
xfce_appfinder_should_sort_icon_view(void)2075 xfce_appfinder_should_sort_icon_view (void)
2076 {
2077 return gtk_get_major_version () >= 3 &&
2078 gtk_get_minor_version () >= 22 &&
2079 gtk_get_micro_version () >= 27;
2080 }
2081