~ubuntu-branches/ubuntu/utopic/cairo-dock-plug-ins/utopic

« back to all changes in this revision

Viewing changes to GMenu/src/applet-menu.c

  • Committer: Package Import Robot
  • Author(s): Matthieu Baerts (matttbe)
  • Date: 2013-03-26 00:17:44 UTC
  • mfrom: (36.1.3 cairo-dock-plug-ins)
  • Revision ID: package-import@ubuntu.com-20130326001744-10z2kb7sa66c6c6q
Tags: 3.2.0-0ubuntu1
* New upstream release.
* Upstream ChangeLog:
  - Clock: iCal: don't add a new task if the uid is NULL
  - DBus interfaces: install python interfaces for both python2 and 3
  - Dock rendering: fixed the drawing of the 3D and Curve views when the
    alignment  is not centered
  - Fixed a few compilation errors and warning for FreeBSD
  - GMenu: init: load all menus and submenus in a separated thread and
    not in the mainloop to avoid tiny freezes at startup
  - GMenu: split the applet in two directories: one if libgnome-menu-3 is
    available and another one (GMenu-old) if libgnome-menu is available.
  - GMenu: if the user wants to show the menu before it's loaded, set a
    pending event
  - gvfs integration: hidden files were not correctly handled
  - po: Imported translations from Launchpad
  - Shortcuts: Disk usage: some sentenses was not translatable
  - Shortcuts: for a bookmark that points to a volume mount it before
  - Shortcuts: if the user wants to show the menu before it's loaded, set
    a pending event
  - ShowDesktop: Gnome-Shell workaround: add a small delay before
    triggering the desktop Exposé or Gnome-Shell will not respond
  - Sound-control: ignore alsa callbacks that are not 'value changed'
  - Status-Notifier: don't reset the icon if not in compact mode
* debian/control:
  - Used the newer version of libgnome-menu (libgnome-menu-3-dev)
  - Bumped Cairo-Dock versions
  - Build-Depends: Added python3 in order to install both python 2 and 3
    interfaces

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
#include <cairo-dock.h>
22
22
 
23
23
#include "applet-struct.h"
24
 
#include "applet-menu-callbacks.h"
25
 
#include "applet-util.h"
26
24
#include "applet-menu.h"
27
 
 
28
 
 
29
 
GtkWidget * add_menu_separator (GtkWidget *menu)
30
 
{
31
 
        GtkWidget *menuitem;
32
 
        
33
 
        menuitem = gtk_separator_menu_item_new ();
34
 
        gtk_widget_set_sensitive (menuitem, FALSE);
35
 
        gtk_widget_show (menuitem);
36
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
37
 
 
38
 
        return menuitem;
39
 
}
40
 
 
41
 
GtkWidget * create_fake_menu (GMenuTreeDirectory *directory)
42
 
{       
43
 
        GtkWidget *menu;
44
 
        guint      idle_id;
45
 
        
46
 
        menu = create_empty_menu ();
47
 
 
48
 
        g_object_set_data_full (G_OBJECT (menu),
49
 
                                "panel-menu-tree-directory",
50
 
                                gmenu_tree_item_ref (directory),
51
 
                                (GDestroyNotify) gmenu_tree_item_unref);
52
 
        
53
 
        g_object_set_data (G_OBJECT (menu),
54
 
                           "panel-menu-needs-loading",
55
 
                           GUINT_TO_POINTER (TRUE));
56
 
 
57
 
        g_signal_connect (menu, "show",
58
 
                          G_CALLBACK (submenu_to_display), NULL);
59
 
 
60
 
        idle_id = g_idle_add_full (G_PRIORITY_LOW,
61
 
                                submenu_to_display_in_idle,
62
 
                                menu,
63
 
                                NULL);
64
 
        g_object_set_data_full (G_OBJECT (menu),
65
 
                                "panel-menu-idle-id",
66
 
                                GUINT_TO_POINTER (idle_id),
67
 
                                remove_submenu_to_display_idle);
68
 
 
69
 
        return menu;
70
 
}
71
 
 
72
 
void image_menu_destroy (GtkWidget *image, gpointer *data)
73
 
{
74
 
        myData.image_menu_items = g_slist_remove (myData.image_menu_items, image);
75
 
        if (myConfig.bLoadIconsAtStartup && ! myData.bIconsLoaded && myData.pPreloadedImagesList && data)
76
 
        { // we want to preload icon, the task has not been launched, the list is not empty and we receive data
77
 
                myData.pPreloadedImagesList = g_list_remove (myData.pPreloadedImagesList, data);
78
 
                g_free (data);
79
 
        }
80
 
}
81
 
 
82
 
 
83
 
void reload_image_menu_items (void)
84
 
{
85
 
        GSList *l;
86
 
 
87
 
        for (l = myData.image_menu_items; l; l = l->next) {
88
 
                GtkWidget *image = l->data;
89
 
                gboolean   is_mapped;
90
 
      
91
 
                ///is_mapped = GTK_WIDGET_MAPPED (image);
92
 
                is_mapped = gtk_widget_get_mapped (image);
93
 
                
94
 
                if (is_mapped)
95
 
                        gtk_widget_unmap (image);
96
 
 
97
 
                gtk_image_set_from_pixbuf (GTK_IMAGE (image), NULL);
98
 
    
99
 
                if (is_mapped)
100
 
                        gtk_widget_map (image);
101
 
 
102
 
        }
103
 
}
104
 
 
105
 
