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

« back to all changes in this revision

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