1 /*
2  * Copyright (C) 2010 Nick Schermer <nick@xfce.org>
3  *
4  * This library is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the Free
6  * Software Foundation; either version 2 of the License, or (at your option)
7  * any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 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 #include <exo/exo.h>
24 #include <garcon/garcon.h>
25 #include <garcon-gtk/garcon-gtk.h>
26 #include <libxfce4ui/libxfce4ui.h>
27 #include <libxfce4util/libxfce4util.h>
28 #include <libxfce4panel/libxfce4panel.h>
29 #include <common/panel-xfconf.h>
30 #include <common/panel-utils.h>
31 #include <common/panel-private.h>
32 #include <common/panel-debug.h>
33 
34 #include "applicationsmenu.h"
35 #include "applicationsmenu-dialog_ui.h"
36 
37 
38 /* I18N: default tooltip of the application menu */
39 #define DEFAULT_TITLE     _("Applications")
40 #define DEFAULT_ICON_NAME "org.xfce.panel.applicationsmenu"
41 #define DEFAULT_ICON_SIZE (16)
42 #define DEFAULT_EDITOR    "menulibre"
43 
44 
45 struct _ApplicationsMenuPluginClass
46 {
47   XfcePanelPluginClass __parent__;
48 };
49 
50 struct _ApplicationsMenuPlugin
51 {
52   XfcePanelPlugin __parent__;
53 
54   GtkWidget       *button;
55   GtkWidget       *box;
56   GtkWidget       *icon;
57   GtkWidget       *label;
58   GtkWidget       *menu;
59 
60   guint            is_constructed : 1;
61 
62   guint            show_button_title : 1;
63   gchar           *button_title;
64   gchar           *button_icon;
65   gboolean         custom_menu;
66   gchar           *custom_menu_file;
67   gchar           *menu_editor;
68 
69   /* temp item we store here when the
70    * properties dialog is opened */
71   GtkWidget       *dialog_icon;
72 
73   gulong           style_set_id;
74   gulong           screen_changed_id;
75   gulong           theme_changed_id;
76 };
77 
78 enum
79 {
80   PROP_0,
81   PROP_SHOW_GENERIC_NAMES,
82   PROP_SHOW_MENU_ICONS,
83   PROP_SHOW_TOOLTIPS,
84   PROP_SHOW_BUTTON_TITLE,
85   PROP_BUTTON_TITLE,
86   PROP_BUTTON_ICON,
87   PROP_CUSTOM_MENU,
88   PROP_CUSTOM_MENU_FILE,
89   PROP_MENU_EDITOR
90 };
91 
92 
93 
94 static void      applications_menu_plugin_get_property         (GObject                *object,
95                                                                 guint                   prop_id,
96                                                                 GValue                 *value,
97                                                                 GParamSpec             *pspec);
98 static void      applications_menu_plugin_set_property         (GObject                *object,
99                                                                 guint                   prop_id,
100                                                                 const GValue           *value,
101                                                                 GParamSpec             *pspec);
102 static void      applications_menu_plugin_construct            (XfcePanelPlugin        *panel_plugin);
103 static void      applications_menu_plugin_free_data            (XfcePanelPlugin        *panel_plugin);
104 static gboolean  applications_menu_plugin_size_changed         (XfcePanelPlugin        *panel_plugin,
105                                                                 gint                    size);
106 static void      applications_menu_plugin_mode_changed         (XfcePanelPlugin        *panel_plugin,
107                                                                 XfcePanelPluginMode     mode);
108 static void      applications_menu_plugin_configure_plugin     (XfcePanelPlugin        *panel_plugin);
109 static gboolean  applications_menu_plugin_remote_event         (XfcePanelPlugin        *panel_plugin,
110                                                                 const gchar            *name,
111                                                                 const GValue           *value);
112 static gboolean  applications_menu_plugin_menu                 (GtkWidget              *button,
113                                                                 GdkEventButton         *event,
114                                                                 ApplicationsMenuPlugin *plugin);
115 static void      applications_menu_plugin_menu_deactivate      (GtkWidget              *menu,
116                                                                 ApplicationsMenuPlugin *plugin);
117 static void      applications_menu_plugin_set_garcon_menu      (ApplicationsMenuPlugin *plugin);
118 static void      applications_menu_button_theme_changed        (ApplicationsMenuPlugin *plugin);
119 
120 
121 
122 /* define the plugin */
XFCE_PANEL_DEFINE_PLUGIN(ApplicationsMenuPlugin,applications_menu_plugin)123 XFCE_PANEL_DEFINE_PLUGIN (ApplicationsMenuPlugin, applications_menu_plugin)
124 
125 
126 
127 static void
128 applications_menu_plugin_class_init (ApplicationsMenuPluginClass *klass)
129 {
130   XfcePanelPluginClass *plugin_class;
131   GObjectClass         *gobject_class;
132 
133   gobject_class = G_OBJECT_CLASS (klass);
134   gobject_class->get_property = applications_menu_plugin_get_property;
135   gobject_class->set_property = applications_menu_plugin_set_property;
136 
137   plugin_class = XFCE_PANEL_PLUGIN_CLASS (klass);
138   plugin_class->construct = applications_menu_plugin_construct;
139   plugin_class->free_data = applications_menu_plugin_free_data;
140   plugin_class->size_changed = applications_menu_plugin_size_changed;
141   plugin_class->mode_changed = applications_menu_plugin_mode_changed;
142   plugin_class->configure_plugin = applications_menu_plugin_configure_plugin;
143   plugin_class->remote_event = applications_menu_plugin_remote_event;
144 
145   g_object_class_install_property (gobject_class,
146                                    PROP_SHOW_GENERIC_NAMES,
147                                    g_param_spec_boolean ("show-generic-names",
148                                                          NULL, NULL,
149                                                          FALSE,
150                                                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
151 
152   g_object_class_install_property (gobject_class,
153                                    PROP_SHOW_MENU_ICONS,
154                                    g_param_spec_boolean ("show-menu-icons",
155                                                          NULL, NULL,
156                                                          TRUE,
157                                                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
158   g_object_class_install_property (gobject_class,
159                                    PROP_SHOW_TOOLTIPS,
160                                    g_param_spec_boolean ("show-tooltips",
161                                                          NULL, NULL,
162                                                          FALSE,
163                                                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
164 
165   g_object_class_install_property (gobject_class,
166                                    PROP_SHOW_BUTTON_TITLE,
167                                    g_param_spec_boolean ("show-button-title",
168                                                          NULL, NULL,
169                                                          TRUE,
170                                                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
171 
172   g_object_class_install_property (gobject_class,
173                                    PROP_BUTTON_TITLE,
174                                    g_param_spec_string ("button-title",
175                                                         NULL, NULL,
176                                                         DEFAULT_TITLE,
177                                                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
178 
179   g_object_class_install_property (gobject_class,
180                                    PROP_BUTTON_ICON,
181                                    g_param_spec_string ("button-icon",
182                                                         NULL, NULL,
183                                                         DEFAULT_ICON_NAME,
184                                                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
185 
186   g_object_class_install_property (gobject_class,
187                                    PROP_CUSTOM_MENU,
188                                    g_param_spec_boolean ("custom-menu",
189                                                          NULL, NULL,
190                                                          FALSE,
191                                                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
192 
193   g_object_class_install_property (gobject_class,
194                                    PROP_CUSTOM_MENU_FILE,
195                                    g_param_spec_string ("custom-menu-file",
196                                                         NULL, NULL,
197                                                         NULL,
198                                                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
199 
200   g_object_class_install_property (gobject_class,
201                                    PROP_MENU_EDITOR,
202                                    g_param_spec_string ("menu-editor",
203                                                         NULL, NULL,
204                                                         DEFAULT_EDITOR,
205                                                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
206 }
207 
208 
209 
210 static void
applications_menu_plugin_init(ApplicationsMenuPlugin * plugin)211 applications_menu_plugin_init (ApplicationsMenuPlugin *plugin)
212 {
213   GtkIconTheme *icon_theme;
214 
215   /* init garcon environment */
216   garcon_set_environment_xdg (GARCON_ENVIRONMENT_XFCE);
217 
218   icon_theme = gtk_icon_theme_get_default ();
219 
220   plugin->button = xfce_panel_create_toggle_button ();
221   xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->button);
222   gtk_container_add (GTK_CONTAINER (plugin), plugin->button);
223   gtk_widget_set_name (plugin->button, "applicationmenu-button");
224   gtk_button_set_relief (GTK_BUTTON (plugin->button), GTK_RELIEF_NONE);
225   gtk_widget_set_tooltip_text (plugin->button, DEFAULT_TITLE);
226   g_signal_connect (G_OBJECT (plugin->button), "button-press-event",
227       G_CALLBACK (applications_menu_plugin_menu), plugin);
228 
229   plugin->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
230   gtk_container_set_border_width (GTK_CONTAINER (plugin->box), 0);
231   gtk_container_add (GTK_CONTAINER (plugin->button), plugin->box);
232   gtk_widget_show (plugin->box);
233 
234   plugin->icon = gtk_image_new_from_icon_name (DEFAULT_ICON_NAME, DEFAULT_ICON_SIZE);
235   gtk_box_pack_start (GTK_BOX (plugin->box), plugin->icon, FALSE, FALSE, 0);
236   gtk_widget_show (plugin->icon);
237 
238   plugin->label = gtk_label_new (DEFAULT_TITLE);
239   gtk_box_pack_start (GTK_BOX (plugin->box), plugin->label, FALSE, FALSE, 0);
240   plugin->show_button_title = TRUE;
241   gtk_widget_show (plugin->label);
242 
243   /* prepare the menu */
244   plugin->menu = garcon_gtk_menu_new (NULL);
245   g_signal_connect (G_OBJECT (plugin->menu), "selection-done",
246       G_CALLBACK (applications_menu_plugin_menu_deactivate), plugin);
247 
248   plugin->style_set_id = g_signal_connect_swapped (G_OBJECT (plugin->button), "style-set",
249                                                    G_CALLBACK (applications_menu_button_theme_changed), plugin);
250   plugin->screen_changed_id = g_signal_connect_swapped (G_OBJECT (plugin->button), "screen-changed",
251                                                         G_CALLBACK (applications_menu_button_theme_changed), plugin);
252   plugin->theme_changed_id = g_signal_connect_swapped (G_OBJECT (icon_theme), "changed",
253                                                        G_CALLBACK (applications_menu_plugin_set_garcon_menu), plugin);
254 }
255 
256 
257 
258 static void
applications_menu_plugin_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)259 applications_menu_plugin_get_property (GObject    *object,
260                                        guint       prop_id,
261                                        GValue     *value,
262                                        GParamSpec *pspec)
263 {
264   ApplicationsMenuPlugin *plugin = XFCE_APPLICATIONS_MENU_PLUGIN (object);
265 
266   switch (prop_id)
267     {
268     case PROP_SHOW_GENERIC_NAMES:
269       g_value_set_boolean (value,
270           garcon_gtk_menu_get_show_generic_names (GARCON_GTK_MENU (plugin->menu)));
271       break;
272 
273     case PROP_SHOW_MENU_ICONS:
274       g_value_set_boolean (value,
275           garcon_gtk_menu_get_show_menu_icons (GARCON_GTK_MENU (plugin->menu)));
276       break;
277 
278     case PROP_SHOW_TOOLTIPS:
279       g_value_set_boolean (value,
280           garcon_gtk_menu_get_show_tooltips (GARCON_GTK_MENU (plugin->menu)));
281       break;
282 
283     case PROP_SHOW_BUTTON_TITLE:
284       g_value_set_boolean (value, plugin->show_button_title);
285       break;
286 
287     case PROP_BUTTON_TITLE:
288       g_value_set_string (value, plugin->button_title == NULL ?
289           DEFAULT_TITLE : plugin->button_title);
290       break;
291 
292     case PROP_BUTTON_ICON:
293       g_value_set_string (value, panel_str_is_empty (plugin->button_icon) ?
294           DEFAULT_ICON_NAME : plugin->button_icon);
295       break;
296 
297     case PROP_CUSTOM_MENU:
298       g_value_set_boolean (value, plugin->custom_menu);
299       break;
300 
301     case PROP_CUSTOM_MENU_FILE:
302       g_value_set_string (value, plugin->custom_menu_file);
303       break;
304 
305     case PROP_MENU_EDITOR:
306       g_value_set_string (value, plugin->menu_editor);
307       break;
308 
309     default:
310       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
311       break;
312     }
313 }
314 
315 
316 
317 static void
applications_menu_plugin_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)318 applications_menu_plugin_set_property (GObject      *object,
319                                        guint         prop_id,
320                                        const GValue *value,
321                                        GParamSpec   *pspec)
322 {
323   ApplicationsMenuPlugin *plugin = XFCE_APPLICATIONS_MENU_PLUGIN (object);
324   gboolean                force_a_resize = FALSE;
325 
326   switch (prop_id)
327     {
328     case PROP_SHOW_GENERIC_NAMES:
329       garcon_gtk_menu_set_show_generic_names (GARCON_GTK_MENU (plugin->menu),
330                                               g_value_get_boolean (value));
331       break;
332 
333     case PROP_SHOW_MENU_ICONS:
334       garcon_gtk_menu_set_show_menu_icons (GARCON_GTK_MENU (plugin->menu),
335                                            g_value_get_boolean (value));
336        break;
337 
338     case PROP_SHOW_TOOLTIPS:
339       garcon_gtk_menu_set_show_tooltips (GARCON_GTK_MENU (plugin->menu),
340                                          g_value_get_boolean (value));
341       break;
342 
343     case PROP_SHOW_BUTTON_TITLE:
344       plugin->show_button_title = g_value_get_boolean (value);
345       if (plugin->show_button_title)
346         gtk_widget_show (plugin->label);
347       else
348         gtk_widget_hide (plugin->label);
349       applications_menu_plugin_size_changed (XFCE_PANEL_PLUGIN (plugin),
350           xfce_panel_plugin_get_size (XFCE_PANEL_PLUGIN (plugin)));
351       return;
352 
353     case PROP_BUTTON_TITLE:
354       g_free (plugin->button_title);
355       plugin->button_title = g_value_dup_string (value);
356       gtk_label_set_text (GTK_LABEL (plugin->label),
357           plugin->button_title != NULL ? plugin->button_title : "");
358       gtk_widget_set_tooltip_text (plugin->button,
359           panel_str_is_empty (plugin->button_title) ? NULL : plugin->button_title);
360 
361       /* check if the label still fits */
362       if (xfce_panel_plugin_get_mode (XFCE_PANEL_PLUGIN (plugin)) == XFCE_PANEL_PLUGIN_MODE_DESKBAR
363           && plugin->show_button_title)
364         {
365           force_a_resize = TRUE;
366         }
367       break;
368 
369     case PROP_BUTTON_ICON:
370       g_free (plugin->button_icon);
371       plugin->button_icon = g_value_dup_string (value);
372 
373       force_a_resize = TRUE;
374       break;
375 
376     case PROP_CUSTOM_MENU:
377       plugin->custom_menu = g_value_get_boolean (value);
378 
379       if (plugin->is_constructed)
380         applications_menu_plugin_set_garcon_menu (plugin);
381       break;
382 
383     case PROP_CUSTOM_MENU_FILE:
384       g_free (plugin->custom_menu_file);
385       plugin->custom_menu_file = g_value_dup_string (value);
386 
387       if (plugin->is_constructed)
388         applications_menu_plugin_set_garcon_menu (plugin);
389       break;
390 
391     case PROP_MENU_EDITOR:
392       plugin->menu_editor = g_value_dup_string (value);
393       break;
394 
395     default:
396       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
397       break;
398     }
399 
400   if (force_a_resize)
401     {
402       applications_menu_plugin_size_changed (XFCE_PANEL_PLUGIN (plugin),
403           xfce_panel_plugin_get_size (XFCE_PANEL_PLUGIN (plugin)));
404     }
405 }
406 
407 
408 
409 static void
applications_menu_plugin_construct(XfcePanelPlugin * panel_plugin)410 applications_menu_plugin_construct (XfcePanelPlugin *panel_plugin)
411 {
412   ApplicationsMenuPlugin *plugin = XFCE_APPLICATIONS_MENU_PLUGIN (panel_plugin);
413   const PanelProperty  properties[] =
414   {
415     { "show-generic-names", G_TYPE_BOOLEAN },
416     { "show-menu-icons", G_TYPE_BOOLEAN },
417     { "show-button-title", G_TYPE_BOOLEAN },
418     { "show-tooltips", G_TYPE_BOOLEAN },
419     { "button-title", G_TYPE_STRING },
420     { "button-icon", G_TYPE_STRING },
421     { "custom-menu", G_TYPE_BOOLEAN },
422     { "custom-menu-file", G_TYPE_STRING },
423     { "menu-editor", G_TYPE_STRING },
424     { NULL }
425   };
426 
427   xfce_panel_plugin_menu_show_configure (XFCE_PANEL_PLUGIN (plugin));
428 
429   /* bind all properties */
430   panel_properties_bind (NULL, G_OBJECT (plugin),
431                          xfce_panel_plugin_get_property_base (panel_plugin),
432                          properties, FALSE);
433 
434   /* make sure the menu is set */
435   applications_menu_plugin_set_garcon_menu (plugin);
436 
437   if (!plugin->menu_editor)
438       plugin->menu_editor = DEFAULT_EDITOR;
439 
440   gtk_widget_show (plugin->button);
441 
442   applications_menu_plugin_size_changed (panel_plugin,
443       xfce_panel_plugin_get_size (panel_plugin));
444   plugin->is_constructed = TRUE;
445 }
446 
447 
448 
449 static void
applications_menu_plugin_free_data(XfcePanelPlugin * panel_plugin)450 applications_menu_plugin_free_data (XfcePanelPlugin *panel_plugin)
451 {
452   ApplicationsMenuPlugin *plugin = XFCE_APPLICATIONS_MENU_PLUGIN (panel_plugin);
453   GtkIconTheme           *icon_theme;
454 
455   if (plugin->menu != NULL)
456     gtk_widget_destroy (plugin->menu);
457 
458   if (plugin->style_set_id != 0)
459     {
460       g_signal_handler_disconnect (plugin->button, plugin->style_set_id);
461       plugin->style_set_id = 0;
462     }
463 
464   if (plugin->screen_changed_id != 0)
465     {
466       g_signal_handler_disconnect (plugin->button, plugin->screen_changed_id);
467       plugin->screen_changed_id = 0;
468     }
469 
470   if (plugin->theme_changed_id != 0)
471     {
472       icon_theme = gtk_icon_theme_get_default ();
473       g_signal_handler_disconnect (G_OBJECT (icon_theme),
474                                    plugin->theme_changed_id);
475       plugin->theme_changed_id = 0;
476     }
477 
478   g_free (plugin->button_title);
479   g_free (plugin->button_icon);
480   g_free (plugin->custom_menu_file);
481 }
482 
483 
484 
485 static gboolean
applications_menu_plugin_size_changed(XfcePanelPlugin * panel_plugin,gint size)486 applications_menu_plugin_size_changed (XfcePanelPlugin *panel_plugin,
487                                        gint             size)
488 {
489   ApplicationsMenuPlugin *plugin = XFCE_APPLICATIONS_MENU_PLUGIN (panel_plugin);
490   XfcePanelPluginMode     mode;
491   GtkRequisition          label_size;
492   GtkOrientation          orientation;
493   gint                    border_thickness;
494   GdkPixbuf              *icon;
495   gint                    icon_size;
496   GdkScreen              *screen;
497   GtkIconTheme           *icon_theme = NULL;
498   gchar                  *icon_name;
499   GtkStyleContext        *ctx;
500   GtkBorder               padding, border;
501 
502   gtk_box_set_child_packing (GTK_BOX (plugin->box), plugin->icon,
503                              !plugin->show_button_title,
504                              !plugin->show_button_title,
505                              0, GTK_PACK_START);
506 
507   mode = xfce_panel_plugin_get_mode (panel_plugin);
508 
509   if (mode == XFCE_PANEL_PLUGIN_MODE_HORIZONTAL)
510     orientation = GTK_ORIENTATION_HORIZONTAL;
511   else
512     orientation = GTK_ORIENTATION_VERTICAL;
513 
514   /* style thickness */
515   ctx = gtk_widget_get_style_context (plugin->button);
516   gtk_style_context_get_padding (ctx, gtk_widget_get_state_flags (plugin->button), &padding);
517   gtk_style_context_get_border (ctx, gtk_widget_get_state_flags (plugin->button), &border);
518   border_thickness = MAX (padding.left + padding.right + border.left + border.right,
519                           padding.top + padding.bottom + border.top + border.bottom);
520 
521   icon_size = xfce_panel_plugin_get_icon_size (panel_plugin);
522 
523   screen = gtk_widget_get_screen (GTK_WIDGET (plugin));
524   if (G_LIKELY (screen != NULL))
525     icon_theme = gtk_icon_theme_get_for_screen (screen);
526 
527   icon_name = panel_str_is_empty (plugin->button_icon) ?
528     DEFAULT_ICON_NAME : plugin->button_icon;
529 
530   icon = xfce_panel_pixbuf_from_source_at_size (icon_name,
531                                                 icon_theme,
532                                                 icon_size,
533                                                 icon_size);
534 
535   if (G_LIKELY (icon != NULL))
536     {
537       gtk_image_set_from_pixbuf (GTK_IMAGE (plugin->icon), icon);
538       g_object_unref (G_OBJECT (icon));
539     }
540 
541   if (plugin->show_button_title &&
542       mode == XFCE_PANEL_PLUGIN_MODE_DESKBAR)
543     {
544       /* check if the label (minimum size) fits next to the icon */
545       gtk_widget_get_preferred_size (GTK_WIDGET (plugin->label), &label_size, NULL);
546       if (label_size.width <= size - icon_size - 2 - border_thickness)
547         orientation = GTK_ORIENTATION_HORIZONTAL;
548     }
549 
550   gtk_orientable_set_orientation (GTK_ORIENTABLE (plugin->box), orientation);
551 
552   return TRUE;
553 }
554 
555 
556 
557 static void
applications_menu_plugin_mode_changed(XfcePanelPlugin * panel_plugin,XfcePanelPluginMode mode)558 applications_menu_plugin_mode_changed (XfcePanelPlugin     *panel_plugin,
559                                        XfcePanelPluginMode  mode)
560 {
561   ApplicationsMenuPlugin *plugin = XFCE_APPLICATIONS_MENU_PLUGIN (panel_plugin);
562   gint                    angle;
563 
564   angle = (mode == XFCE_PANEL_PLUGIN_MODE_VERTICAL) ? 270 : 0;
565   gtk_label_set_angle (GTK_LABEL (plugin->label), angle);
566 
567   applications_menu_plugin_size_changed (panel_plugin,
568       xfce_panel_plugin_get_size (panel_plugin));
569 }
570 
571 
572 
573 static void
applications_menu_plugin_configure_plugin_file_set(GtkFileChooserButton * button,ApplicationsMenuPlugin * plugin)574 applications_menu_plugin_configure_plugin_file_set (GtkFileChooserButton   *button,
575                                                     ApplicationsMenuPlugin *plugin)
576 {
577   gchar *filename;
578 
579   panel_return_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (button));
580   panel_return_if_fail (XFCE_IS_APPLICATIONS_MENU_PLUGIN (plugin));
581 
582   filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (button));
583   g_object_set (G_OBJECT (plugin), "custom-menu-file", filename, NULL);
584   g_free (filename);
585 }
586 
587 
588 
589 static void
applications_menu_plugin_configure_plugin_icon_chooser(GtkWidget * button,ApplicationsMenuPlugin * plugin)590 applications_menu_plugin_configure_plugin_icon_chooser (GtkWidget              *button,
591                                                         ApplicationsMenuPlugin *plugin)
592 {
593 #ifdef EXO_CHECK_VERSION
594   GtkWidget *chooser;
595   gchar     *icon;
596 
597   panel_return_if_fail (XFCE_IS_APPLICATIONS_MENU_PLUGIN (plugin));
598   panel_return_if_fail (GTK_IMAGE (plugin->dialog_icon));
599 
600   chooser = exo_icon_chooser_dialog_new (_("Select An Icon"),
601                                          GTK_WINDOW (gtk_widget_get_toplevel (button)),
602                                          _("_Cancel"), GTK_RESPONSE_CANCEL,
603                                          _("_OK"), GTK_RESPONSE_ACCEPT,
604                                          NULL);
605   gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_ACCEPT);
606 
607   exo_icon_chooser_dialog_set_icon (EXO_ICON_CHOOSER_DIALOG (chooser),
608       panel_str_is_empty (plugin->button_icon) ? DEFAULT_ICON_NAME : plugin->button_icon);
609 
610   if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT)
611     {
612       icon = exo_icon_chooser_dialog_get_icon (EXO_ICON_CHOOSER_DIALOG (chooser));
613       g_object_set (G_OBJECT (plugin), "button-icon", icon, NULL);
614       gtk_image_set_from_icon_name (GTK_IMAGE (plugin->dialog_icon),
615                                     exo_str_is_empty (plugin->button_icon) ?
616                                     DEFAULT_ICON_NAME : plugin->button_icon,
617                                     GTK_ICON_SIZE_DIALOG);
618       g_free (icon);
619     }
620 
621   gtk_widget_destroy (chooser);
622 #endif
623 }
624 
625 
626 
627 static void
applications_menu_plugin_configure_plugin_edit(GtkWidget * button,ApplicationsMenuPlugin * plugin)628 applications_menu_plugin_configure_plugin_edit (GtkWidget              *button,
629                                                 ApplicationsMenuPlugin *plugin)
630 {
631   GError      *error = NULL;
632 
633   panel_return_if_fail (XFCE_IS_APPLICATIONS_MENU_PLUGIN (plugin));
634   panel_return_if_fail (GTK_IS_WIDGET (button));
635 
636   if (!xfce_spawn_command_line (gtk_widget_get_screen (button), plugin->menu_editor,
637                                 FALSE, FALSE, TRUE, &error))
638     {
639       xfce_dialog_show_error (NULL, error, _("Failed to execute command \"%s\"."), plugin->menu_editor);
640       g_error_free (error);
641     }
642 }
643 
644 
645 
646 static void
applications_menu_plugin_configure_plugin(XfcePanelPlugin * panel_plugin)647 applications_menu_plugin_configure_plugin (XfcePanelPlugin *panel_plugin)
648 {
649   ApplicationsMenuPlugin *plugin = XFCE_APPLICATIONS_MENU_PLUGIN (panel_plugin);
650   GtkBuilder             *builder;
651   GObject                *dialog, *object, *object2;
652   guint                   i;
653   gchar                  *path;
654   const gchar            *check_names[] = { "show-generic-names", "show-menu-icons",
655                                             "show-tooltips", "show-button-title" };
656 
657   /* setup the dialog */
658   PANEL_UTILS_LINK_4UI
659   builder = panel_utils_builder_new (panel_plugin, applicationsmenu_dialog_ui,
660                                      applicationsmenu_dialog_ui_length, &dialog);
661   if (G_UNLIKELY (builder == NULL))
662     return;
663 
664   for (i = 0; i < G_N_ELEMENTS (check_names); ++i)
665     {
666       object = gtk_builder_get_object (builder, check_names[i]);
667       panel_return_if_fail (GTK_IS_CHECK_BUTTON (object));
668       g_object_bind_property (G_OBJECT (plugin), check_names[i],
669                               G_OBJECT (object), "active",
670                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
671     }
672 
673   object = gtk_builder_get_object (builder, "button-title");
674   panel_return_if_fail (GTK_IS_ENTRY (object));
675   g_object_bind_property (G_OBJECT (plugin), "button-title",
676                           G_OBJECT (object), "text",
677                           G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
678 
679   object = gtk_builder_get_object (builder, "icon-button");
680   panel_return_if_fail (GTK_IS_BUTTON (object));
681   g_signal_connect (G_OBJECT (object), "clicked",
682      G_CALLBACK (applications_menu_plugin_configure_plugin_icon_chooser), plugin);
683 
684   plugin->dialog_icon = gtk_image_new_from_icon_name (
685       panel_str_is_empty (plugin->button_icon) ? DEFAULT_ICON_NAME : plugin->button_icon,
686       GTK_ICON_SIZE_DIALOG);
687   gtk_container_add (GTK_CONTAINER (object), plugin->dialog_icon);
688   g_object_add_weak_pointer (G_OBJECT (plugin->dialog_icon), (gpointer) &plugin->dialog_icon);
689   gtk_widget_show (plugin->dialog_icon);
690 
691   /* whether we show the edit menu button */
692   object = gtk_builder_get_object (builder, "edit-menu-button");
693   panel_return_if_fail (GTK_IS_BUTTON (object));
694   path = g_find_program_in_path (plugin->menu_editor);
695   if (path != NULL)
696     {
697       object2 = gtk_builder_get_object (builder, "use-default-menu");
698       panel_return_if_fail (GTK_IS_RADIO_BUTTON (object2));
699       g_object_bind_property (G_OBJECT (object2), "active",
700                               G_OBJECT (object), "sensitive",
701                               G_BINDING_SYNC_CREATE);
702       g_signal_connect (G_OBJECT (object), "clicked",
703           G_CALLBACK (applications_menu_plugin_configure_plugin_edit), plugin);
704     }
705   else
706     {
707       gtk_widget_hide (GTK_WIDGET (object));
708     }
709   g_free (path);
710 
711   object = gtk_builder_get_object (builder, "use-custom-menu");
712   panel_return_if_fail (GTK_IS_RADIO_BUTTON (object));
713   g_object_bind_property (G_OBJECT (plugin), "custom-menu",
714                           G_OBJECT (object), "active",
715                           G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
716 
717   /* sensitivity of custom file selector */
718   object2 = gtk_builder_get_object (builder, "custom-box");
719   panel_return_if_fail (GTK_IS_WIDGET (object2));
720   g_object_bind_property (G_OBJECT (object), "active",
721                           G_OBJECT (object2), "sensitive",
722                           G_BINDING_SYNC_CREATE);
723 
724   object = gtk_builder_get_object (builder, "custom-file");
725   panel_return_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (object));
726   if (!panel_str_is_empty (plugin->custom_menu_file))
727     gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (object), plugin->custom_menu_file);
728   g_signal_connect (G_OBJECT (object), "file-set",
729      G_CALLBACK (applications_menu_plugin_configure_plugin_file_set), plugin);
730 
731   gtk_widget_show (GTK_WIDGET (dialog));
732 }
733 
734 
735 
736 static gboolean
applications_menu_plugin_remote_event(XfcePanelPlugin * panel_plugin,const gchar * name,const GValue * value)737 applications_menu_plugin_remote_event (XfcePanelPlugin *panel_plugin,
738                                        const gchar     *name,
739                                        const GValue    *value)
740 {
741   ApplicationsMenuPlugin *plugin = XFCE_APPLICATIONS_MENU_PLUGIN (panel_plugin);
742 
743   panel_return_val_if_fail (value == NULL || G_IS_VALUE (value), FALSE);
744 
745   if (strcmp (name, "popup") == 0
746       && gtk_widget_get_visible (GTK_WIDGET (panel_plugin))
747       && !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (plugin->button))
748       && panel_utils_grab_available ())
749     {
750       if (value != NULL
751           && G_VALUE_HOLDS_BOOLEAN (value)
752           && g_value_get_boolean (value))
753         {
754           /* show menu under cursor */
755           applications_menu_plugin_menu (NULL, NULL, plugin);
756         }
757       else
758         {
759           /* show the menu at the button */
760           applications_menu_plugin_menu (plugin->button, NULL, plugin);
761         }
762 
763       /* don't popup another menu */
764       return TRUE;
765     }
766 
767   return FALSE;
768 }
769 
770 
771 
772 static void
applications_menu_plugin_menu_deactivate(GtkWidget * menu,ApplicationsMenuPlugin * plugin)773 applications_menu_plugin_menu_deactivate (GtkWidget *menu,
774                                           ApplicationsMenuPlugin *plugin)
775 {
776   panel_return_if_fail (plugin->button == NULL || GTK_IS_TOGGLE_BUTTON (plugin->button));
777   panel_return_if_fail (GTK_IS_MENU (menu));
778 
779   xfce_panel_plugin_block_autohide (XFCE_PANEL_PLUGIN (plugin), FALSE);
780 
781   /* button is NULL when we popup the menu under the cursor position */
782   if (plugin->button != NULL)
783     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plugin->button), FALSE);
784 
785   gtk_menu_popdown (GTK_MENU (menu));
786 }
787 
788 
789 
790 static void
applications_menu_plugin_set_garcon_menu(ApplicationsMenuPlugin * plugin)791 applications_menu_plugin_set_garcon_menu (ApplicationsMenuPlugin *plugin)
792 {
793   GarconMenu *menu = NULL;
794   gchar      *filename;
795   GFile      *file;
796 
797   panel_return_if_fail (XFCE_IS_APPLICATIONS_MENU_PLUGIN (plugin));
798   panel_return_if_fail (GARCON_GTK_IS_MENU (plugin->menu));
799 
800   /* load the custom menu if set */
801   if (plugin->custom_menu
802       && plugin->custom_menu_file != NULL)
803     menu = garcon_menu_new_for_path (plugin->custom_menu_file);
804 
805   /* use the applications menu, this also respects the
806    * XDG_MENU_PREFIX environment variable */
807   if (G_LIKELY (menu == NULL))
808     menu = garcon_menu_new_applications ();
809 
810   /* set the menu */
811   garcon_gtk_menu_set_menu (GARCON_GTK_MENU (plugin->menu), menu);
812 
813   /* debugging information */
814   if (0)
815     {
816   file = garcon_menu_get_file (menu);
817   filename = g_file_get_parse_name (file);
818   g_object_unref (G_OBJECT (file));
819 
820   panel_debug (PANEL_DEBUG_APPLICATIONSMENU,
821                "menu from \"%s\"", filename);
822   g_free (filename);
823     }
824 
825   g_object_unref (G_OBJECT (menu));
826 }
827 
828 
829 
830 static gboolean
applications_menu_plugin_menu(GtkWidget * button,GdkEventButton * event,ApplicationsMenuPlugin * plugin)831 applications_menu_plugin_menu (GtkWidget              *button,
832                                GdkEventButton         *event,
833                                ApplicationsMenuPlugin *plugin)
834 {
835   panel_return_val_if_fail (XFCE_IS_APPLICATIONS_MENU_PLUGIN (plugin), FALSE);
836   panel_return_val_if_fail (button == NULL || plugin->button == button, FALSE);
837 
838   if (event != NULL /* remove event */
839       && !(event->button == 1
840            && event->type == GDK_BUTTON_PRESS
841            && !PANEL_HAS_FLAG (event->state, GDK_CONTROL_MASK)))
842     return FALSE;
843 
844   xfce_panel_plugin_block_autohide (XFCE_PANEL_PLUGIN (plugin), TRUE);
845 
846   if (button != NULL)
847     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
848 
849   /* show the menu */
850   gtk_menu_popup_at_widget (GTK_MENU (plugin->menu), button,
851                             xfce_panel_plugin_get_orientation (XFCE_PANEL_PLUGIN (plugin)) == GTK_ORIENTATION_VERTICAL
852                             ? GDK_GRAVITY_NORTH_EAST : GDK_GRAVITY_SOUTH_WEST,
853                             GDK_GRAVITY_NORTH_WEST,
854                             (GdkEvent *) event);
855 
856   return TRUE;
857 }
858 
859 
860 
861 static void
applications_menu_button_theme_changed(ApplicationsMenuPlugin * plugin)862 applications_menu_button_theme_changed (ApplicationsMenuPlugin *plugin)
863 {
864   XfcePanelPlugin *panel_plugin = XFCE_PANEL_PLUGIN (plugin);
865 
866   applications_menu_plugin_size_changed (panel_plugin,
867       xfce_panel_plugin_get_size (panel_plugin));
868 }
869