static void
106
 
remove_pixmap_from_loaded (gpointer data, GObject *where_the_object_was)
107
 
{
108
 
        char *key = data;
109
 
 
110
 
        if (myData.loaded_icons != NULL)
111
 
                g_hash_table_remove (myData.loaded_icons, key);
112
 
 
113
 
        g_free (key);
114
 
}
115
 
GdkPixbuf * panel_make_menu_icon (GtkIconTheme *icon_theme,
116
 
                      const char   *icon,
117
 
                      const char   *fallback,
118
 
                      int           size,
119
 
                      gboolean     *long_operation)
120
 
{
121
 
        GdkPixbuf *pb;
122
 
        char *file, *key;
123
 
        gboolean loaded;
124
 
 
125
 
        g_return_val_if_fail (size > 0, NULL);
126
 
 
127
 
        file = NULL;
128
 
        if (icon != NULL)
129
 
                file = panel_find_icon (icon_theme, icon, size);
130
 
        if (file == NULL && fallback != NULL)
131
 
                file = panel_find_icon (icon_theme, fallback, size);
132
 
 
133
 
        if (file == NULL)
134
 
                return NULL;
135
 
 
136
 
        if (long_operation != NULL)
137
 
                *long_operation = TRUE;
138
 
 
139
 
        pb = NULL;
140
 
 
141
 
        loaded = FALSE;
142
 
 
143
 
        key = g_strdup_printf ("%d:%s", size, file);
144
 
 
145
 
        if (myData.loaded_icons != NULL &&
146
 
            (pb = g_hash_table_lookup (myData.loaded_icons, key)) != NULL) {
147
 
                if (pb != NULL)
148
 
                        g_object_ref (G_OBJECT (pb));
149
 
        }
150
 
 
151
 
        if (pb == NULL) {
152
 
                pb = gdk_pixbuf_new_from_file (file, NULL);
153
 
                if (pb) {
154
 
                        gint width, height;
155
 
 
156
 
                        width = gdk_pixbuf_get_width (pb);
157
 
                        height = gdk_pixbuf_get_height (pb);
158
 
                        
159
 
                        /* if we want 24 and we get 22, do nothing;
160
 
                         * else scale */
161
 
                        if (!(size - 2 <= width && width <= size &&
162
 
                              size - 2 <= height && height <= size)) {
163
 
                                GdkPixbuf *tmp;
164
 
 
165
 
                                tmp = gdk_pixbuf_scale_simple (pb, size, size,
166
 
                                                               GDK_INTERP_BILINEAR);
167
 
 
168
 
                                g_object_unref (pb);
169
 
                                pb = tmp;
170
 
                        }
171
 
                }
172
 
                                
173
 
                /* add icon to the hash table so we don't load it again */
174
 
                loaded = TRUE;
175
 
        }
176
 
 
177
 
        if (pb == NULL) {
178
 
                g_free (file);
179
 
                g_free (key);
180
 
                return NULL;
181
 
        }
182
 
 
183
 
        if (loaded &&
184
 
            (gdk_pixbuf_get_width (pb) != size &&
185
 
             gdk_pixbuf_get_height (pb) != size)) {
186
 
                GdkPixbuf *pb2;
187
 
                int        dest_width;
188
 
                int        dest_height;
189
 
                int        width;
190
 
                int        height;
191
 
 
192
 
                width  = gdk_pixbuf_get_width (pb);
193
 
                height = gdk_pixbuf_get_height (pb);
194
 
 
195
 
                if (height > width) {
196
 
                        dest_width  = (size * width) / height;
197
 
                        dest_height = size;
198
 
                } else {
199
 
                        dest_width  = size;
200
 
                        dest_height = (size * height) / width;
201
 
                }
202
 
 
203
 
                pb2 = gdk_pixbuf_scale_simple (pb, dest_width, dest_height,
204
 
                                               GDK_INTERP_BILINEAR);
205
 
                g_object_unref (G_OBJECT (pb));
206
 
                pb = pb2;
207
 
        }
208
 
 
209
 
        if (loaded) {
210
 
                if (myData.loaded_icons == NULL)
211
 
                        myData.loaded_icons = g_hash_table_new_full
212
 
                                (g_str_hash, g_str_equal,
213
 
                                 (GDestroyNotify) g_free,
214
 
                                 (GDestroyNotify) g_object_unref);
215
 
                g_hash_table_replace (myData.loaded_icons,
216
 
                                      g_strdup (key),
217
 
                                      g_object_ref (G_OBJECT (pb)));
218
 
                g_object_weak_ref (G_OBJECT (pb),
219
 
                                   (GWeakNotify) remove_pixmap_from_loaded,
220
 
                                   g_strdup (key));
221
 
        } else {
222
 
                /* we didn't load from disk */
223
 
                if (long_operation != NULL)
224
 
                        *long_operation = FALSE;
225
 
        }
226
 
 
227
 
        g_free (file);
228
 
        g_free (key);
229
 
 
230
 
        return pb;
231
 
}
232
 
 
233
 
void panel_load_menu_image_deferred (GtkWidget   *image_menu_item,
234
 
                                GtkIconSize  icon_size,
235
 
                                ///const char  *stock_id,
236
 
                                ///GIcon       *gicon,
237
 
                                const char  *image_filename,
238
 
                                const char  *fallback_image_filename)
