2
* This file is a part of the Cairo-Dock project
4
* Copyright : (C) see the 'copyright' file.
5
* E-mail : see the 'copyright' file.
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.
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/>.
20
/******************************************************************************
22
This file is a part of the cairo-dock program,
23
released under the terms of the GNU General Public License.
25
Adapted from the Gnome-panel for Cairo-Dock by Fabrice Rey (for any bug report, please mail me to fabounet@users.berlios.de)
27
******************************************************************************/
30
#include <cairo-dock.h>
31
#include <gdk/gdkkeysyms.h>
33
#include "applet-struct.h"
34
#include "applet-menu.h"
35
#include "applet-util.h"
36
#include "applet-recent.h"
37
#include "applet-menu-callbacks.h"
39
static guint load_icons_id = 0;
40
static GList *icons_to_load = NULL;
41
static GList *icons_to_add = NULL;
44
void handle_gmenu_tree_changed (GMenuTree *tree,
47
g_print ("%s ()\n", __func__);
49
if (myData.pMenu != NULL)
51
gtk_widget_destroy (myData.pMenu);
55
if (myData.pMenu == NULL)
57
myData.pMenu = create_main_menu (NULL);
63
while (GTK_MENU_SHELL (menu)->children)
64
gtk_widget_destroy (GTK_MENU_SHELL (menu)->children->data);
66
g_object_set_data_full (G_OBJECT (menu),
67
"panel-menu-tree-directory",
70
g_object_set_data (G_OBJECT (menu),
71
"panel-menu-needs-loading",
72
GUINT_TO_POINTER (TRUE));
74
idle_id = g_idle_add_full (G_PRIORITY_LOW,
75
submenu_to_display_in_idle,
78
if (myData.iSidTreeChangeIdle != 0)
79
g_source_remove (myData.iSidTreeChangeIdle);
80
myData.iSidTreeChangeIdle = idle_id;
81
g_object_set_data_full (G_OBJECT (menu),
83
GUINT_TO_POINTER (idle_id),
84
remove_submenu_to_display_idle);
87
void remove_gmenu_tree_monitor (GtkWidget *menu,
90
g_print ("%s (%x)\n", __func__, tree);
91
gmenu_tree_remove_monitor (tree,
92
(GMenuTreeChangedFunc) handle_gmenu_tree_changed,
97
gboolean menu_dummy_button_press_event (GtkWidget *menuitem,
98
GdkEventButton *event)
100
if (event->button == 3)
107
void remove_submenu_to_display_idle (gpointer data)
109
guint idle_id = GPOINTER_TO_UINT (data);
111
g_source_remove (idle_id);
115
gboolean submenu_to_display_in_idle (gpointer data)
117
GtkWidget *menu = GTK_WIDGET (data);
118
cd_message ("%s (%x)", __func__, menu);
120
g_object_set_data (G_OBJECT (menu), "panel-menu-idle-id", NULL);
122
submenu_to_display (menu);
127
void submenu_to_display (GtkWidget *menu)
129
cd_message ("%s (%x)", __func__, menu);
131
GMenuTreeDirectory *directory;
132
const char *menu_path;
133
void (*append_callback) (GtkWidget *, gpointer);
134
gpointer append_data;
136
if (!g_object_get_data (G_OBJECT (menu), "panel-menu-needs-loading"))
138
g_print ("en fait non\n");
142
g_object_set_data (G_OBJECT (menu), "panel-menu-needs-loading", NULL);
144
directory = g_object_get_data (G_OBJECT (menu),
145
"panel-menu-tree-directory");
147
menu_path = g_object_get_data (G_OBJECT (menu),
148
"panel-menu-tree-path");
149
g_print ("n'est pas un directory, menu_path : %s\n", menu_path);
152
cd_warning ("menu_path is empty");
156
tree = g_object_get_data (G_OBJECT (menu), "panel-menu-tree");
159
cd_warning ("no tree found in datas");
162
directory = gmenu_tree_get_directory_from_path (tree,
165
g_object_set_data_full (G_OBJECT (menu),
166
"panel-menu-tree-directory",
168
(GDestroyNotify) gmenu_tree_item_unref);
170
//g_print ("%s ()\n", __func__);
172
populate_menu_from_directory (menu, directory);
174
append_callback = g_object_get_data (G_OBJECT (menu),
175
"panel-menu-append-callback");
176
append_data = g_object_get_data (G_OBJECT (menu),
177
"panel-menu-append-callback-data");
179
append_callback (menu, append_data);
183
void panel_desktop_menu_item_append_menu (GtkWidget *menu,
186
//g_print ("%s ()\n", __func__);
187
CairoDockModuleInstance *myApplet;
188
gboolean add_separator;
192
myApplet = (CairoDockModuleInstance *) data;
194
add_separator = FALSE;
195
children = gtk_container_get_children (GTK_CONTAINER (menu));
196
last = g_list_last (children);
199
/// add_separator = !GTK_IS_SEPARATOR (GTK_WIDGET (last->data));
201
g_list_free (children);
204
add_menu_separator (menu);
206
//panel_menu_items_append_from_desktop (menu, "yelp.desktop", NULL);
207
//panel_menu_items_append_from_desktop (menu, "gnome-about.desktop", NULL);
209
//if (parent->priv->append_lock_logout)
210
// panel_menu_items_append_lock_logout (menu);
212
void main_menu_append (GtkWidget *main_menu,
215
//g_print ("%s ()\n", __func__);
216
CairoDockModuleInstance *myApplet;
218
gboolean add_separator;
222
myApplet = (CairoDockModuleInstance *) data;
224
add_separator = FALSE;
225
children = gtk_container_get_children (GTK_CONTAINER (main_menu));
226
last = g_list_last (children);
228
///add_separator = !GTK_IS_SEPARATOR (GTK_WIDGET (last->data));
230
g_list_free (children);
233
add_menu_separator (main_menu);
236
GtkWidget *desktop_menu;
238
desktop_menu = create_applications_menu ("settings.menu", NULL, main_menu);
239
g_object_set_data_full (G_OBJECT (desktop_menu),
240
"panel-menu-tree-directory",
243
g_object_set_data (G_OBJECT (desktop_menu),
244
"panel-menu-append-callback",
245
panel_desktop_menu_item_append_menu);
246
g_object_set_data (G_OBJECT (desktop_menu),
247
"panel-menu-append-callback-data",
250
if (myConfig.bShowRecent)
252
cd_menu_append_recent_to_menu (main_menu, myApplet);
254
/*item = panel_place_menu_item_new (TRUE);
255
panel_place_menu_item_set_panel (item, panel);
256
gtk_menu_shell_append (GTK_MENU_SHELL (main_menu), item);
257
gtk_widget_show (item);
259
item = panel_desktop_menu_item_new (TRUE, FALSE);
260
panel_desktop_menu_item_set_panel (item, panel);
261
gtk_menu_shell_append (GTK_MENU_SHELL (main_menu), item);
262
gtk_widget_show (item);
264
panel_menu_items_append_lock_logout (main_menu);*/
267
/*gboolean show_item_menu (GtkWidget *item,
268
GdkEventButton *bevent)
270
CairoDockModuleInstance *myApplet;
273
if (panel_lockdown_get_locked_down ())
276
panel_widget = menu_get_panel (item);
278
menu = g_object_get_data (G_OBJECT (item), "panel-item-context-menu");
281
menu = create_item_context_menu (item, panel_widget);
286
gtk_menu_set_screen (GTK_MENU (menu),
287
gtk_window_get_screen (GTK_WINDOW (panel_widget->toplevel)));
289
gtk_menu_popup (GTK_MENU (menu),
290
NULL, NULL, NULL, NULL,
296
gboolean panel_menu_key_press_handler (GtkWidget *widget,
299
gboolean retval = FALSE;
301
if ((event->keyval == GDK_Menu) ||
302
(event->keyval == GDK_F10 &&
303
(event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_SHIFT_MASK)) {
304
GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
306
if (menu_shell->active_menu_item &&
307
GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL) {
308
GdkEventButton bevent;
311
bevent.time = GDK_CURRENT_TIME;
312
retval = show_item_menu (menu_shell->active_menu_item,
320
static void menu_item_style_set (GtkImage *image,
325
GtkIconSize icon_size = (GtkIconSize) GPOINTER_TO_INT (data);
329
if (!gtk_icon_size_lookup (icon_size, NULL, &icon_height))
332
pixbuf = gtk_image_get_pixbuf (image);
336
if (gdk_pixbuf_get_height (pixbuf) == icon_height)
339
widget = GTK_WIDGET (image);
341
is_mapped = GTK_WIDGET_MAPPED (widget);
343
gtk_widget_unmap (widget);
345
gtk_image_set_from_pixbuf (image, NULL);
348
gtk_widget_map (widget);
350
static void do_icons_to_add (void)
352
while (icons_to_add) {
353
IconToAdd *icon_to_add = icons_to_add->data;
355
icons_to_add = g_list_delete_link (icons_to_add, icons_to_add);
357
if (icon_to_add->stock_id)
358
gtk_image_set_from_stock (
359
GTK_IMAGE (icon_to_add->image),
360
icon_to_add->stock_id,
361
icon_to_add->icon_size);
363
g_assert (icon_to_add->pixbuf);
365
gtk_image_set_from_pixbuf (
366
GTK_IMAGE (icon_to_add->image),
367
icon_to_add->pixbuf);
369
g_signal_connect (icon_to_add->image, "style-set",
370
G_CALLBACK (menu_item_style_set),
371
GINT_TO_POINTER (icon_to_add->icon_size));
373
g_object_unref (icon_to_add->pixbuf);
376
g_object_unref (icon_to_add->image);
377
g_free (icon_to_add);
380
void icon_to_load_free (IconToLoad *icon)
386
g_object_unref (icon->pixmap);
390
g_object_unref (icon->gicon);
393
g_free (icon->image); icon->image = NULL;
394
g_free (icon->fallback_image); icon->fallback_image = NULL;
397
static gboolean load_icons_handler (gpointer data)
400
gboolean long_operation = FALSE;
402
load_icons_handler_again:
404
if (!icons_to_load) {
411
icon = icons_to_load->data;
412
icons_to_load->data = NULL;
414
icons_to_load = g_list_delete_link (icons_to_load, icons_to_load);
416
/* if not visible anymore, just ignore */
417
if ( ! GTK_WIDGET_VISIBLE (icon->pixmap)) {
418
icon_to_load_free (icon);
419
/* we didn't do anything long/hard, so just do this again,
420
* this is fun, don't go back to main loop */
421
goto load_icons_handler_again;
424
if (icon->stock_id) {
425
IconToAdd *icon_to_add;
427
icon_to_add = g_new (IconToAdd, 1);
428
icon_to_add->image = g_object_ref (icon->pixmap);
429
icon_to_add->stock_id = icon->stock_id;
430
icon_to_add->pixbuf = NULL;
431
icon_to_add->icon_size = icon->icon_size;
433
icons_to_add = g_list_prepend (icons_to_add, icon_to_add);
436
else if (icon->gicon) {
437
IconToAdd *icon_to_add;
440
int icon_height = PANEL_DEFAULT_MENU_ICON_SIZE;
442
gtk_icon_size_lookup (icon->icon_size, NULL, &icon_height);
444
icon_name = panel_util_get_icon_name_from_g_icon (icon->gicon);
447
pb = panel_make_menu_icon (icon->icon_theme,
449
icon->fallback_image,
454
pb = panel_util_get_pixbuf_from_g_loadable_icon (icon->gicon, icon_height);
455
if (!pb && icon->fallback_image) {
456
pb = panel_make_menu_icon (icon->icon_theme,
458
icon->fallback_image,
465
icon_to_load_free (icon);
467
/* this may have been a long operation so jump
468
* back to the main loop for a while */
471
/* we didn't do anything long/hard, so just do
472
* this again, this is fun, don't go back to
474
goto load_icons_handler_again;
477
icon_to_add = g_new (IconToAdd, 1);
478
icon_to_add->image = g_object_ref (icon->pixmap);
479
icon_to_add->stock_id = NULL;
480
icon_to_add->pixbuf = pb;
481
icon_to_add->icon_size = icon->icon_size;
483
icons_to_add = g_list_prepend (icons_to_add, icon_to_add);
487
IconToAdd *icon_to_add;
489
int icon_height = PANEL_DEFAULT_MENU_ICON_SIZE;
491
gtk_icon_size_lookup (icon->icon_size, NULL, &icon_height);
493
pb = panel_make_menu_icon (icon->icon_theme,
495
icon->fallback_image,
499
icon_to_load_free (icon);
501
/* this may have been a long operation so jump back to
502
* the main loop for a while */
505
/* we didn't do anything long/hard, so just do this again,
506
* this is fun, don't go back to main loop */
507
goto load_icons_handler_again;
510
icon_to_add = g_new (IconToAdd, 1);
511
icon_to_add->image = g_object_ref (icon->pixmap);
512
icon_to_add->stock_id = NULL;
513
icon_to_add->pixbuf = pb;
514
icon_to_add->icon_size = icon->icon_size;
516
icons_to_add = g_list_prepend (icons_to_add, icon_to_add);
519
icon_to_load_free (icon);
522
/* we didn't do anything long/hard, so just do this again,
523
* this is fun, don't go back to main loop */
524
goto load_icons_handler_again;
526
/* if still more we'll come back */
529
static GList * find_in_load_list (GtkWidget *image)
532
for (li = icons_to_load; li != NULL; li = li->next) {
533
IconToLoad *icon = li->data;
534
if (icon->pixmap == image)
539
static IconToLoad * icon_to_load_copy (IconToLoad *icon)
546
retval = g_new0 (IconToLoad, 1);
548
retval->pixmap = g_object_ref (icon->pixmap);
550
retval->gicon = g_object_ref (icon->gicon);
552
retval->gicon = NULL;
553
retval->image = g_strdup (icon->image);
554
retval->fallback_image = g_strdup (icon->fallback_image);
555
retval->stock_id = icon->stock_id;
556
retval->icon_size = icon->icon_size;
560
void image_menu_shown (GtkWidget *image, gpointer data)
562
IconToLoad *new_icon;
565
icon = (IconToLoad *) data;
567
/* if we've already handled this */
568
if (gtk_image_get_storage_type (GTK_IMAGE (image)) != GTK_IMAGE_EMPTY)
571
if (find_in_load_list (image) == NULL) {
572
new_icon = icon_to_load_copy (icon);
573
new_icon->icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (image));
574
icons_to_load = g_list_append (icons_to_load, new_icon);
576
if (load_icons_id == 0)
577
load_icons_id = g_idle_add (load_icons_handler, NULL);
580
void activate_app_def (GtkWidget *menuitem,
581
GMenuTreeEntry *entry)
585
path = gmenu_tree_entry_get_desktop_file_path (entry);
586
panel_menu_item_activate_desktop_file (menuitem, path);
591
void drag_begin_menu_cb (GtkWidget *widget, GdkDragContext *context)
593
/* FIXME: workaround for a possible gtk+ bug
594
* See bugs #92085(gtk+) and #91184(panel) for details.
595
* Maybe it's not needed with GtkTooltip?
597
g_object_set (widget, "has-tooltip", FALSE, NULL);
600
/* This is a _horrible_ hack to have this here. This needs to be added to the
601
* GTK+ menuing code in some manner.
603
void drag_end_menu_cb (GtkWidget *widget, GdkDragContext *context)
605
GtkWidget *xgrab_shell;
608
/* Find the last viewable ancestor, and make an X grab on it
610
parent = widget->parent;
613
/* FIXME: workaround for a possible gtk+ bug
614
* See bugs #92085(gtk+) and #91184(panel) for details.
616
g_object_set (widget, "has-tooltip", TRUE, NULL);
620
gboolean viewable = TRUE;
621
GtkWidget *tmp = parent;
625
if (!GTK_WIDGET_MAPPED (tmp))
634
xgrab_shell = parent;
636
parent = GTK_MENU_SHELL (parent)->parent_menu_shell;
639
if (xgrab_shell && !GTK_MENU(xgrab_shell)->torn_off)
641
GdkCursor *cursor = gdk_cursor_new (GDK_ARROW);
643
if ((gdk_pointer_grab (xgrab_shell->window, TRUE,
644
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
645
GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
646
GDK_POINTER_MOTION_MASK,
647
NULL, cursor, GDK_CURRENT_TIME) == 0))
649
if (gdk_keyboard_grab (xgrab_shell->window, TRUE,
650
GDK_CURRENT_TIME) == 0)
651
GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
654
gdk_pointer_ungrab (GDK_CURRENT_TIME);
658
gdk_cursor_unref (cursor);
662
void drag_data_get_menu_cb (GtkWidget *widget,
663
GdkDragContext *context,
664
GtkSelectionData *selection_data,
667
GMenuTreeEntry *entry)
673
path = gmenu_tree_entry_get_desktop_file_path (entry);
674
uri = g_filename_to_uri (path, NULL, NULL);
675
uri_list = g_strconcat (uri, "\r\n", NULL);
678
gtk_selection_data_set (selection_data,
679
selection_data->target, 8, (guchar *)uri_list,
684
/*gboolean menuitem_button_press_event (GtkWidget *menuitem,
685
GdkEventButton *event)
687
if (event->button == 3)
688
return show_item_menu (menuitem, event);