1 /*
2  *  xfce4-settings-manager
3  *
4  *  Copyright (c) 2008 Brian Tarricone <bjt23@cornell.edu>
5  *                     Jannis Pohlmann <jannis@xfce.org>
6  *  Copyright (c) 2012 Nick Schermer <nick@xfce.org>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; version 2 of the License ONLY.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_STRING_H
30 #include <string.h>
31 #endif
32 
33 #include <gtk/gtk.h>
34 #include <gtk/gtkx.h>
35 #include <gdk/gdkkeysyms.h>
36 
37 #include <libxfce4util/libxfce4util.h>
38 #include <libxfce4ui/libxfce4ui.h>
39 #include <xfconf/xfconf.h>
40 #include <garcon/garcon.h>
41 #include <exo/exo.h>
42 
43 #include "xfce-settings-manager-dialog.h"
44 
45 #define TEXT_WIDTH (128)
46 #define ICON_WIDTH (48)
47 
48 
49 
50 struct _XfceSettingsManagerDialogClass
51 {
52     XfceTitledDialogClass __parent__;
53 };
54 
55 struct _XfceSettingsManagerDialog
56 {
57     XfceTitledDialog __parent__;
58 
59     XfconfChannel  *channel;
60     GarconMenu     *menu;
61 
62     GtkListStore   *store;
63 
64     GtkWidget      *revealer;
65     GtkWidget      *filter_button;
66     GtkWidget      *filter_entry;
67     gchar          *filter_text;
68 
69     GtkWidget      *category_viewport;
70     GtkWidget      *category_scroll;
71     GtkWidget      *category_box;
72 
73     GList          *categories;
74 
75     GtkCssProvider *css_provider;
76 
77     GtkWidget      *socket_scroll;
78     GtkWidget      *socket_viewport;
79     GarconMenuItem *socket_item;
80 
81     GtkWidget      *button_back;
82     GtkWidget      *button_help;
83 
84     gchar          *help_page;
85     gchar          *help_component;
86     gchar          *help_version;
87 };
88 
89 typedef struct
90 {
91     GarconMenuDirectory       *directory;
92     XfceSettingsManagerDialog *dialog;
93     GtkWidget                 *iconview;
94     GtkWidget                 *box;
95 }
96 DialogCategory;
97 
98 
99 
100 enum
101 {
102     COLUMN_NAME,
103     COLUMN_ICON_NAME,
104     COLUMN_TOOLTIP,
105     COLUMN_MENU_ITEM,
106     COLUMN_MENU_DIRECTORY,
107     COLUMN_FILTER_TEXT,
108     N_COLUMNS
109 };
110 
111 
112 
113 static void     xfce_settings_manager_dialog_finalize        (GObject                   *object);
114 static void     xfce_settings_manager_dialog_style_updated   (GtkWidget                 *widget);
115 static void     xfce_settings_manager_dialog_set_hover_style (XfceSettingsManagerDialog *dialog);
116 static void     xfce_settings_manager_dialog_response        (GtkDialog                 *widget,
117                                                               gint                       response_id);
118 static void     xfce_settings_manager_dialog_set_title       (XfceSettingsManagerDialog *dialog,
119                                                               const gchar               *title,
120                                                               const gchar               *icon_name);
121 static void     xfce_settings_manager_dialog_go_back         (XfceSettingsManagerDialog *dialog);
122 static void     xfce_settings_manager_show_filter_toggled    (GtkToggleButton           *button,
123                                                               gpointer                   user_data);
124 static void     xfce_settings_manager_dialog_entry_changed   (GtkWidget                 *entry,
125                                                               XfceSettingsManagerDialog *dialog);
126 static gboolean xfce_settings_manager_dialog_entry_key_press (GtkWidget                 *entry,
127                                                               GdkEventKey               *event,
128                                                               XfceSettingsManagerDialog *dialog);
129 static void     xfce_settings_manager_dialog_menu_reload     (XfceSettingsManagerDialog *dialog);
130 static void     xfce_settings_manager_dialog_scroll_to_item  (GtkWidget                 *iconview,
131                                                               XfceSettingsManagerDialog *dialog);
132 
133 
134 
G_DEFINE_TYPE(XfceSettingsManagerDialog,xfce_settings_manager_dialog,XFCE_TYPE_TITLED_DIALOG)135 G_DEFINE_TYPE (XfceSettingsManagerDialog, xfce_settings_manager_dialog, XFCE_TYPE_TITLED_DIALOG)
136 
137 
138 
139 static void
140 xfce_settings_manager_dialog_class_init (XfceSettingsManagerDialogClass *klass)
141 {
142     GObjectClass   *gobject_class;
143     GtkDialogClass *gtkdialog_class;
144     GtkWidgetClass *gtkwiget_class;
145 
146     gobject_class = G_OBJECT_CLASS (klass);
147     gobject_class->finalize = xfce_settings_manager_dialog_finalize;
148 
149     gtkwiget_class = GTK_WIDGET_CLASS (klass);
150     gtkwiget_class->style_updated = xfce_settings_manager_dialog_style_updated;
151 
152     gtkdialog_class = GTK_DIALOG_CLASS (klass);
153     gtkdialog_class->response = xfce_settings_manager_dialog_response;
154 }
155 
156 
157 
158 static void
xfce_settings_manager_queue_resize(XfceSettingsManagerDialog * dialog)159 xfce_settings_manager_queue_resize (XfceSettingsManagerDialog *dialog)
160 {
161     GList *li;
162     DialogCategory *category;
163 
164     for (li = dialog->categories; li != NULL; li = li->next)
165     {
166         category = li->data;
167         gtk_widget_queue_resize (GTK_WIDGET (category->iconview));
168     }
169 }
170 
171 static gboolean
xfce_settings_manager_queue_resize_cb(gpointer user_data)172 xfce_settings_manager_queue_resize_cb (gpointer user_data)
173 {
174     XfceSettingsManagerDialog *dialog = user_data;
175 
176     xfce_settings_manager_queue_resize (dialog);
177     return FALSE;
178 }
179 
180 
181 
182 static void
xfce_settings_manager_dialog_check_resize(GtkWidget * widget,gpointer * user_data)183 xfce_settings_manager_dialog_check_resize (GtkWidget *widget, gpointer *user_data)
184 {
185     XfceSettingsManagerDialog *dialog = XFCE_SETTINGS_MANAGER_DIALOG (user_data);
186     xfce_settings_manager_queue_resize (dialog);
187 }
188 
189 
190 
191 static void
xfce_settings_manager_dialog_init(XfceSettingsManagerDialog * dialog)192 xfce_settings_manager_dialog_init (XfceSettingsManagerDialog *dialog)
193 {
194     GtkWidget *dialog_vbox;
195     GtkWidget *box;
196     GtkWidget *entry;
197     GtkWidget *scroll;
198     GtkWidget *viewport;
199     GtkWidget *image;
200     GtkWidget *button;
201     gchar     *path;
202 
203     dialog->channel = xfconf_channel_get ("xfce4-settings-manager");
204 
205     dialog->store = gtk_list_store_new (N_COLUMNS,
206                                         G_TYPE_STRING,
207                                         G_TYPE_STRING,
208                                         G_TYPE_STRING,
209                                         GARCON_TYPE_MENU_ITEM,
210                                         GARCON_TYPE_MENU_DIRECTORY,
211                                         G_TYPE_STRING);
212 
213     path = xfce_resource_lookup (XFCE_RESOURCE_CONFIG, "menus/xfce-settings-manager.menu");
214     dialog->menu = garcon_menu_new_for_path (path != NULL ? path : MENUFILE);
215     g_free (path);
216 
217     gtk_window_set_default_size (GTK_WINDOW (dialog),
218       xfconf_channel_get_int (dialog->channel, "/last/window-width", 640),
219       xfconf_channel_get_int (dialog->channel, "/last/window-height", 500));
220     xfce_settings_manager_dialog_set_title (dialog, NULL, NULL);
221 
222     /* Add a buttonbox (Help, All Settings, Close) at bottom of the main box */
223     xfce_titled_dialog_create_action_area (XFCE_TITLED_DIALOG (dialog));
224 
225     dialog->button_help = xfce_titled_dialog_add_button (XFCE_TITLED_DIALOG (dialog), _("_Help"), GTK_RESPONSE_HELP);
226     image = gtk_image_new_from_icon_name ("help-browser", GTK_ICON_SIZE_BUTTON);
227     gtk_button_set_image (GTK_BUTTON (dialog->button_help), image);
228 
229     dialog->button_back = xfce_titled_dialog_add_button (XFCE_TITLED_DIALOG (dialog), _("All _Settings"), GTK_RESPONSE_NONE);
230     image = gtk_image_new_from_icon_name ("go-previous-symbolic", GTK_ICON_SIZE_BUTTON);
231     gtk_button_set_image (GTK_BUTTON (dialog->button_back), image);
232     gtk_widget_set_sensitive (dialog->button_back, FALSE);
233     g_signal_connect_swapped (G_OBJECT (dialog->button_back), "clicked",
234         G_CALLBACK (xfce_settings_manager_dialog_go_back), dialog);
235 
236     button = xfce_titled_dialog_add_button (XFCE_TITLED_DIALOG (dialog), _("_Close"), GTK_RESPONSE_CLOSE);
237     image = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_BUTTON);
238     gtk_button_set_image (GTK_BUTTON (button), image);
239 
240     /* Add the filter bar */
241     box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
242     dialog->revealer = gtk_revealer_new ();
243     gtk_revealer_set_transition_type (GTK_REVEALER (dialog->revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN);
244     gtk_widget_set_margin_top (box, 4);
245     gtk_container_add (GTK_CONTAINER (dialog->revealer), box);
246     gtk_widget_show (dialog->revealer);
247 
248     dialog->filter_button = button = gtk_toggle_button_new ();
249     image = gtk_image_new_from_icon_name ("edit-find-symbolic", GTK_ICON_SIZE_BUTTON);
250     gtk_button_set_image (GTK_BUTTON (button), image);
251     gtk_header_bar_pack_end (GTK_HEADER_BAR (gtk_dialog_get_header_bar (GTK_DIALOG (dialog))), button);
252     gtk_widget_show (button);
253     g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (xfce_settings_manager_show_filter_toggled), dialog);
254     xfconf_g_property_bind (dialog->channel, "/last/filter-visible", G_TYPE_BOOLEAN, G_OBJECT (button), "active");
255 
256     dialog->filter_entry = entry = gtk_search_entry_new ();
257     gtk_box_pack_start (GTK_BOX (box), entry, TRUE, FALSE, 0);
258     gtk_widget_set_valign (entry, GTK_ALIGN_CENTER);
259     g_signal_connect (G_OBJECT (entry), "changed",
260         G_CALLBACK (xfce_settings_manager_dialog_entry_changed), dialog);
261     g_signal_connect (G_OBJECT (entry), "key-press-event",
262         G_CALLBACK (xfce_settings_manager_dialog_entry_key_press), dialog);
263     gtk_widget_show_all (box);
264 
265     dialog_vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
266 
267     gtk_box_pack_start (GTK_BOX (dialog_vbox), dialog->revealer, FALSE, TRUE, 0);
268 
269     dialog->category_scroll = scroll = gtk_scrolled_window_new (NULL, NULL);
270     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_ETCHED_IN);
271     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
272     gtk_box_pack_start (GTK_BOX (dialog_vbox), scroll, TRUE, TRUE, 0);
273     gtk_container_set_border_width (GTK_CONTAINER (scroll), 6);
274     gtk_widget_show (scroll);
275 
276     viewport = dialog->category_viewport = gtk_viewport_new (NULL, NULL);
277     gtk_container_add (GTK_CONTAINER (scroll), viewport);
278     gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE);
279     gtk_widget_show (viewport);
280 
281     dialog->category_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
282     gtk_container_add (GTK_CONTAINER (viewport), dialog->category_box);
283     gtk_container_set_border_width (GTK_CONTAINER (dialog->category_box), 6);
284     gtk_widget_show (dialog->category_box);
285     gtk_widget_set_size_request (dialog->category_box,
286                                  TEXT_WIDTH   /* text */
287                                  + ICON_WIDTH /* icon */
288                                  + (5 * 6)    /* borders */, -1);
289 
290     /* pluggable dialog scrolled window and viewport */
291     dialog->socket_scroll = scroll = gtk_scrolled_window_new (NULL, NULL);
292     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_NONE);
293     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
294     gtk_box_pack_start (GTK_BOX (dialog_vbox), scroll, TRUE, TRUE, 0);
295     gtk_container_set_border_width (GTK_CONTAINER (scroll), 0);
296 
297     dialog->socket_viewport = viewport = gtk_viewport_new (NULL, NULL);
298     gtk_container_add (GTK_CONTAINER (scroll), viewport);
299     gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE);
300     gtk_widget_show (viewport);
301 
302     dialog->css_provider = gtk_css_provider_new ();
303 
304     xfce_settings_manager_dialog_menu_reload (dialog);
305 
306     g_signal_connect_swapped (G_OBJECT (dialog->menu), "reload-required",
307         G_CALLBACK (xfce_settings_manager_dialog_menu_reload), dialog);
308 
309     g_signal_connect (G_OBJECT (dialog), "check-resize", G_CALLBACK (xfce_settings_manager_dialog_check_resize), dialog);
310 }
311 
312 
313 
314 static void
xfce_settings_manager_dialog_finalize(GObject * object)315 xfce_settings_manager_dialog_finalize (GObject *object)
316 {
317     XfceSettingsManagerDialog *dialog = XFCE_SETTINGS_MANAGER_DIALOG (object);
318 
319     g_free (dialog->help_page);
320     g_free (dialog->help_component);
321     g_free (dialog->help_version);
322 
323     g_free (dialog->filter_text);
324 
325     if (dialog->socket_item != NULL)
326         g_object_unref (G_OBJECT (dialog->socket_item));
327 
328     g_object_unref (G_OBJECT (dialog->menu));
329     g_object_unref (G_OBJECT (dialog->store));
330 
331     G_OBJECT_CLASS (xfce_settings_manager_dialog_parent_class)->finalize (object);
332 }
333 
334 
335 
336 static void
xfce_settings_manager_dialog_style_updated(GtkWidget * widget)337 xfce_settings_manager_dialog_style_updated (GtkWidget *widget)
338 {
339     XfceSettingsManagerDialog *dialog = XFCE_SETTINGS_MANAGER_DIALOG (widget);
340     GtkStyleContext *context;
341 
342     context = gtk_widget_get_style_context (dialog->category_viewport);
343     gtk_style_context_add_class (context, "view");
344     gtk_style_context_add_class (context, "exoiconview");
345     xfce_settings_manager_dialog_set_hover_style (dialog);
346 }
347 
348 
349 
350 static void
xfce_settings_manager_dialog_set_hover_style(XfceSettingsManagerDialog * dialog)351 xfce_settings_manager_dialog_set_hover_style (XfceSettingsManagerDialog *dialog)
352 {
353     GtkStyleContext *context;
354     GdkRGBA          color;
355     gchar           *css_string;
356     gchar           *color_text;
357     GdkScreen       *screen;
358 
359     context = gtk_widget_get_style_context (GTK_WIDGET (dialog));
360     /* Reset the provider to make sure we drop the previous Gtk theme style */
361     gtk_style_context_remove_provider (context,
362                                        GTK_STYLE_PROVIDER (dialog->css_provider));
363     /* Get the foreground color for the underline */
364     gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
365     color_text = gdk_rgba_to_string (&color);
366     /* Set a fake underline with box-shadow and use gtk to highlight the icon of the cell renderer */
367     css_string = g_strdup_printf (".exoiconview.view *:hover { -gtk-icon-effect: highlight; box-shadow: inset 0 -1px 1px %s;"
368                                   "                            border-left: 1px solid transparent; border-right: 1px solid transparent; }",
369                                   color_text);
370     gtk_css_provider_load_from_data (dialog->css_provider, css_string, -1, NULL);
371     screen = gdk_screen_get_default ();
372     /* As we don't have the individual ExoIconView widgets here, we set this provider for the whole screen.
373        This is fairly unproblematic as nobody uses the CSS class exiconview. */
374     gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (dialog->css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
375     g_free (css_string);
376     g_free (color_text);
377 }
378 
379 
380 
381 static void
xfce_settings_manager_dialog_response(GtkDialog * widget,gint response_id)382 xfce_settings_manager_dialog_response (GtkDialog *widget,
383                                        gint       response_id)
384 {
385     XfceSettingsManagerDialog *dialog = XFCE_SETTINGS_MANAGER_DIALOG (widget);
386     const gchar               *help_component;
387 
388     if (response_id == GTK_RESPONSE_NONE)
389         return;
390 
391     if (response_id == GTK_RESPONSE_HELP)
392     {
393         if (dialog->help_component != NULL)
394             help_component = dialog->help_component;
395         else
396             help_component = "xfce4-settings";
397 
398         xfce_dialog_show_help_with_version (GTK_WINDOW (widget),
399                                             help_component,
400                                             dialog->help_page,
401                                             NULL,
402                                             dialog->help_version);
403     }
404     else
405     {
406         GdkWindowState state;
407         gint           width, height;
408 
409         /* Don't save the state for full-screen windows */
410         state = gdk_window_get_state (gtk_widget_get_window(GTK_WIDGET(widget)));
411 
412         if ((state & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)) == 0)
413         {
414             /* Save window size */
415             gtk_window_get_size (GTK_WINDOW (widget), &width, &height);
416             xfconf_channel_set_int (dialog->channel, "/last/window-width", width),
417             xfconf_channel_set_int (dialog->channel, "/last/window-height", height);
418         }
419 
420         g_object_unref (dialog->css_provider);
421         gtk_widget_destroy (GTK_WIDGET (widget));
422         gtk_main_quit ();
423     }
424 }
425 
426 
427 
428 static void
xfce_settings_manager_dialog_set_title(XfceSettingsManagerDialog * dialog,const gchar * title,const gchar * icon_name)429 xfce_settings_manager_dialog_set_title (XfceSettingsManagerDialog *dialog,
430                                         const gchar               *title,
431                                         const gchar               *icon_name)
432 {
433     g_return_if_fail (XFCE_IS_SETTINGS_MANAGER_DIALOG (dialog));
434 
435     if (icon_name == NULL)
436         icon_name = "org.xfce.settings.manager";
437     if (title == NULL)
438         title = _("Settings");
439 
440     gtk_window_set_title (GTK_WINDOW (dialog), title);
441     gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
442 }
443 
444 
445 
446 static gint
xfce_settings_manager_dialog_iconview_find(gconstpointer a,gconstpointer b)447 xfce_settings_manager_dialog_iconview_find (gconstpointer a,
448                                             gconstpointer b)
449 {
450     const DialogCategory *category = a;
451 
452     return category->iconview == b ? 0 : 1;
453 }
454 
455 
456 
457 static gboolean
xfce_settings_manager_dialog_iconview_keynav_failed(ExoIconView * current_view,GtkDirectionType direction,XfceSettingsManagerDialog * dialog)458 xfce_settings_manager_dialog_iconview_keynav_failed (ExoIconView               *current_view,
459                                                      GtkDirectionType           direction,
460                                                      XfceSettingsManagerDialog *dialog)
461 {
462     GList          *li;
463     GtkTreePath    *path;
464     ExoIconView    *new_view;
465     gboolean        result = FALSE;
466     GtkTreeModel   *model;
467     GtkTreeIter     iter;
468     gint            col_old, col_new;
469     gint            dist_prev, dist_new;
470     GtkTreePath    *sel_path;
471     DialogCategory *category;
472 
473     if (direction == GTK_DIR_UP || direction == GTK_DIR_DOWN)
474     {
475         /* find this category in the list */
476         li = g_list_find_custom (dialog->categories, current_view,
477             xfce_settings_manager_dialog_iconview_find);
478 
479         /* find the next of previous visible item */
480         for (; li != NULL; )
481         {
482             if (direction == GTK_DIR_DOWN)
483                 li = g_list_next (li);
484             else
485                 li = g_list_previous (li);
486 
487             if (li != NULL)
488             {
489                 category = li->data;
490                 if (gtk_widget_get_visible (category->box))
491                     break;
492             }
493         }
494 
495         /* leave there is no view above or below this one */
496         if (li == NULL)
497             return FALSE;
498 
499         category = li->data;
500         new_view = EXO_ICON_VIEW (category->iconview);
501 
502         if (exo_icon_view_get_cursor (current_view, &path, NULL))
503         {
504             col_old = exo_icon_view_get_item_column (current_view, path);
505             gtk_tree_path_free (path);
506 
507             dist_prev = 1000;
508             sel_path = NULL;
509 
510             model = exo_icon_view_get_model (new_view);
511             if (gtk_tree_model_get_iter_first (model, &iter))
512             {
513                 do
514                 {
515                      path = gtk_tree_model_get_path (model, &iter);
516                      col_new = exo_icon_view_get_item_column (new_view, path);
517                      dist_new = ABS (col_new - col_old);
518 
519                      if ((direction == GTK_DIR_UP && dist_new <= dist_prev)
520                          || (direction == GTK_DIR_DOWN  && dist_new < dist_prev))
521                      {
522                          if (sel_path != NULL)
523                              gtk_tree_path_free (sel_path);
524 
525                          sel_path = path;
526                          dist_prev = dist_new;
527                      }
528                      else
529                      {
530                          gtk_tree_path_free (path);
531                      }
532                 }
533                 while (gtk_tree_model_iter_next (model, &iter));
534             }
535 
536             if (G_LIKELY (sel_path != NULL))
537             {
538                 /* move cursor, grab-focus will handle the selection */
539                 exo_icon_view_set_cursor (new_view, sel_path, NULL, FALSE);
540                 xfce_settings_manager_dialog_scroll_to_item (GTK_WIDGET (new_view), dialog);
541                 gtk_tree_path_free (sel_path);
542 
543                 gtk_widget_grab_focus (GTK_WIDGET (new_view));
544 
545                 result = TRUE;
546             }
547         }
548     }
549 
550     return result;
551 }
552 
553 
554 
555 static gboolean
xfce_settings_manager_dialog_query_tooltip(GtkWidget * iconview,gint x,gint y,gboolean keyboard_mode,GtkTooltip * tooltip,XfceSettingsManagerDialog * dialog)556 xfce_settings_manager_dialog_query_tooltip (GtkWidget                 *iconview,
557                                             gint                       x,
558                                             gint                       y,
559                                             gboolean                   keyboard_mode,
560                                             GtkTooltip                *tooltip,
561                                             XfceSettingsManagerDialog *dialog)
562 {
563     GtkTreePath    *path;
564     GValue          value = { 0, };
565     GtkTreeModel   *model;
566     GtkTreeIter     iter;
567     GarconMenuItem *item;
568     const gchar    *comment;
569 
570     if (keyboard_mode)
571     {
572         if (!exo_icon_view_get_cursor (EXO_ICON_VIEW (iconview), &path, NULL))
573             return FALSE;
574     }
575     else
576     {
577         path = exo_icon_view_get_path_at_pos (EXO_ICON_VIEW (iconview), x, y);
578         if (G_UNLIKELY (path == NULL))
579             return FALSE;
580     }
581 
582     model = exo_icon_view_get_model (EXO_ICON_VIEW (iconview));
583     if (gtk_tree_model_get_iter (model, &iter, path))
584     {
585         gtk_tree_model_get_value (model, &iter, COLUMN_MENU_ITEM, &value);
586         item = g_value_get_object (&value);
587         g_assert (GARCON_IS_MENU_ITEM (item));
588 
589         comment = garcon_menu_item_get_comment (item);
590         if (!exo_str_is_empty (comment))
591             gtk_tooltip_set_text (tooltip, comment);
592 
593         g_value_unset (&value);
594     }
595 
596     gtk_tree_path_free (path);
597 
598     return TRUE;
599 }
600 
601 
602 
603 static gboolean
xfce_settings_manager_dialog_iconview_focus(GtkWidget * iconview,GdkEventFocus * event,XfceSettingsManagerDialog * dialog)604 xfce_settings_manager_dialog_iconview_focus (GtkWidget                 *iconview,
605                                              GdkEventFocus             *event,
606                                              XfceSettingsManagerDialog *dialog)
607 {
608     GtkTreePath *path;
609 
610     if (event->in)
611     {
612         /* a mouse click will have focus, tab events not */
613         if (!exo_icon_view_get_cursor (EXO_ICON_VIEW (iconview), &path, NULL))
614         {
615            path = gtk_tree_path_new_from_indices (0, -1);
616            exo_icon_view_set_cursor (EXO_ICON_VIEW (iconview), path, NULL, FALSE);
617            xfce_settings_manager_dialog_scroll_to_item (iconview, dialog);
618         }
619 
620         exo_icon_view_select_path (EXO_ICON_VIEW (iconview), path);
621         gtk_tree_path_free (path);
622     }
623     else
624     {
625         exo_icon_view_unselect_all (EXO_ICON_VIEW (iconview));
626     }
627 
628     return FALSE;
629 }
630 
631 
632 
633 static void
xfce_settings_manager_dialog_remove_socket(XfceSettingsManagerDialog * dialog)634 xfce_settings_manager_dialog_remove_socket (XfceSettingsManagerDialog *dialog)
635 {
636     GtkWidget *socket;
637 
638     socket = gtk_bin_get_child (GTK_BIN (dialog->socket_viewport));
639     if (G_UNLIKELY (socket != NULL))
640         gtk_container_remove (GTK_CONTAINER (dialog->socket_viewport), socket);
641 
642     if (dialog->socket_item != NULL)
643     {
644         g_object_unref (G_OBJECT (dialog->socket_item));
645         dialog->socket_item = NULL;
646     }
647 }
648 
649 
650 
651 static void
xfce_settings_manager_dialog_go_back(XfceSettingsManagerDialog * dialog)652 xfce_settings_manager_dialog_go_back (XfceSettingsManagerDialog *dialog)
653 {
654     /* make sure no cursor is shown */
655     gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(dialog)), NULL);
656 
657     /* reset dialog info */
658     xfce_settings_manager_dialog_set_title (dialog, NULL, NULL);
659 
660     gtk_widget_show (dialog->category_scroll);
661     gtk_widget_hide (dialog->socket_scroll);
662 
663     g_free (dialog->help_page);
664     dialog->help_page = NULL;
665     g_free (dialog->help_component);
666     dialog->help_component = NULL;
667     g_free (dialog->help_version);
668     dialog->help_version = NULL;
669 
670     gtk_widget_set_sensitive (dialog->button_back, FALSE);
671     gtk_widget_set_sensitive (dialog->button_help, TRUE);
672 
673     gtk_widget_show (dialog->filter_button);
674     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->filter_button)))
675         gtk_widget_show (dialog->revealer);
676     gtk_entry_set_text (GTK_ENTRY (dialog->filter_entry), "");
677     gtk_widget_grab_focus (dialog->filter_entry);
678 
679     xfce_settings_manager_dialog_remove_socket (dialog);
680 }
681 
682 
683 
684 static void
xfce_settings_manager_dialog_entry_changed(GtkWidget * entry,XfceSettingsManagerDialog * dialog)685 xfce_settings_manager_dialog_entry_changed (GtkWidget                 *entry,
686                                             XfceSettingsManagerDialog *dialog)
687 {
688     const gchar    *text;
689     gchar          *normalized;
690     gchar          *filter_text;
691     GList          *li;
692     GtkTreeModel   *model;
693     gint            n_children;
694     DialogCategory *category;
695 
696     text = gtk_entry_get_text (GTK_ENTRY (entry));
697     if (text == NULL || *text == '\0')
698     {
699         filter_text = NULL;
700     }
701     else
702     {
703         /* create independent search string */
704         normalized = g_utf8_normalize (text, -1, G_NORMALIZE_DEFAULT);
705         filter_text = g_utf8_casefold (normalized, -1);
706         g_free (normalized);
707     }
708 
709     /* check if we need to update */
710     if (g_strcmp0 (dialog->filter_text, filter_text) != 0)
711     {
712         /* set new filter */
713         g_free (dialog->filter_text);
714         dialog->filter_text = filter_text;
715 
716         /* update the category models */
717         for (li = dialog->categories; li != NULL; li = li->next)
718         {
719             category = li->data;
720 
721             /* update model filters */
722             model = exo_icon_view_get_model (EXO_ICON_VIEW (category->iconview));
723             gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
724 
725             /* set visibility of the category */
726             n_children = gtk_tree_model_iter_n_children (model, NULL);
727             gtk_widget_set_visible (category->box, n_children > 0);
728         }
729 
730         g_idle_add (xfce_settings_manager_queue_resize_cb, dialog);
731     }
732     else
733     {
734         g_free (dialog->filter_text);
735         dialog->filter_text = NULL;
736         g_free (filter_text);
737     }
738 }
739 
740 
741 
742 static void
xfce_settings_manager_show_filter_toggled(GtkToggleButton * button,gpointer user_data)743 xfce_settings_manager_show_filter_toggled (GtkToggleButton *button,
744                                            gpointer         user_data)
745 {
746     XfceSettingsManagerDialog *dialog = XFCE_SETTINGS_MANAGER_DIALOG (user_data);
747     gboolean state;
748 
749     state = gtk_toggle_button_get_active (button);
750     gtk_widget_show (dialog->revealer);
751     gtk_revealer_set_reveal_child (GTK_REVEALER (dialog->revealer), state);
752     if (state && GTK_IS_WIDGET (dialog->filter_entry))
753         gtk_widget_grab_focus (dialog->filter_entry);
754 }
755 
756 
757 
758 static gboolean
xfce_settings_manager_dialog_entry_key_press(GtkWidget * entry,GdkEventKey * event,XfceSettingsManagerDialog * dialog)759 xfce_settings_manager_dialog_entry_key_press (GtkWidget                 *entry,
760                                               GdkEventKey               *event,
761                                               XfceSettingsManagerDialog *dialog)
762 {
763     GList          *li;
764     DialogCategory *category;
765     GtkTreePath    *path;
766     gint            n_visible_items;
767     GtkTreeModel   *model;
768     const gchar    *text;
769 
770     if (event->keyval == GDK_KEY_Escape)
771     {
772         text = gtk_entry_get_text (GTK_ENTRY (entry));
773         if (text != NULL && *text != '\0')
774         {
775             gtk_entry_set_text (GTK_ENTRY (entry), "");
776             return TRUE;
777         }
778     }
779     else if (event->keyval == GDK_KEY_Return)
780     {
781         /* count visible children */
782         n_visible_items = 0;
783         for (li = dialog->categories; li != NULL; li = li->next)
784         {
785             category = li->data;
786             if (gtk_widget_get_visible (category->box))
787             {
788                 model = exo_icon_view_get_model (EXO_ICON_VIEW (category->iconview));
789                 n_visible_items += gtk_tree_model_iter_n_children (model, NULL);
790 
791                 /* stop searching if there are more then 1 items */
792                 if (n_visible_items > 1)
793                     break;
794             }
795         }
796 
797         for (li = dialog->categories; li != NULL; li = li->next)
798         {
799             category = li->data;
800 
801             /* find the first visible category */
802             if (!gtk_widget_get_visible (category->box))
803                 continue;
804 
805             path = gtk_tree_path_new_first ();
806             if (n_visible_items == 1)
807             {
808                 /* activate this one item */
809                 exo_icon_view_item_activated (EXO_ICON_VIEW (category->iconview), path);
810             }
811             else
812             {
813                 /* select first item in view */
814                 exo_icon_view_set_cursor (EXO_ICON_VIEW (category->iconview),
815                                           path, NULL, FALSE);
816                 gtk_widget_grab_focus (category->iconview);
817             }
818             gtk_tree_path_free (path);
819             break;
820         }
821 
822         return TRUE;
823     }
824 
825     return FALSE;
826 }
827 
828 
829 
830 static void
xfce_settings_manager_dialog_plug_added(GtkWidget * socket,XfceSettingsManagerDialog * dialog)831 xfce_settings_manager_dialog_plug_added (GtkWidget                 *socket,
832                                          XfceSettingsManagerDialog *dialog)
833 {
834     /* set dialog information from desktop file */
835     xfce_settings_manager_dialog_set_title (dialog,
836         garcon_menu_item_get_name (dialog->socket_item),
837         garcon_menu_item_get_icon_name (dialog->socket_item));
838 
839     /* show socket and hide the categories view */
840     gtk_widget_show (dialog->socket_scroll);
841     gtk_widget_hide (dialog->category_scroll);
842 
843     /* button sensitivity */
844     gtk_widget_set_sensitive (dialog->button_back, TRUE);
845     gtk_widget_set_sensitive (dialog->button_help, dialog->help_page != NULL);
846     gtk_widget_hide (dialog->filter_button);
847     gtk_widget_hide (dialog->revealer);
848 
849     /* plug startup complete */
850     gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(dialog)), NULL);
851 }
852 
853 
854 
855 static void
xfce_settings_manager_dialog_plug_removed(GtkWidget * socket,XfceSettingsManagerDialog * dialog)856 xfce_settings_manager_dialog_plug_removed (GtkWidget                 *socket,
857                                            XfceSettingsManagerDialog *dialog)
858 {
859     /* this shouldn't happen */
860     g_critical ("pluggable dialog \"%s\" crashed",
861                 garcon_menu_item_get_command (dialog->socket_item));
862 
863     /* restore dialog */
864     xfce_settings_manager_dialog_go_back (dialog);
865 }
866 
867 
868 
869 static void
xfce_settings_manager_dialog_spawn(XfceSettingsManagerDialog * dialog,GarconMenuItem * item)870 xfce_settings_manager_dialog_spawn (XfceSettingsManagerDialog *dialog,
871                                     GarconMenuItem            *item)
872 {
873     gchar          *command;
874     gboolean        snotify;
875     GdkScreen      *screen;
876     GdkDisplay     *display;
877     GError         *error = NULL;
878     GFile          *desktop_file;
879     gchar          *filename;
880     XfceRc         *rc;
881     gboolean        pluggable = FALSE;
882     gchar          *cmd;
883     gchar          *uri;
884     GtkWidget      *socket;
885     GdkCursor      *cursor;
886 
887     g_return_if_fail (GARCON_IS_MENU_ITEM (item));
888 
889     screen = gtk_window_get_screen (GTK_WINDOW (dialog));
890 
891     /* expand the field codes */
892     uri = garcon_menu_item_get_uri (item);
893     command = xfce_expand_desktop_entry_field_codes (garcon_menu_item_get_command (item),
894                                                      NULL,
895                                                      garcon_menu_item_get_icon_name (item),
896                                                      garcon_menu_item_get_name (item),
897                                                      uri, FALSE);
898     g_free (uri);
899 
900     /* we need to read some more info from the desktop
901      *  file that is not supported by garcon */
902     desktop_file = garcon_menu_item_get_file (item);
903     filename = g_file_get_path (desktop_file);
904     g_object_unref (desktop_file);
905 
906     rc = xfce_rc_simple_open (filename, TRUE);
907     g_free (filename);
908     if (G_LIKELY (rc != NULL))
909     {
910         pluggable = xfce_rc_read_bool_entry (rc, "X-XfcePluggable", FALSE);
911         if (pluggable)
912         {
913             dialog->help_page = g_strdup (xfce_rc_read_entry (rc, "X-XfceHelpPage", NULL));
914             dialog->help_component = g_strdup (xfce_rc_read_entry (rc, "X-XfceHelpComponent", NULL));
915             dialog->help_version = g_strdup (xfce_rc_read_entry (rc, "X-XfceHelpVersion", NULL));
916         }
917 
918         xfce_rc_close (rc);
919     }
920 
921     if (pluggable)
922     {
923         /* fake startup notification */
924         display = gdk_display_get_default ();
925         cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
926         gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(dialog)), cursor);
927         g_object_unref (cursor);
928 
929         xfce_settings_manager_dialog_remove_socket (dialog);
930 
931         /* create fresh socket */
932         socket = gtk_socket_new ();
933         gtk_container_add (GTK_CONTAINER (dialog->socket_viewport), socket);
934         g_signal_connect (G_OBJECT (socket), "plug-added",
935             G_CALLBACK (xfce_settings_manager_dialog_plug_added), dialog);
936         g_signal_connect (G_OBJECT (socket), "plug-removed",
937             G_CALLBACK (xfce_settings_manager_dialog_plug_removed), dialog);
938         gtk_widget_show (socket);
939 
940         /* for info when the plug is attached */
941         dialog->socket_item = g_object_ref (item);
942 
943         /* spawn dialog with socket argument */
944         cmd = g_strdup_printf ("%s --socket-id=%d", command, (gint)gtk_socket_get_id (GTK_SOCKET (socket)));
945         if (!xfce_spawn_command_line_on_screen (screen, cmd, FALSE, FALSE, &error))
946         {
947             gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(dialog)), NULL);
948 
949             xfce_dialog_show_error (GTK_WINDOW (dialog), error,
950                                     _("Unable to start \"%s\""), command);
951             g_error_free (error);
952         }
953         g_free (cmd);
954     }
955     else
956     {
957         snotify = garcon_menu_item_supports_startup_notification (item);
958         if (!xfce_spawn_command_line_on_screen (screen, command, FALSE, snotify, &error))
959         {
960             xfce_dialog_show_error (GTK_WINDOW (dialog), error,
961                                     _("Unable to start \"%s\""), command);
962             g_error_free (error);
963         }
964     }
965 
966   g_free (command);
967 }
968 
969 
970 
971 static void
xfce_settings_manager_dialog_item_activated(ExoIconView * iconview,GtkTreePath * path,XfceSettingsManagerDialog * dialog)972 xfce_settings_manager_dialog_item_activated (ExoIconView               *iconview,
973                                              GtkTreePath               *path,
974                                              XfceSettingsManagerDialog *dialog)
975 {
976     GtkTreeModel   *model;
977     GtkTreeIter     iter;
978     GarconMenuItem *item;
979 
980     model = exo_icon_view_get_model (iconview);
981     if (gtk_tree_model_get_iter (model, &iter, path))
982     {
983         gtk_tree_model_get (model, &iter, COLUMN_MENU_ITEM, &item, -1);
984         g_assert (GARCON_IS_MENU_ITEM (item));
985 
986         xfce_settings_manager_dialog_spawn (dialog, item);
987 
988         g_object_unref (G_OBJECT (item));
989     }
990 }
991 
992 
993 
994 static gboolean
xfce_settings_manager_dialog_filter_category(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)995 xfce_settings_manager_dialog_filter_category (GtkTreeModel *model,
996                                               GtkTreeIter  *iter,
997                                               gpointer      data)
998 {
999     GValue          cat_val = { 0, };
1000     GValue          filter_val = { 0, };
1001     gboolean        visible;
1002     DialogCategory *category = data;
1003     const gchar    *filter_text;
1004 
1005     /* filter only the active category */
1006     gtk_tree_model_get_value (model, iter, COLUMN_MENU_DIRECTORY, &cat_val);
1007     visible = g_value_get_object (&cat_val) == G_OBJECT (category->directory);
1008     g_value_unset (&cat_val);
1009 
1010     /* filter search string */
1011     if (visible && category->dialog->filter_text != NULL)
1012     {
1013         gtk_tree_model_get_value (model, iter, COLUMN_FILTER_TEXT, &filter_val);
1014         filter_text = g_value_get_string (&filter_val);
1015         visible = strstr (filter_text, category->dialog->filter_text) != NULL;
1016         g_value_unset (&filter_val);
1017     }
1018 
1019     return visible;
1020 }
1021 
1022 
1023 
1024 static void
xfce_settings_manager_dialog_scroll_to_item(GtkWidget * iconview,XfceSettingsManagerDialog * dialog)1025 xfce_settings_manager_dialog_scroll_to_item (GtkWidget                 *iconview,
1026                                              XfceSettingsManagerDialog *dialog)
1027 {
1028     GtkAllocation *alloc = g_new0 (GtkAllocation, 1);
1029     GtkTreePath   *path;
1030     gint           row, row_height;
1031     gdouble        rows;
1032     GtkAdjustment *adjustment;
1033     gdouble        lower, upper;
1034 
1035     if (exo_icon_view_get_cursor (EXO_ICON_VIEW (iconview), &path, NULL))
1036     {
1037         /* get item row */
1038         row = exo_icon_view_get_item_row (EXO_ICON_VIEW (iconview), path);
1039         gtk_tree_path_free (path);
1040 
1041         /* estimated row height */
1042         gtk_widget_get_allocation(GTK_WIDGET(iconview), alloc);
1043         rows = alloc->height / 56;
1044         row_height = alloc->height / MAX (1.0, (gint) rows);
1045 
1046         /* selected item boundries */
1047         lower = alloc->y + row_height * row;
1048         upper = alloc->y + row_height * (row + 1);
1049 
1050         /* scroll so item is visible */
1051         adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (dialog->category_viewport));
1052         gtk_adjustment_clamp_page (adjustment, lower, upper);
1053     }
1054 
1055     g_free (alloc);
1056 }
1057 
1058 
1059 
1060 static gboolean
xfce_settings_manager_dialog_key_press_event(GtkWidget * iconview,GdkEventKey * event,XfceSettingsManagerDialog * dialog)1061 xfce_settings_manager_dialog_key_press_event (GtkWidget                 *iconview,
1062                                               GdkEventKey               *event,
1063                                               XfceSettingsManagerDialog *dialog)
1064 {
1065     gboolean result;
1066 
1067     /* let exo handle the selection first */
1068     result = GTK_WIDGET_CLASS (G_OBJECT_GET_CLASS (iconview))->key_press_event (iconview, event);
1069 
1070     /* make sure the selected item is visible */
1071     if (result)
1072         xfce_settings_manager_dialog_scroll_to_item (iconview, dialog);
1073 
1074     return result;
1075 }
1076 
1077 
1078 
1079 static gboolean
xfce_settings_manager_start_search(GtkWidget * iconview,XfceSettingsManagerDialog * dialog)1080 xfce_settings_manager_start_search (GtkWidget                 *iconview,
1081                                     XfceSettingsManagerDialog *dialog)
1082 {
1083     gtk_widget_grab_focus (dialog->filter_entry);
1084     return TRUE;
1085 }
1086 
1087 
1088 
1089 static void
xfce_settings_manager_dialog_category_free(gpointer data)1090 xfce_settings_manager_dialog_category_free (gpointer data)
1091 {
1092     DialogCategory            *category = data;
1093     XfceSettingsManagerDialog *dialog = category->dialog;
1094 
1095     dialog->categories = g_list_remove (dialog->categories, category);
1096 
1097     g_object_unref (G_OBJECT (category->directory));
1098     g_slice_free (DialogCategory, category);
1099 }
1100 
1101 
1102 
1103 static void
xfce_settings_manager_dialog_add_category(XfceSettingsManagerDialog * dialog,GarconMenuDirectory * directory)1104 xfce_settings_manager_dialog_add_category (XfceSettingsManagerDialog *dialog,
1105                                            GarconMenuDirectory       *directory)
1106 {
1107     GtkTreeModel    *filter;
1108     GtkWidget       *iconview;
1109     GtkWidget       *label;
1110     GtkWidget       *separator;
1111     GtkWidget       *vbox;
1112     PangoAttrList   *attrs;
1113     GtkCellRenderer *render;
1114     DialogCategory  *category;
1115 
1116     category = g_slice_new0 (DialogCategory);
1117     category->directory = (GarconMenuDirectory *) g_object_ref (G_OBJECT (directory));
1118     category->dialog = dialog;
1119 
1120     /* filter category from main store */
1121     filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (dialog->store), NULL);
1122     gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
1123         xfce_settings_manager_dialog_filter_category,
1124         category, xfce_settings_manager_dialog_category_free);
1125 
1126     category->box = vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1127     gtk_box_pack_start (GTK_BOX (dialog->category_box), vbox, FALSE, TRUE, 0);
1128     gtk_widget_show (vbox);
1129 
1130     /* create a label for the category title */
1131     label = gtk_label_new (garcon_menu_directory_get_name (directory));
1132     attrs = pango_attr_list_new ();
1133     pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
1134     gtk_label_set_attributes (GTK_LABEL (label), attrs);
1135     pango_attr_list_unref (attrs);
1136     gtk_widget_set_halign (label, GTK_ALIGN_START);
1137     gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
1138     gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
1139     gtk_widget_show (label);
1140 
1141     /* separate title and content using a horizontal line */
1142     separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
1143     gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, TRUE, 0);
1144     gtk_widget_show (separator);
1145 
1146     category->iconview = iconview = exo_icon_view_new_with_model (GTK_TREE_MODEL (filter));
1147     gtk_container_add (GTK_CONTAINER (vbox), iconview);
1148     exo_icon_view_set_orientation (EXO_ICON_VIEW (iconview), GTK_ORIENTATION_HORIZONTAL);
1149     exo_icon_view_set_margin (EXO_ICON_VIEW (iconview), 0);
1150     exo_icon_view_set_single_click (EXO_ICON_VIEW (iconview), TRUE);
1151     exo_icon_view_set_enable_search (EXO_ICON_VIEW (iconview), FALSE);
1152     exo_icon_view_set_item_width (EXO_ICON_VIEW (iconview), TEXT_WIDTH + ICON_WIDTH);
1153     xfce_settings_manager_dialog_set_hover_style (dialog);
1154     gtk_widget_show (iconview);
1155 
1156     /* list used for unselecting */
1157     dialog->categories = g_list_append (dialog->categories, category);
1158 
1159     gtk_widget_set_has_tooltip (iconview, TRUE);
1160     g_signal_connect (G_OBJECT (iconview), "query-tooltip",
1161         G_CALLBACK (xfce_settings_manager_dialog_query_tooltip), dialog);
1162     g_signal_connect (G_OBJECT (iconview), "focus-in-event",
1163         G_CALLBACK (xfce_settings_manager_dialog_iconview_focus), dialog);
1164     g_signal_connect (G_OBJECT (iconview), "focus-out-event",
1165         G_CALLBACK (xfce_settings_manager_dialog_iconview_focus), dialog);
1166     g_signal_connect (G_OBJECT (iconview), "keynav-failed",
1167         G_CALLBACK (xfce_settings_manager_dialog_iconview_keynav_failed), dialog);
1168     g_signal_connect (G_OBJECT (iconview), "item-activated",
1169         G_CALLBACK (xfce_settings_manager_dialog_item_activated), dialog);
1170     g_signal_connect (G_OBJECT (iconview), "key-press-event",
1171         G_CALLBACK (xfce_settings_manager_dialog_key_press_event), dialog);
1172     g_signal_connect (G_OBJECT (iconview), "start-interactive-search",
1173         G_CALLBACK (xfce_settings_manager_start_search), dialog);
1174 
1175     render = gtk_cell_renderer_pixbuf_new ();
1176     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (iconview), render, FALSE);
1177     gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (iconview), render, "icon-name", COLUMN_ICON_NAME);
1178     g_object_set (G_OBJECT (render),
1179                   "stock-size", GTK_ICON_SIZE_DIALOG,
1180                   "follow-state", TRUE,
1181                   NULL);
1182 
1183     render = gtk_cell_renderer_text_new ();
1184     gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (iconview), render, FALSE);
1185     gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (iconview), render, "text", COLUMN_NAME);
1186     g_object_set (G_OBJECT (render),
1187                   "wrap-mode", PANGO_WRAP_WORD,
1188                   "wrap-width", TEXT_WIDTH,
1189                   NULL);
1190 
1191     g_object_unref (G_OBJECT (filter));
1192 }
1193 
1194 
1195 
1196 static void
xfce_settings_manager_dialog_menu_collect(GarconMenu * menu,GList ** items)1197 xfce_settings_manager_dialog_menu_collect (GarconMenu  *menu,
1198                                            GList      **items)
1199 {
1200     GList *elements, *li;
1201 
1202     g_return_if_fail (GARCON_IS_MENU (menu));
1203 
1204     elements = garcon_menu_get_elements (menu);
1205 
1206     for (li = elements; li != NULL; li = li->next)
1207     {
1208         if (GARCON_IS_MENU_ITEM (li->data))
1209         {
1210             /* only add visible items */
1211             if (garcon_menu_element_get_visible (li->data))
1212                 *items = g_list_prepend (*items, li->data);
1213         }
1214         else if (GARCON_IS_MENU (li->data))
1215         {
1216             /* we collect only 1 level deep in a category, so
1217              * add the submenu items too (should never happen tho) */
1218             xfce_settings_manager_dialog_menu_collect (li->data, items);
1219         }
1220     }
1221 
1222     g_list_free (elements);
1223 }
1224 
1225 
1226 
1227 static gint
xfce_settings_manager_dialog_menu_sort(gconstpointer a,gconstpointer b)1228 xfce_settings_manager_dialog_menu_sort (gconstpointer a,
1229                                         gconstpointer b)
1230 {
1231     return g_utf8_collate (garcon_menu_item_get_name (GARCON_MENU_ITEM (a)),
1232                            garcon_menu_item_get_name (GARCON_MENU_ITEM (b)));
1233 }
1234 
1235 
1236 
1237 static void
xfce_settings_manager_dialog_menu_reload(XfceSettingsManagerDialog * dialog)1238 xfce_settings_manager_dialog_menu_reload (XfceSettingsManagerDialog *dialog)
1239 {
1240     GError              *error = NULL;
1241     GList               *elements, *li;
1242     GList               *lnext;
1243     GarconMenuDirectory *directory;
1244     GList               *items, *lp;
1245     GList               *keywords, *kli;
1246     gint                 i = 0;
1247     gchar               *item_text;
1248     gchar               *normalized;
1249     gchar               *filter_text;
1250     GString             *item_keywords;
1251     DialogCategory      *category;
1252 
1253     g_return_if_fail (XFCE_IS_SETTINGS_MANAGER_DIALOG (dialog));
1254     g_return_if_fail (GARCON_IS_MENU (dialog->menu));
1255 
1256     if (dialog->categories != NULL)
1257     {
1258         for (li = dialog->categories; li != NULL; li = lnext)
1259         {
1260             lnext = li->next;
1261             category = li->data;
1262 
1263             gtk_widget_destroy (category->box);
1264         }
1265 
1266         g_assert (dialog->categories == NULL);
1267 
1268         gtk_list_store_clear (GTK_LIST_STORE (dialog->store));
1269     }
1270 
1271     if (garcon_menu_load (dialog->menu, NULL, &error))
1272     {
1273         /* get all menu elements (preserve layout) */
1274         elements = garcon_menu_get_elements (dialog->menu);
1275         for (li = elements; li != NULL; li = li->next)
1276         {
1277             /* only accept toplevel menus */
1278             if (!GARCON_IS_MENU (li->data))
1279                 continue;
1280 
1281             directory = garcon_menu_get_directory (li->data);
1282             if (G_UNLIKELY (directory == NULL))
1283                 continue;
1284 
1285             items = NULL;
1286 
1287             xfce_settings_manager_dialog_menu_collect (li->data, &items);
1288 
1289             /* add the new category if it has visible items */
1290             if (G_LIKELY (items != NULL))
1291             {
1292                 /* insert new items in main store */
1293                 items = g_list_sort (items, xfce_settings_manager_dialog_menu_sort);
1294                 for (lp = items; lp != NULL; lp = lp->next)
1295                 {
1296                     /* create independent search string based on name, comment and keywords */
1297                     keywords = garcon_menu_item_get_keywords (lp->data);
1298                     item_keywords = g_string_new (NULL);
1299                     for (kli = keywords; kli != NULL; kli = kli->next)
1300                     {
1301                         g_string_append (item_keywords, kli->data);
1302                     }
1303                     item_text = g_strdup_printf ("%s\n%s\n%s",
1304                         garcon_menu_item_get_name (lp->data),
1305                         garcon_menu_item_get_comment (lp->data),
1306                         item_keywords->str);
1307                     g_string_free (item_keywords, TRUE);
1308                     g_list_free (kli);
1309                     normalized = g_utf8_normalize (item_text, -1, G_NORMALIZE_DEFAULT);
1310                     g_free (item_text);
1311                     filter_text = g_utf8_casefold (normalized, -1);
1312                     g_free (normalized);
1313 
1314                     gtk_list_store_insert_with_values (dialog->store, NULL, i++,
1315                         COLUMN_NAME, garcon_menu_item_get_name (lp->data),
1316                         COLUMN_ICON_NAME, garcon_menu_item_get_icon_name (lp->data),
1317                         COLUMN_TOOLTIP, garcon_menu_item_get_comment (lp->data),
1318                         COLUMN_MENU_ITEM, lp->data,
1319                         COLUMN_MENU_DIRECTORY, directory,
1320                         COLUMN_FILTER_TEXT, filter_text, -1);
1321 
1322                     g_free (filter_text);
1323                 }
1324                 g_list_free (items);
1325 
1326                 /* add the new category to the box */
1327                 xfce_settings_manager_dialog_add_category (dialog, directory);
1328             }
1329         }
1330 
1331         g_list_free (elements);
1332     }
1333     else
1334     {
1335         g_critical ("Failed to load menu: %s", error->message);
1336         g_error_free (error);
1337     }
1338 
1339     g_idle_add (xfce_settings_manager_queue_resize_cb, dialog);
1340 }
1341 
1342 
1343 GtkWidget *
xfce_settings_manager_dialog_new(void)1344 xfce_settings_manager_dialog_new (void)
1345 {
1346     return g_object_new (XFCE_TYPE_SETTINGS_MANAGER_DIALOG, NULL);
1347 }
1348 
1349 
1350 
1351 gboolean
xfce_settings_manager_dialog_show_dialog(XfceSettingsManagerDialog * dialog,const gchar * dialog_name)1352 xfce_settings_manager_dialog_show_dialog (XfceSettingsManagerDialog *dialog,
1353                                           const gchar               *dialog_name)
1354 {
1355     GtkTreeModel   *model = GTK_TREE_MODEL (dialog->store);
1356     GtkTreeIter     iter;
1357     GarconMenuItem *item;
1358     const gchar    *desktop_id;
1359     gchar          *name;
1360     gboolean        found = FALSE;
1361 
1362     g_return_val_if_fail (XFCE_IS_SETTINGS_MANAGER_DIALOG (dialog), FALSE);
1363 
1364     name = g_strdup_printf ("%s.desktop", dialog_name);
1365 
1366     if (gtk_tree_model_get_iter_first (model, &iter))
1367     {
1368         do
1369         {
1370              gtk_tree_model_get (model, &iter, COLUMN_MENU_ITEM, &item, -1);
1371              g_assert (GARCON_IS_MENU_ITEM (item));
1372 
1373              desktop_id = garcon_menu_item_get_desktop_id (item);
1374              if (g_strcmp0 (desktop_id, name) == 0)
1375              {
1376                   xfce_settings_manager_dialog_spawn (dialog, item);
1377                   found = TRUE;
1378              }
1379 
1380              g_object_unref (G_OBJECT (item));
1381         }
1382         while (!found && gtk_tree_model_iter_next (model, &iter));
1383     }
1384 
1385     g_free (name);
1386 
1387     return found;
1388 }
1389