239
 
{
240
 
        IconToLoad *icon;
241
 
        GtkWidget *image;
242
 
        int        icon_height = myData.iPanelDefaultMenuIconSize;
243
 
 
244
 
        icon = g_new0 (IconToLoad, 1);
245
 
 
246
 
        gtk_icon_size_lookup (icon_size, NULL, &icon_height);
247
 
 
248
 
        image = gtk_image_new ();
249
 
        ///image->requisition.width  = icon_height;
250
 
        ///image->requisition.height = icon_height;
251
 
        gtk_widget_set_size_request (image, icon_height, icon_height);
252
 
        
253
 
        /* this takes over the floating ref */
254
 
        icon->pixmap = g_object_ref (G_OBJECT (image));
255
 
        g_object_ref_sink (G_OBJECT (image));
256
 
 
257
 
        /**icon->stock_id       = stock_id;
258
 
        if (gicon)
259
 
                icon->gicon  = g_object_ref (gicon);
260
 
        else
261
 
                icon->gicon  = NULL;*/
262
 
        icon->image          = g_strdup (image_filename);
263
 
        icon->fallback_image = g_strdup (fallback_image_filename);
264
 
        icon->icon_size      = icon_size;
265
 
 
266
 
        /**g_object_set_data_full (G_OBJECT (image_menu_item),
267
 
                                "Panel:Image",
268
 
                                g_object_ref (image),
269
 
                                (GDestroyNotify) g_object_unref);*/
270
 
 
271
 
        g_signal_connect_data (image, "map",
272
 
                               G_CALLBACK (image_menu_shown), icon,
273
 
                               (GClosureNotify) icon_to_load_free, 0);
274
 
 
275
 
        // pre-load all icons
276
 
        gpointer *data = NULL;
277
 
        if (myConfig.bLoadIconsAtStartup && ! myData.bIconsLoaded)
278
 
        {
279
 
                data = g_new0 (gpointer, 2);
280
 
                data[0] = image;
281
 
                data[1] = icon;
282
 
                myData.pPreloadedImagesList = g_list_append (myData.pPreloadedImagesList, data);
283
 
        }
284
 
 
285
 
        _gtk_image_menu_item_set_image (
286
 
                GTK_IMAGE_MENU_ITEM (image_menu_item), image);
287
 
 
288
 
        gtk_widget_show (image);
289
 
 
290
 
        g_signal_connect (image, "destroy",
291
 
                          G_CALLBACK (image_menu_destroy), data);
292
 
 
293
 
        myData.image_menu_items = g_slist_prepend (myData.image_menu_items, image);
294
 
}
295
 
GtkWidget * create_submenu_entry (GtkWidget          *menu,
296
 
                      GMenuTreeDirectory *directory)
297
 
{
298
 
        GtkWidget *menuitem;
299
 
 
300
 
        menuitem = gtk_image_menu_item_new ();
301
 
 
302
 
        panel_load_menu_image_deferred (menuitem,
303
 
                                        32, //panel_menu_icon_get_size (),
304
 
                                        ///NULL, NULL,
305
 
                                        gmenu_tree_directory_get_icon (directory),
306
 
                                        PANEL_ICON_FOLDER);
307
 
 
308
 
        setup_menuitem (menuitem,
309
 
                        32, //panel_menu_icon_get_size (),
310
 
                        ///NULL,
311
 
                        gmenu_tree_directory_get_name (directory));
312
 
 
313
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
314
 
 
315
 
        gtk_widget_show (menuitem);
316
 
 
317
 
        return menuitem;
318
 
}
319
 
 
320
 
void create_submenu (GtkWidget          *menu,
321
 
                GMenuTreeDirectory *directory,
322
 
                GMenuTreeDirectory *alias_directory)
323
 
{
324
 
        GtkWidget *menuitem;
325
 
        GtkWidget *submenu;
326
 
 
327
 
        if (alias_directory)
328
 
                menuitem = create_submenu_entry (menu, alias_directory);
329
 
        else
330
 
                menuitem = create_submenu_entry (menu, directory);
331
 
        
332
 
        submenu = create_fake_menu (directory);
333
 
 
334
 
        gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
335
 
}
336
 
 
337
 
void create_header (GtkWidget       *menu,
338
 
               GMenuTreeHeader *header)
339
 
{
340
 
        GMenuTreeDirectory *directory;
341
 
        GtkWidget          *menuitem;
342
 
 
343
 
        directory = gmenu_tree_header_get_directory (header);
344
 
        menuitem = create_submenu_entry (menu, directory);
345
 
        gmenu_tree_item_unref (directory);
346
 
 
347
 
        g_object_set_data_full (G_OBJECT (menuitem),
348
 
                                "panel-gmenu-tree.header",
349
 
                                gmenu_tree_item_ref (header),
350
 
                                (GDestroyNotify) gmenu_tree_item_unref);
351
 
 
352
 
        g_signal_connect (menuitem, "activate",
353
 
                          G_CALLBACK (gtk_false), NULL);
354
 
}
355
 
 
356
 
void create_menuitem (GtkWidget          *menu,
357
 
                 GMenuTreeEntry     *entry,
358
 
                 GMenuTreeDirectory *alias_directory)
359
 
{
360
 
        GtkWidget  *menuitem;
361
 
        
362
 
        menuitem = gtk_image_menu_item_new ();
363
 
 
364
 
        g_object_set_data_full (G_OBJECT (menuitem),
365
 
                                "panel-menu-tree-entry",
366
 
                                gmenu_tree_item_ref (entry),
367
 
                                (GDestroyNotify) gmenu_tree_item_unref);
368
 
 
369
 
        if (alias_directory)
370
 
                //FIXME: we should probably use this data when we do dnd or
371
 
                //context menu for this menu item
372
 
                g_object_set_data_full (G_OBJECT (menuitem),
373
 
                                        "panel-menu-tree-alias-directory",
374
 
                                        gmenu_tree_item_ref (alias_directory),
375
 
                                        (GDestroyNotify) gmenu_tree_item_unref);
376
 
 
377
 
        panel_load_menu_image_deferred (menuitem,
378
 
                                        myData.iPanelDefaultMenuIconSize, //panel_menu_icon_get_size (),
379
 
                                        ///NULL, NULL,
380
 
                                        alias_directory ? gmenu_tree_directory_get_icon (alias_directory) :
381
 
                                                          gmenu_tree_entry_get_icon (entry),
382
 
                                        NULL);
383
 
 
384
 
        setup_menuitem (menuitem,
385
 
                        myData.iPanelDefaultMenuIconSize, //panel_menu_icon_get_size (),
386
 
                        ///NULL,
387
 
                        alias_directory ? gmenu_tree_directory_get_name (alias_directory) :
388
 
                                          gmenu_tree_entry_get_name (entry));
389
 
 
390
 
        if ((alias_directory &&
391
 
             gmenu_tree_directory_get_comment (alias_directory)) ||
392
 
            (!alias_directory &&
393
 
             gmenu_tree_entry_get_comment (entry)))
394
 
                panel_util_set_tooltip_text (menuitem,
395
 
                                             alias_directory ?
396
 
                                                gmenu_tree_directory_get_comment (alias_directory) :
397
 
                                                gmenu_tree_entry_get_comment (entry));
398
 
 
399
 
        /*g_signal_connect_after (menuitem, "button_press_event",
400
 
                                G_CALLBACK (menuitem_button_press_event), NULL);*/
401
 
 
402
 
        //if (!panel_lockdown_get_locked_down ()) {
403
 
        {
404
 
                static GtkTargetEntry menu_item_targets[] = {
405
 
                        { (gchar*)"text/uri-list", 0, 0 }
406
 
                };
407
 
 
408
 
                gtk_drag_source_set (menuitem,
409
 
                                     GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
410
 
                                     menu_item_targets, 1,
411
 
                                     GDK_ACTION_COPY);
412
 
 
413
 
                if (gmenu_tree_entry_get_icon (entry) != NULL) {
414
 
                        const char *icon;
415
 
                        char       *icon_no_ext;
416
 
 
417
 
                        icon = gmenu_tree_entry_get_icon (entry);
418
 
                        if (!g_path_is_absolute (icon)) {
419
 
                                icon_no_ext = panel_util_icon_remove_extension (icon);
420
 
                                gtk_drag_source_set_icon_name (menuitem,
421
 
                                                               icon_no_ext);
422
 
                                g_free (icon_no_ext);
423
 
                        }
424
 
                }
425
 
 
426
 
                ///g_signal_connect (G_OBJECT (menuitem), "drag_begin",
427
 
                ///               G_CALLBACK (drag_begin_menu_cb), NULL);
428
 
                g_signal_connect (menuitem, "drag_data_get",
429
 
                                  G_CALLBACK (drag_data_get_menu_cb), entry);
430
 
                ///g_signal_connect (menuitem, "drag_end",
431
 
                ///               G_CALLBACK (drag_end_menu_cb), NULL);
432
 
        }
433
 
 
434
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
435
 
 
436
 
        g_signal_connect (menuitem, "activate",
437
 
                          G_CALLBACK (activate_app_def), entry);
438
 
 
439
 
        gtk_widget_show (menuitem);
440
 
}
441
 
 
442
 
void create_menuitem_from_alias (GtkWidget      *menu,
443
 
                            GMenuTreeAlias *alias)
444
 
{
445
 
        GMenuTreeItem *aliased_item;
446
 
 
447
 
        aliased_item = gmenu_tree_alias_get_item (alias);
448
 
 
449
 
        switch (gmenu_tree_item_get_type (aliased_item)) {
450
 
        case GMENU_TREE_ITEM_DIRECTORY:
451
 
                create_submenu (menu,
452
 
                                GMENU_TREE_DIRECTORY (aliased_item),
453
 
                                gmenu_tree_alias_get_directory (alias));
454
 
                break;
455
 
 
456
 
        case GMENU_TREE_ITEM_ENTRY:
457
 
                create_menuitem (menu,
458
 
                                 GMENU_TREE_ENTRY (aliased_item),
459
 
                                 gmenu_tree_alias_get_directory (alias));
460
 
                break;
461
 
 
462
 
        default:
463
 
                break;
464
 
        }
465
 
 
466
 
        gmenu_tree_item_unref (aliased_item);
467
 
}
468
 
 
469
 
 
470
 
/**static void
471
 
image_menuitem_size_request (GtkWidget      *menuitem,
472
 
                             GtkRequisition *requisition,
473
 
                             gpointer        data)
474
 
{
475
 
        GtkIconSize icon_size = (GtkIconSize) GPOINTER_TO_INT (data);
476
 
        int         icon_height;
477
 
        int         req_height;
478
 
 
479
 
        if (!gtk_icon_size_lookup (icon_size, NULL, &icon_height))
480
 
                return;
481
 
 
482
 
        // If we don't have a pixmap for this menuitem
483
 
        // at least make sure its the same height as
484
 
        // the rest.
485
 
        // This is a bit ugly, since we should keep this in sync with what's in
486
 
        // gtk_menu_item_size_request()
487
 
        req_height = icon_height;
488
 
        req_height += (GTK_CONTAINER (menuitem)->border_width +
489
 
                       menuitem->style->thickness) * 2;
490
 
        requisition->height = MAX (requisition->height, req_height);
491
 
}*/
492
 
void setup_menuitem (GtkWidget   *menuitem,
493
 
                GtkIconSize  icon_size,
494
 
                ///GtkWidget   *image,
495
 
                const char  *title)
496
 
                               
497
 
{
498
 
        GtkWidget *label;
499
 
        char      *_title;
500
 
 
501
 
        /* this creates a label with an invisible mnemonic */
502
 
        label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
503
 
        _title = menu_escape_underscores_and_prepend (title);
504
 
        gtk_label_set_text_with_mnemonic (GTK_LABEL (label), _title);
505
 
        g_free (_title);
506
 
 
507
 
        gtk_label_set_pattern (GTK_LABEL (label), "");
508
 
 
509
 
        gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), menuitem);
510
 
 
511
 
        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
512
 
        gtk_widget_show (label);
513
 
 
514
 
        gtk_container_add (GTK_CONTAINER (menuitem), label);
515
 
 
516
 
        /**if (image) {
517
 
                g_object_set_data_full (G_OBJECT (menuitem),
518
 
                                        "Panel:Image",
519
 
                                        g_object_ref (image),
520
 
                                        (GDestroyNotify) g_object_unref);
521
 
                gtk_widget_show (image);
522
 
                _gtk_image_menu_item_set_image (
523
 
                        GTK_IMAGE_MENU_ITEM (menuitem), image);
524
 
        } else if (icon_size != GTK_ICON_SIZE_INVALID)
525
 
                g_signal_connect (menuitem, "size_request",
526
 
                                  G_CALLBACK (image_menuitem_size_request),
527
 
                                  GINT_TO_POINTER (icon_size));
528
 
        */
529
 
        gtk_widget_show (menuitem);
530
 
}
531
 
 
532
 
GtkWidget * populate_menu_from_directory (GtkWidget          *menu,
533
 
                              GMenuTreeDirectory *directory)
534
 
{       
535
 
        GSList   *l;
536
 
        GSList   *items;
537
 
        gboolean  add_separator;
538
 
 
539
 
        ///add_separator = (GTK_MENU_SHELL (menu)->children != NULL);
540
 
        GList *children = gtk_container_get_children (GTK_CONTAINER (menu));
541
 
        add_separator = (children != NULL);
542
 
        g_list_free (children);  // not very optimized ...      
543
 
        
544
 
        items = gmenu_tree_directory_get_contents (directory);
545
 
 
546
 
        for (l = items; l; l = l->next) {
547
 
                GMenuTreeItem *item = l->data;
548
 
 
549
 
                if (add_separator ||
550
 
                    gmenu_tree_item_get_type (item) == GMENU_TREE_ITEM_SEPARATOR) {
551
 
                        add_menu_separator (menu);
552
 
                        add_separator = FALSE;
553
 
                }
554
 
 
555
 
                switch (gmenu_tree_item_get_type (item)) {
556
 
                case GMENU_TREE_ITEM_DIRECTORY:
557
 
                        create_submenu (menu, GMENU_TREE_DIRECTORY (item), NULL);
558
 
                        break;
559
 
 
560
 
                case GMENU_TREE_ITEM_ENTRY:
561
 
                        create_menuitem (menu, GMENU_TREE_ENTRY (item), NULL);
562
 
                        break;
563
 
 
564
 
                case GMENU_TREE_ITEM_SEPARATOR :
565
 
                        /* already added */
566
 
                        break;
567
 
 
568
 
                case GMENU_TREE_ITEM_ALIAS:
569
 
                        create_menuitem_from_alias (menu, GMENU_TREE_ALIAS (item));
570
 
                        break;
571
 
 
572
 
                case GMENU_TREE_ITEM_HEADER:
573
 
                        create_header (menu, GMENU_TREE_HEADER (item));
574
 
                        break;
575
 
 
576
 
                default:
577
 
                        break;
578
 
                }
579
 
 
580
 
                gmenu_tree_item_unref (item);
581
 
        }
582
 
 
583
 
        g_slist_free (items);
584
 
 
585
 
        return menu;
586
 
}
587
 
 
588
 
 
589
 
 
590
 
/**void icon_theme_changed (GtkIconTheme *icon_theme,
591
 
                    gpointer      data)
592
 
{
593
 
        reload_image_menu_items ();
594
 
}
595
 
 
596
 
static inline GtkWidget * panel_create_menu (void)
597
 
{
598
 
        GtkWidget       *retval;
599
 
        static gboolean  registered_icon_theme_changer = FALSE;
600
 
 
601
 
        if (!registered_icon_theme_changer) {
602
 
                registered_icon_theme_changer = TRUE;
603
 
 
604
 
                g_signal_connect (gtk_icon_theme_get_default (), "changed",
605
 
                                  G_CALLBACK (icon_theme_changed), NULL);
606
 
        }
607
 
        
608
 
        retval = gtk_menu_new ();
609
 
        
610
 
        return retval;
611
 
}*/
612
 
GtkWidget * create_empty_menu (void)
613
 
{
614
 
        GtkWidget *retval;
615
 
 
616
 
        ///retval = panel_create_menu ();
617
 
        retval = gtk_menu_new ();
618
 
        
619
 
        return retval;
620
 
}
621
 
 
622
 
static void _on_remove_tree (GMenuTree  *tree)
623
 
{
624
 
        cd_message ("%s (%x)", __func__, tree);
625
 
        //gmenu_tree_unref (tree);
626
 
}
627
 
 
628
 
GtkWidget * create_applications_menu (const char *menu_file,
629
 
                          const char *menu_path, GtkWidget *parent_menu)
630
 
{
631
 
        GMenuTree *tree;
632
 
        GtkWidget *menu;
633
 
        guint      idle_id;
634
 
 
635
 
        menu = (parent_menu ? parent_menu : create_empty_menu ());
636
 
        
637
 
        cd_message ("%s (%s)", __func__, menu_file);
638
 
        tree = gmenu_tree_lookup (menu_file, GMENU_TREE_FLAGS_NONE);
639
 
        cd_debug (" tree : %x", tree);
640
 
 
641
 
        g_object_set_data_full (G_OBJECT (menu),
642
 
                                "panel-menu-tree",
643
 
                                gmenu_tree_ref (tree),
644
 
                                (GDestroyNotify) _on_remove_tree);
645
 
 
646
 
        g_object_set_data_full (G_OBJECT (menu),
647
 
                                "panel-menu-tree-path",
648
 
                                g_strdup (menu_path ? menu_path : "/"),
649
 
                                (GDestroyNotify) g_free);
650
 
        
651
 
        g_object_set_data (G_OBJECT (menu),
652
 
                           "panel-menu-needs-loading",
653
 
                           GUINT_TO_POINTER (TRUE));
654
 
        
655
 
        // load the menu in idle, and force the loading if it's shown before.
656
 
        g_signal_connect (menu, "show",
657
 
                          G_CALLBACK (submenu_to_display), NULL);
658
 
 
659
 
        idle_id = g_idle_add_full (G_PRIORITY_LOW,
660
 
                                submenu_to_display_in_idle,
661
 
                                menu,
662
 
                                NULL);
663
 
        g_object_set_data_full (G_OBJECT (menu),
664
 
                                "panel-menu-idle-id",
665
 
                                GUINT_TO_POINTER (idle_id),
666
 
                                remove_submenu_to_display_idle);
667
 
 
668
 
        gmenu_tree_add_monitor (tree,
669
 
                               (GMenuTreeChangedFunc) handle_gmenu_tree_changed,
670
 
                               menu);
671
 
        g_signal_connect (menu, "destroy",
672
 
                          G_CALLBACK (remove_gmenu_tree_monitor), tree);
673
 
 
674
 
        gmenu_tree_unref (tree);
675
 
 
676
 
        return menu;
677
 
}
678
 
 
679
 
// $XDG_CONFIG_DIRS => /etc/xdg/xdg-cairo-dock:/etc/xdg
680
 
// http://developer.gnome.org/menu-spec/
681
 
gchar ** cd_gmenu_get_xdg_menu_dirs (void)
682
 
{
683
 
        const gchar *cMenuPrefix = g_getenv ("XDG_CONFIG_DIRS");
684
 
        if (! cMenuPrefix || *cMenuPrefix == '\0')
685
 
                cMenuPrefix = "/etc/xdg/menus";
686
 
 
687
 
        return g_strsplit (cMenuPrefix, ":", 0);
688
 
}
689
 
 
690
 
// check if the file exists and if yes, *cMenuName is created
691
 
gboolean _check_file_exists (const gchar *cDir, const gchar *cPrefix, gchar **cMenuName)
692
 
{
693
 
        gchar *cMenuFilePathWithPrefix = g_strdup_printf ("%s/menus/%sapplications.menu", cDir, cPrefix);
694
 
 
695
 
        gboolean bFileExists = g_file_test (cMenuFilePathWithPrefix, G_FILE_TEST_EXISTS);
696
 
        if (bFileExists)
697
 
                *cMenuName = g_strdup_printf ("%sapplications.menu", cPrefix);
698
 
 
699
 
        cd_debug ("Check: %s: %d", cMenuFilePathWithPrefix, bFileExists);
700
 
        g_free (cMenuFilePathWithPrefix);
701
 
        return bFileExists;
702
 
}
703
 
 
704
 
static const gchar *cPrefixNames[] = {"", "gnome-", "kde-", "kde4-", "xfce-", "lxde-", NULL};
705
 
 
706
 
GtkWidget * create_main_menu (CairoDockModuleInstance *myApplet)
707
 
{
708
 
        GtkWidget *main_menu;
709
 
 
710
 
        gchar *cMenuFileName = NULL, *cXdgMenuPath = NULL;
711
 
        const gchar *cMenuPrefix = g_getenv ("XDG_MENU_PREFIX"); // e.g. on xfce, it contains "xfce-", nothing on gnome
712
 
        gchar **cXdgPath = cd_gmenu_get_xdg_menu_dirs ();
713
 
 
714
 
        int i;
715
 
        for (i = 0; cXdgPath[i] != NULL; i++)
716
 
        {
717
 
                g_free (cXdgMenuPath);
718
 
                cXdgMenuPath = g_strdup_printf ("%s/menus", cXdgPath[i]);
719
 
                if (! g_file_test (cXdgMenuPath, G_FILE_TEST_IS_DIR)) // cXdgPath can contain an invalid dir
720
 
                        continue;
721
 
 
722
 
                // this test should be the good one: with or without the prefix
723
 
                if (_check_file_exists (cXdgPath[i], cMenuPrefix ? cMenuPrefix : "", &cMenuFileName))
724
 
                        break;
725
 
 
726
 
                // let's check with common prefixes
727
 
                for (int iPrefix = 0; cPrefixNames[iPrefix] != NULL; iPrefix++)
728
 
                {
729
 
                        if (_check_file_exists (cXdgPath[i], cPrefixNames[iPrefix], &cMenuFileName))
730
 
                                break;
731
 
                }
732
 
 
733
 
                if (cMenuFileName == NULL) // let's check any *-applications.menu
734
 
                {
735
 
                        const gchar *cFileName;
736
 
                        GDir *dir = g_dir_open (cXdgPath[i], 0, NULL);
737
 
                        if (dir)
 
25
#include "applet-recent.h"
 
26
#include "applet-tree.h"
 
27
 
 
28
static void cd_menu_append_poweroff_to_menu (GtkWidget *menu, CairoDockModuleInstance *myApplet);
 
29
 
 
30
 
 
31
static gboolean _make_menu_from_trees (CDSharedMemory *pSharedMemory)
 
32
{
 
33
        CD_APPLET_ENTER;
 
34
        
 
35
        myData.pTrees = pSharedMemory->pTrees;
 
36
        pSharedMemory->pTrees = NULL;
 
37
 
 
38
        myData.pMenu = pSharedMemory->pMenu;
 
39
        pSharedMemory->pMenu = NULL;
 
40
        
 
41
        // append recent events
 
42
        if (myConfig.bShowRecent)
 
43
                cd_menu_append_recent_to_menu (myData.pMenu, myApplet);
 
44
        
 
45
        // append logout item
 
46
        if (myConfig.iShowQuit != CD_GMENU_SHOW_QUIT_NONE)
 
47
                cd_menu_append_poweroff_to_menu (myData.pMenu, myApplet);
 
48
        
 
49
        if (myData.bShowMenuPending)
 
50
        {
 
51
                cd_menu_show_menu ();
 
52
                myData.bShowMenuPending = FALSE;
 
53
        }
 
54
        
 
55
        cairo_dock_discard_task (myData.pTask);
 
56
        myData.pTask = NULL;
 
57
        
 
58
        CD_APPLET_LEAVE (FALSE);
 
59
}
 
60
 
 
61
static void _load_trees_async (CDSharedMemory *pSharedMemory)
 
62
{
 
63
        GMenuTree *tree = cd_load_tree_from_file ("applications.menu");
 
64
        if (tree)
 
65
                pSharedMemory->pTrees = g_list_append (pSharedMemory->pTrees, tree);
 
66
        
 
67
        tree = cd_load_tree_from_file ("settings.menu");
 
68
        if (tree)
 
69
                pSharedMemory->pTrees = g_list_append (pSharedMemory->pTrees, tree);
 
70
 
 
71
        // create the menu
 
72
        pSharedMemory->pMenu = gtk_menu_new ();
 
73
        
 
74
        /* append the trees we got
 
75
         *  + it will populate menu and create all things
 
76
         *     (it will have a look at new images and maybe preload them)
 
77
         *  => do that in the separated thread
 
78
         */
 
79
        GList *t;
 
80
        for (t = pSharedMemory->pTrees; t != NULL; t = t->next)
 
81
        {
 
82
                tree = t->data;
 
83
                cd_append_tree_in_menu (tree, pSharedMemory->pMenu);
 
84
        }
 
85
}
 
86
 
 
87
static void _free_shared_memory (CDSharedMemory *pSharedMemory)
 
88
{
 
89
        g_list_foreach (pSharedMemory->pTrees, (GFunc)g_object_unref, NULL);
 
90
        g_list_free (pSharedMemory->pTrees);
 
91
        if (pSharedMemory->pMenu)
 
92
                gtk_widget_destroy (pSharedMemory->pMenu);
 
93
        g_free (pSharedMemory);
 
94
}
 
95
 
 
96
void cd_menu_start (void)
 
97
{
 
98
        CDSharedMemory *pSharedMemory = g_new0 (CDSharedMemory, 1);
 
99
        
 
100
        myData.pTask = cairo_dock_new_task_full (0,  // 1 shot task.
 
101
                (CairoDockGetDataAsyncFunc) _load_trees_async,
 
102
                (CairoDockUpdateSyncFunc) _make_menu_from_trees,
 
103
                (GFreeFunc) _free_shared_memory,
 
104
                pSharedMemory);
 
105
        
 
106
        if (cairo_dock_is_loading ())
 
107
                cairo_dock_launch_task_delayed (myData.pTask, 0);  // 0 <=> g_idle
 
108
        else
 
109
                cairo_dock_launch_task (myData.pTask);
 
110
}
 
111
 
 
112
void cd_menu_stop (void)
 
113
{
 
114
        cairo_dock_discard_task (myData.pTask);
 
115
        myData.pTask = NULL;
 
116
        
 
117
        g_list_foreach (myData.pTrees, (GFunc)g_object_unref, NULL);
 
118
        g_list_free (myData.pTrees);
 
119
        myData.pTrees = NULL;
 
120
        
 
121
        if (myData.pMenu != NULL)
 
122
        {
 
123
                gtk_widget_destroy (myData.pMenu);
 
124
                myData.pMenu = NULL;
 
125
                myData.pRecentMenuItem = NULL;
 
126
        }
 
127
}
 
128
 
 
129
 
 
130
 
 
131
// == cairo_dock_add_in_menu_with_stock_and_data   with icon size 24
 
132
static GtkWidget *_append_one_item_to_menu (const gchar *cLabel, const gchar *gtkStock, GFunc pFunction, GtkWidget *pMenu, gpointer pData)
 
133
{
 
134
        GtkWidget *pMenuItem = gtk_image_menu_item_new_with_label (cLabel);
 
135
        if (gtkStock)
 
136
        {
 
137
                GtkWidget *image = NULL;
 
138
                if (*gtkStock == '/')
 
139
                {
 
140
                        GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size (gtkStock, myData.iPanelDefaultMenuIconSize, myData.iPanelDefaultMenuIconSize, NULL);
 
141
                        image = gtk_image_new_from_pixbuf (pixbuf);
 
142
                        g_object_unref (pixbuf);
 
143
                }
 
144
                else
 
145
                {
 
146
                        const gchar *cIconPath = cairo_dock_search_icon_s_path (gtkStock, myData.iPanelDefaultMenuIconSize);
 
147
                        if (cIconPath == NULL)
738
148
                        {
739
 
                                while ((cFileName = g_dir_read_name (dir)))
740
 
                                {
741
 
                                        if (g_str_has_suffix (cFileName, "-applications.menu"))
742
 
                                        {
743
 
                                                cMenuFileName = g_strdup (cFileName);
744
 
                                                break;
745
 
                                        }
746
 
                                }
747
 
                                g_dir_close (dir);
748
 
                                if (cMenuFileName != NULL)
749
 
                                        break;
 
149
                                cIconPath = g_strconcat (MY_APPLET_SHARE_DATA_DIR"/", gtkStock, ".svg", NULL);
750
150
                        }
 
151
                        GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size (cIconPath, myData.iPanelDefaultMenuIconSize, myData.iPanelDefaultMenuIconSize, NULL);
 
152
                        image = gtk_image_new_from_pixbuf (pixbuf);
 
153
                        g_object_unref (pixbuf);
751
154
                }
752
 
        }
753
 
 
754
 
        cd_debug ("Menu: Found %s in %s (%s)", cMenuFileName, cXdgPath[i], cXdgMenuPath);
755
 
 
756
 
        if (cMenuFileName == NULL) // arf
757
 
                cMenuFileName = g_strdup ("applications.menu");
758
 
        
759
 
        main_menu = create_applications_menu (cMenuFileName, NULL, NULL);
760
 
        
761
 
        g_object_set_data (G_OBJECT (main_menu),
762
 
                "panel-menu-append-callback",
763
 
                main_menu_append);
764
 
        g_object_set_data (G_OBJECT (main_menu),
765
 
                "panel-menu-append-callback-data",
766
 
                myApplet);
767
 
 
768
 
        g_strfreev (cXdgPath);
769
 
        g_free (cMenuFileName);
770
 
        g_free (cXdgMenuPath);
771
 
 
772
 
        return main_menu;
 
155
                _gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (pMenuItem), image);
 
156
        }
 
157
        gtk_menu_shell_append  (GTK_MENU_SHELL (pMenu), pMenuItem);
 
158
        if (pFunction)
 
159
                g_signal_connect (G_OBJECT (pMenuItem), "activate", G_CALLBACK (pFunction), pData);
 
160
        return pMenuItem;
 
161
}
 
162
 
 
163
static void cd_menu_append_poweroff_to_menu (GtkWidget *menu, CairoDockModuleInstance *myApplet)
 
164
{
 
165
        GtkWidget *menuitem = gtk_separator_menu_item_new ();
 
166
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
 
167
        gtk_widget_show (menuitem);
 
168
 
 
169
        if (myConfig.iShowQuit == CD_GMENU_SHOW_QUIT_LOGOUT || myConfig.iShowQuit == CD_GMENU_SHOW_QUIT_BOTH)
 
170
                _append_one_item_to_menu (D_("Logout"), "system-log-out", (GFunc) cairo_dock_fm_logout, menu, NULL);
 
171
 
 
172
        if (myConfig.iShowQuit == CD_GMENU_SHOW_QUIT_SHUTDOWN || myConfig.iShowQuit == CD_GMENU_SHOW_QUIT_BOTH)
 
173
                _append_one_item_to_menu (D_("Shutdown"), "system-shutdown", (GFunc) cairo_dock_fm_shutdown, menu, NULL);
 
174
}
 
175
 
 
176
void cd_menu_show_menu (void)
 
177
{
 
178
        if (myData.pMenu != NULL)
 
179
        {
 
180
                CD_APPLET_POPUP_MENU_ON_MY_ICON (myData.pMenu);
 
181
        }
 
182
        else
 
183
        {
 
184
                myData.bShowMenuPending = TRUE;
 
185
        }
773
186
}