2
* Copyright (C) 1997 - 2000 The Free Software Foundation
3
* Copyright (C) 2000 Helix Code, Inc.
4
* Copyright (C) 2000 Eazel, Inc.
5
* Copyright (C) 2004 Red Hat Inc.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License as
9
* published by the Free Software Foundation; either version 2 of the
10
* License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful, but
13
* WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
29
#include <glib/gi18n.h>
31
#include <gdk/gdkkeysyms.h>
33
#include <libpanel-util/panel-keyfile.h>
34
#include <libpanel-util/panel-xdg.h>
37
#include "panel-util.h"
39
#include "panel-stock-icons.h"
40
#include "panel-action-button.h"
41
#include "panel-menu-button.h"
42
#include "panel-menu-items.h"
43
#include "panel-globals.h"
44
#include "panel-run-dialog.h"
45
#include "panel-lockdown.h"
46
#include "panel-icon-names.h"
54
GtkIconTheme *icon_theme;
55
GtkIconSize icon_size;
63
GtkIconSize icon_size;
66
static guint load_icons_id = 0;
67
static GHashTable *loaded_icons = NULL;
68
static GList *icons_to_load = NULL;
69
static GList *icons_to_add = NULL;
71
static GSList *image_menu_items = NULL;
73
static GtkWidget *populate_menu_from_directory (GtkWidget *menu,
74
GMenuTreeDirectory *directory);
76
static void panel_load_menu_image_deferred (GtkWidget *image_menu_item,
77
GtkIconSize icon_size,
80
const char *image_filename,
81
const char *fallback_image_filename);
84
add_menu_separator (GtkWidget *menu)
88
menuitem = gtk_separator_menu_item_new ();
89
gtk_widget_set_sensitive (menuitem, FALSE);
90
gtk_widget_show (menuitem);
91
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
97
activate_app_def (GtkWidget *menuitem,
98
GMenuTreeEntry *entry)
102
path = gmenu_tree_entry_get_desktop_file_path (entry);
103
panel_menu_item_activate_desktop_file (menuitem, path);
107
menu_get_panel (GtkWidget *menu)
109
PanelWidget *retval = NULL;
111
g_return_val_if_fail (menu != NULL, NULL);
113
if (GTK_IS_MENU_ITEM (menu))
114
menu = gtk_widget_get_parent (menu);
116
g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
119
retval = g_object_get_data (G_OBJECT (menu), "menu_panel");
123
menu = gtk_widget_get_parent (gtk_menu_get_attach_widget (GTK_MENU (menu)));
124
if (!GTK_IS_MENU (menu))
128
if (retval && !PANEL_IS_WIDGET (retval)) {
129
g_warning ("Invalid PanelWidget associated with menu");
134
g_warning ("Cannot find the PanelWidget associated with menu");
135
retval = panels->data;
142
setup_menu_panel (GtkWidget *menu)
146
panel = g_object_get_data (G_OBJECT (menu), "menu_panel");
150
panel = menu_get_panel (menu);
151
g_object_set_data (G_OBJECT (menu), "menu_panel", panel);
154
gtk_menu_set_screen (GTK_MENU (menu),
155
gtk_widget_get_screen (GTK_WIDGET (panel)));
159
menuitem_to_screen (GtkWidget *menuitem)
161
PanelWidget *panel_widget;
163
panel_widget = menu_get_panel (menuitem);
165
return gtk_window_get_screen (GTK_WINDOW (panel_widget->toplevel));
169
reload_image_menu_items (void)
173
for (l = image_menu_items; l; l = l->next) {
174
GtkWidget *image = l->data;
177
is_mapped = gtk_widget_get_mapped (image);
180
gtk_widget_unmap (image);
182
gtk_image_set_from_pixbuf (GTK_IMAGE (image), NULL);
185
gtk_widget_map (image);
191
icon_theme_changed (GtkIconTheme *icon_theme,
194
reload_image_menu_items ();
198
panel_create_menu (void)
201
GtkStyleContext *context;
202
static gboolean registered_icon_theme_changer = FALSE;
204
if (!registered_icon_theme_changer) {
205
registered_icon_theme_changer = TRUE;
207
g_signal_connect (gtk_icon_theme_get_default (), "changed",
208
G_CALLBACK (icon_theme_changed), NULL);
211
retval = gtk_menu_new ();
212
gtk_widget_set_name (retval, "gnome-panel-main-menu");
214
context = gtk_widget_get_style_context (retval);
215
gtk_style_context_add_class (context, "gnome-panel-main-menu");
221
create_empty_menu (void)
225
retval = panel_create_menu ();
227
g_signal_connect (retval, "show", G_CALLBACK (setup_menu_panel), NULL);
229
/* intercept all right button clicks makes sure they don't
230
go to the object itself */
231
g_signal_connect (retval, "button_press_event",
232
G_CALLBACK (menu_dummy_button_press_event), NULL);
238
icon_to_load_free (IconToLoad *icon)
244
g_object_unref (icon->pixmap);
248
g_object_unref (icon->gicon);
251
g_free (icon->image); icon->image = NULL;
252
g_free (icon->fallback_image); icon->fallback_image = NULL;
257
icon_to_load_copy (IconToLoad *icon)
264
retval = g_new0 (IconToLoad, 1);
266
retval->pixmap = g_object_ref (icon->pixmap);
268
retval->gicon = g_object_ref (icon->gicon);
270
retval->gicon = NULL;
271
retval->image = g_strdup (icon->image);
272
retval->fallback_image = g_strdup (icon->fallback_image);
273
retval->stock_id = icon->stock_id;
274
retval->icon_size = icon->icon_size;
280
remove_pixmap_from_loaded (gpointer data, GObject *where_the_object_was)
284
if (loaded_icons != NULL)
285
g_hash_table_remove (loaded_icons, key);
291
panel_make_menu_icon (GtkIconTheme *icon_theme,
293
const char *fallback,
295
gboolean *long_operation)
301
g_return_val_if_fail (size > 0, NULL);
305
file = panel_find_icon (icon_theme, icon, size);
306
if (file == NULL && fallback != NULL)
307
file = panel_find_icon (icon_theme, fallback, size);
312
if (long_operation != NULL)
313
*long_operation = TRUE;
319
key = g_strdup_printf ("%d:%s", size, file);
321
if (loaded_icons != NULL &&
322
(pb = g_hash_table_lookup (loaded_icons, key)) != NULL) {
324
g_object_ref (G_OBJECT (pb));
328
pb = gdk_pixbuf_new_from_file (file, NULL);
332
width = gdk_pixbuf_get_width (pb);
333
height = gdk_pixbuf_get_height (pb);
335
/* if we want 24 and we get 22, do nothing;
337
if (!(size - 2 <= width && width <= size &&
338
size - 2 <= height && height <= size)) {
341
tmp = gdk_pixbuf_scale_simple (pb, size, size,
342
GDK_INTERP_BILINEAR);
349
/* add icon to the hash table so we don't load it again */
360
(gdk_pixbuf_get_width (pb) != size &&
361
gdk_pixbuf_get_height (pb) != size)) {
368
width = gdk_pixbuf_get_width (pb);
369
height = gdk_pixbuf_get_height (pb);
371
if (height > width) {
372
dest_width = (size * width) / height;
376
dest_height = (size * height) / width;
379
pb2 = gdk_pixbuf_scale_simple (pb, dest_width, dest_height,
380
GDK_INTERP_BILINEAR);
381
g_object_unref (G_OBJECT (pb));
386
if (loaded_icons == NULL)
387
loaded_icons = g_hash_table_new_full
388
(g_str_hash, g_str_equal,
389
(GDestroyNotify) g_free,
390
(GDestroyNotify) g_object_unref);
391
g_hash_table_replace (loaded_icons,
393
g_object_ref (G_OBJECT (pb)));
394
g_object_weak_ref (G_OBJECT (pb),
395
(GWeakNotify) remove_pixmap_from_loaded,
398
/* we didn't load from disk */
399
if (long_operation != NULL)
400
*long_operation = FALSE;
410
menu_item_style_updated (GtkImage *image,
415
GtkIconSize icon_size = (GtkIconSize) GPOINTER_TO_INT (data);
419
if (!gtk_icon_size_lookup (icon_size, NULL, &icon_height))
422
pixbuf = gtk_image_get_pixbuf (image);
426
if (gdk_pixbuf_get_height (pixbuf) == icon_height)
429
widget = GTK_WIDGET (image);
431
is_mapped = gtk_widget_get_mapped (widget);
433
gtk_widget_unmap (widget);
435
gtk_image_set_from_pixbuf (image, NULL);
438
gtk_widget_map (widget);
442
do_icons_to_add (void)
444
while (icons_to_add) {
445
IconToAdd *icon_to_add = icons_to_add->data;
447
icons_to_add = g_list_delete_link (icons_to_add, icons_to_add);
449
if (icon_to_add->stock_id) {
450
gtk_image_set_from_stock (
451
GTK_IMAGE (icon_to_add->image),
452
icon_to_add->stock_id,
453
icon_to_add->icon_size);
454
} else if (icon_to_add->gicon) {
455
gtk_image_set_from_gicon (
456
GTK_IMAGE (icon_to_add->image),
458
icon_to_add->icon_size);
460
g_assert (icon_to_add->pixbuf);
462
gtk_image_set_from_pixbuf (
463
GTK_IMAGE (icon_to_add->image),
464
icon_to_add->pixbuf);
466
g_signal_connect (icon_to_add->image, "style-updated",
467
G_CALLBACK (menu_item_style_updated),
468
GINT_TO_POINTER (icon_to_add->icon_size));
470
g_object_unref (icon_to_add->pixbuf);
473
if (icon_to_add->gicon)
474
g_object_unref (icon_to_add->gicon);
475
g_object_unref (icon_to_add->image);
476
g_free (icon_to_add);
481
load_icons_handler (gpointer data)
484
gboolean long_operation = FALSE;
486
load_icons_handler_again:
488
if (!icons_to_load) {
495
icon = icons_to_load->data;
496
icons_to_load->data = NULL;
498
icons_to_load = g_list_delete_link (icons_to_load, icons_to_load);
500
/* if not visible anymore, just ignore */
501
if ( ! gtk_widget_get_visible (icon->pixmap)) {
502
icon_to_load_free (icon);
503
/* we didn't do anything long/hard, so just do this again,
504
* this is fun, don't go back to main loop */
505
goto load_icons_handler_again;
508
if (icon->stock_id || icon->gicon) {
509
IconToAdd *icon_to_add;
511
icon_to_add = g_new (IconToAdd, 1);
512
icon_to_add->image = g_object_ref (icon->pixmap);
513
icon_to_add->stock_id = icon->stock_id;
514
icon_to_add->pixbuf = NULL;
515
icon_to_add->icon_size = icon->icon_size;
517
icon_to_add->gicon = g_object_ref (icon->gicon);
519
icon_to_add->gicon = NULL;
521
icons_to_add = g_list_prepend (icons_to_add, icon_to_add);
523
IconToAdd *icon_to_add;
525
int icon_height = PANEL_DEFAULT_MENU_ICON_SIZE;
527
gtk_icon_size_lookup (icon->icon_size, NULL, &icon_height);
529
pb = panel_make_menu_icon (icon->icon_theme,
531
icon->fallback_image,
535
icon_to_load_free (icon);
537
/* this may have been a long operation so jump back to
538
* the main loop for a while */
541
/* we didn't do anything long/hard, so just do this again,
542
* this is fun, don't go back to main loop */
543
goto load_icons_handler_again;
546
icon_to_add = g_new (IconToAdd, 1);
547
icon_to_add->image = g_object_ref (icon->pixmap);
548
icon_to_add->stock_id = NULL;
549
icon_to_add->gicon = NULL;
550
icon_to_add->pixbuf = pb;
551
icon_to_add->icon_size = icon->icon_size;
553
icons_to_add = g_list_prepend (icons_to_add, icon_to_add);
556
icon_to_load_free (icon);
559
/* we didn't do anything long/hard, so just do this again,
560
* this is fun, don't go back to main loop */
561
goto load_icons_handler_again;
563
/* if still more we'll come back */
568
menu_dummy_button_press_event (GtkWidget *menuitem,
569
GdkEventButton *event)
571
if (event->button == 3)
578
drag_begin_menu_cb (GtkWidget *widget, GdkDragContext *context)
580
/* FIXME: workaround for a possible gtk+ bug
581
* See bugs #92085(gtk+) and #91184(panel) for details.
582
* Maybe it's not needed with GtkTooltip?
584
g_object_set (widget, "has-tooltip", FALSE, NULL);
587
/* This is a _horrible_ hack to have this here. This needs to be added to the
588
* GTK+ menuing code in some manner.
591
drag_end_menu_cb (GtkWidget *widget, GdkDragContext *context)
593
GtkWidget *xgrab_shell;
596
/* Find the last viewable ancestor, and make an X grab on it
598
parent = gtk_widget_get_parent (widget);
601
/* FIXME: workaround for a possible gtk+ bug
602
* See bugs #92085(gtk+) and #91184(panel) for details.
604
g_object_set (widget, "has-tooltip", TRUE, NULL);
608
gboolean viewable = TRUE;
609
GtkWidget *tmp = parent;
613
if (!gtk_widget_get_mapped (tmp))
618
tmp = gtk_widget_get_parent (tmp);
622
xgrab_shell = parent;
624
parent = gtk_menu_shell_get_parent_shell (GTK_MENU_SHELL (parent));
627
if (xgrab_shell && !gtk_menu_get_tearoff_state (GTK_MENU(xgrab_shell)))
633
GdkDeviceManager *device_manager;
634
GdkWindow *window = gtk_widget_get_window (xgrab_shell);
635
GdkCursor *cursor = gdk_cursor_new (GDK_ARROW);
637
display = gdk_window_get_display (window);
638
device_manager = gdk_display_get_device_manager (display);
639
pointer = gdk_device_manager_get_client_pointer (device_manager);
640
keyboard = gdk_device_get_associated_device (pointer);
642
/* FIXMEgpoo: Not sure if report to GDK_OWNERSHIP_WINDOW
643
or GDK_OWNERSHIP_APPLICATION. Idem for the
645
status = gdk_device_grab (pointer, window,
646
GDK_OWNERSHIP_WINDOW, TRUE,
647
GDK_BUTTON_PRESS_MASK
648
| GDK_BUTTON_RELEASE_MASK
649
| GDK_ENTER_NOTIFY_MASK
650
| GDK_LEAVE_NOTIFY_MASK
651
| GDK_POINTER_MOTION_MASK,
652
cursor, GDK_CURRENT_TIME);
656
if (gdk_device_grab (keyboard, window,
657
GDK_OWNERSHIP_WINDOW, TRUE,
658
GDK_KEY_PRESS | GDK_KEY_RELEASE,
659
NULL, GDK_CURRENT_TIME) == GDK_GRAB_SUCCESS)
661
/* FIXMEgpoo: We need either accessors or a workaround to grab
664
GTK_MENU_SHELL (xgrab_shell)->GSEAL(have_xgrab) = TRUE;
669
gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
673
g_object_unref (cursor);
678
drag_data_get_menu_cb (GtkWidget *widget,
679
GdkDragContext *context,
680
GtkSelectionData *selection_data,
683
GMenuTreeEntry *entry)
689
path = gmenu_tree_entry_get_desktop_file_path (entry);
690
uri = g_filename_to_uri (path, NULL, NULL);
691
uri_list = g_strconcat (uri, "\r\n", NULL);
694
gtk_selection_data_set (selection_data,
695
gtk_selection_data_get_target (selection_data), 8, (guchar *)uri_list,
701
image_menuitem_set_size_request (GtkWidget *menuitem,
702
GtkIconSize icon_size)
704
GtkStyleContext *context;
706
GtkBorder padding, border;
711
if (!gtk_icon_size_lookup (icon_size, NULL, &icon_height))
714
/* If we don't have a pixmap for this menuitem
715
* at least make sure its the same height as
717
* This is a bit ugly, since we should keep this in sync with what's in
718
* gtk_menu_item_size_request()
720
context = gtk_widget_get_style_context (menuitem);
721
state = gtk_widget_get_state_flags (menuitem);
722
gtk_style_context_get_padding (context, state, &padding);
723
gtk_style_context_get_border (context, state, &border);
725
border_width = gtk_container_get_border_width (GTK_CONTAINER (menuitem));
726
req_height = icon_height;
727
req_height += (border_width * 2) + padding.top + padding.bottom + border.top + border.bottom;
728
gtk_widget_set_size_request (menuitem, -1, req_height);
732
menu_escape_underscores_and_prepend (const char *text)
734
GString *escaped_text;
739
return g_strdup (text);
741
escaped_text = g_string_sized_new (strlen (text) + 1);
742
g_string_printf (escaped_text, "_%s", text);
750
c = g_utf8_get_char (src);
752
if (c == (gunichar)-1) {
753
g_warning ("Invalid input string for underscore escaping");
754
return g_strdup (text);
755
} else if (c == '_') {
756
g_string_insert_c (escaped_text,
757
src - text + inserted, '_');
761
src = g_utf8_next_char (src);
764
return g_string_free (escaped_text, FALSE);
768
setup_menuitem (GtkWidget *menuitem,
769
GtkIconSize icon_size,
777
/* this creates a label with an invisible mnemonic */
778
label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
779
_title = menu_escape_underscores_and_prepend (title);
780
gtk_label_set_text_with_mnemonic (GTK_LABEL (label), _title);
783
gtk_label_set_pattern (GTK_LABEL (label), "");
785
gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), menuitem);
787
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
788
gtk_widget_show (label);
790
gtk_container_add (GTK_CONTAINER (menuitem), label);
793
g_object_set_data_full (G_OBJECT (menuitem),
795
g_object_ref (image),
796
(GDestroyNotify) g_object_unref);
797
gtk_widget_show (image);
798
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem),
800
} else if (icon_size != GTK_ICON_SIZE_INVALID)
801
image_menuitem_set_size_request (menuitem, icon_size);
803
gtk_widget_show (menuitem);
807
drag_data_get_string_cb (GtkWidget *widget, GdkDragContext *context,
808
GtkSelectionData *selection_data, guint info,
809
guint time, const char *string)
811
gtk_selection_data_set (selection_data,
812
gtk_selection_data_get_target (selection_data), 8, (guchar *)string,
817
setup_uri_drag (GtkWidget *menuitem,
821
static GtkTargetEntry menu_item_targets[] = {
822
{ "text/uri-list", 0, 0 }
825
if (panel_lockdown_get_panels_locked_down_s ())
828
gtk_drag_source_set (menuitem,
829
GDK_BUTTON1_MASK|GDK_BUTTON2_MASK,
830
menu_item_targets, 1,
834
gtk_drag_source_set_icon_name (menuitem, icon);
836
g_signal_connect (G_OBJECT (menuitem), "drag_begin",
837
G_CALLBACK (drag_begin_menu_cb), NULL);
838
g_signal_connect_data (G_OBJECT (menuitem), "drag_data_get",
839
G_CALLBACK (drag_data_get_string_cb),
841
(GClosureNotify)g_free,
842
0 /* connect_flags */);
843
g_signal_connect (G_OBJECT (menuitem), "drag_end",
844
G_CALLBACK (drag_end_menu_cb), NULL);
848
setup_internal_applet_drag (GtkWidget *menuitem,
849
PanelActionButtonType type)
851
static GtkTargetEntry menu_item_targets[] = {
852
{ "application/x-panel-applet-internal", 0, 0 }
855
if (panel_lockdown_get_panels_locked_down_s ())
858
gtk_drag_source_set (menuitem,
859
GDK_BUTTON1_MASK|GDK_BUTTON2_MASK,
860
menu_item_targets, 1,
863
if (panel_action_get_icon_name (type) != NULL)
864
gtk_drag_source_set_icon_name (menuitem,
865
panel_action_get_icon_name (type));
867
g_signal_connect (G_OBJECT (menuitem), "drag_begin",
868
G_CALLBACK (drag_begin_menu_cb), NULL);
869
g_signal_connect_data (G_OBJECT (menuitem), "drag_data_get",
870
G_CALLBACK (drag_data_get_string_cb),
871
g_strdup (panel_action_get_drag_id (type)),
872
(GClosureNotify)g_free,
873
0 /* connect_flags */);
874
g_signal_connect (G_OBJECT (menuitem), "drag_end",
875
G_CALLBACK (drag_end_menu_cb), NULL);
879
submenu_to_display (GtkWidget *menu)
882
GMenuTreeDirectory *directory;
883
const char *menu_path;
884
void (*append_callback) (GtkWidget *, gpointer);
885
gpointer append_data;
887
if (!g_object_get_data (G_OBJECT (menu), "panel-menu-needs-loading"))
890
g_object_set_data (G_OBJECT (menu), "panel-menu-needs-loading", NULL);
892
directory = g_object_get_data (G_OBJECT (menu),
893
"panel-menu-tree-directory");
895
menu_path = g_object_get_data (G_OBJECT (menu),
896
"panel-menu-tree-path");
900
tree = g_object_get_data (G_OBJECT (menu), "panel-menu-tree");
904
directory = gmenu_tree_get_directory_from_path (tree,
907
g_object_set_data_full (G_OBJECT (menu),
908
"panel-menu-tree-directory",
910
(GDestroyNotify) gmenu_tree_item_unref);
914
populate_menu_from_directory (menu, directory);
916
append_callback = g_object_get_data (G_OBJECT (menu),
917
"panel-menu-append-callback");
918
append_data = g_object_get_data (G_OBJECT (menu),
919
"panel-menu-append-callback-data");
921
append_callback (menu, append_data);
925
submenu_to_display_in_idle (gpointer data)
927
GtkWidget *menu = GTK_WIDGET (data);
929
g_object_set_data (G_OBJECT (menu), "panel-menu-idle-id", NULL);
931
submenu_to_display (menu);
937
remove_submenu_to_display_idle (gpointer data)
939
guint idle_id = GPOINTER_TO_UINT (data);
941
g_source_remove (idle_id);
945
create_fake_menu (GMenuTreeDirectory *directory)
950
menu = create_empty_menu ();
952
g_object_set_data_full (G_OBJECT (menu),
953
"panel-menu-tree-directory",
954
gmenu_tree_item_ref (directory),
955
(GDestroyNotify) gmenu_tree_item_unref);
957
g_object_set_data (G_OBJECT (menu),
958
"panel-menu-needs-loading",
959
GUINT_TO_POINTER (TRUE));
961
g_signal_connect (menu, "show",
962
G_CALLBACK (submenu_to_display), NULL);
964
idle_id = g_idle_add_full (G_PRIORITY_LOW,
965
submenu_to_display_in_idle,
968
g_object_set_data_full (G_OBJECT (menu),
969
"panel-menu-idle-id",
970
GUINT_TO_POINTER (idle_id),
971
remove_submenu_to_display_idle);
973
g_signal_connect (menu, "button_press_event",
974
G_CALLBACK (menu_dummy_button_press_event), NULL);
980
panel_image_menu_item_new (void)
983
GtkStyleContext *context;
985
menuitem = gtk_image_menu_item_new ();
986
gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menuitem),
988
context = gtk_widget_get_style_context (menuitem);
989
gtk_style_context_add_class (context, "gnome-panel-menu-item");
995
create_submenu_entry (GtkWidget *menu,
996
GMenuTreeDirectory *directory)
999
gboolean force_categories_icon;
1001
force_categories_icon = g_object_get_data (G_OBJECT (menu),
1002
"panel-menu-force-icon-for-categories") != NULL;
1004
if (force_categories_icon)
1005
menuitem = panel_image_menu_item_new ();
1007
menuitem = gtk_image_menu_item_new ();
1009
panel_load_menu_image_deferred (menuitem,
1010
panel_menu_icon_get_size (),
1012
gmenu_tree_directory_get_icon (directory),
1015
setup_menuitem (menuitem,
1016
panel_menu_icon_get_size (),
1018
gmenu_tree_directory_get_name (directory));
1020
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1022
gtk_widget_show (menuitem);
1028
create_submenu (GtkWidget *menu,
1029
GMenuTreeDirectory *directory,
1030
GMenuTreeDirectory *alias_directory)
1032
GtkWidget *menuitem;
1034
gboolean force_categories_icon;
1036
if (alias_directory)
1037
menuitem = create_submenu_entry (menu, alias_directory);
1039
menuitem = create_submenu_entry (menu, directory);
1041
submenu = create_fake_menu (directory);
1043
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
1045
/* Keep the infor that we force (or not) the icons to be visible */
1046
force_categories_icon = g_object_get_data (G_OBJECT (menu),
1047
"panel-menu-force-icon-for-categories") != NULL;
1048
g_object_set_data (G_OBJECT (submenu),
1049
"panel-menu-force-icon-for-categories",
1050
GINT_TO_POINTER (force_categories_icon));
1054
create_header (GtkWidget *menu,
1055
GMenuTreeHeader *header)
1057
GMenuTreeDirectory *directory;
1058
GtkWidget *menuitem;
1060
directory = gmenu_tree_header_get_directory (header);
1061
menuitem = create_submenu_entry (menu, directory);
1062
gmenu_tree_item_unref (directory);
1064
g_signal_connect (menuitem, "activate",
1065
G_CALLBACK (gtk_false), NULL);
1069
create_menuitem (GtkWidget *menu,
1070
GMenuTreeEntry *entry,
1071
GMenuTreeDirectory *alias_directory)
1073
GtkWidget *menuitem;
1075
menuitem = panel_image_menu_item_new ();
1077
panel_load_menu_image_deferred (menuitem,
1078
panel_menu_icon_get_size (),
1080
alias_directory ? gmenu_tree_directory_get_icon (alias_directory) :
1081
gmenu_tree_entry_get_icon (entry),
1084
setup_menuitem (menuitem,
1085
panel_menu_icon_get_size (),
1087
alias_directory ? gmenu_tree_directory_get_name (alias_directory) :
1088
gmenu_tree_entry_get_display_name (entry));
1090
if (alias_directory &&
1091
gmenu_tree_directory_get_comment (alias_directory))
1092
panel_util_set_tooltip_text (menuitem,
1093
gmenu_tree_directory_get_comment (alias_directory));
1094
else if (!alias_directory &&
1095
gmenu_tree_entry_get_comment (entry))
1096
panel_util_set_tooltip_text (menuitem,
1097
gmenu_tree_entry_get_comment (entry));
1098
else if (!alias_directory &&
1099
gmenu_tree_entry_get_generic_name (entry))
1100
panel_util_set_tooltip_text (menuitem,
1101
gmenu_tree_entry_get_generic_name (entry));
1103
g_signal_connect_after (menuitem, "button_press_event",
1104
G_CALLBACK (menu_dummy_button_press_event), NULL);
1106
if (!panel_lockdown_get_panels_locked_down_s ()) {
1107
static GtkTargetEntry menu_item_targets[] = {
1108
{ "text/uri-list", 0, 0 }
1111
gtk_drag_source_set (menuitem,
1112
GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
1113
menu_item_targets, 1,
1116
if (gmenu_tree_entry_get_icon (entry) != NULL) {
1120
icon = gmenu_tree_entry_get_icon (entry);
1121
if (!g_path_is_absolute (icon)) {
1122
icon_no_ext = panel_xdg_icon_remove_extension (icon);
1123
gtk_drag_source_set_icon_name (menuitem,
1125
g_free (icon_no_ext);
1129
g_signal_connect (G_OBJECT (menuitem), "drag_begin",
1130
G_CALLBACK (drag_begin_menu_cb), NULL);
1131
g_signal_connect (menuitem, "drag_data_get",
1132
G_CALLBACK (drag_data_get_menu_cb), entry);
1133
g_signal_connect (menuitem, "drag_end",
1134
G_CALLBACK (drag_end_menu_cb), NULL);
1137
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1139
g_signal_connect (menuitem, "activate",
1140
G_CALLBACK (activate_app_def), entry);
1142
gtk_widget_show (menuitem);
1146
create_menuitem_from_alias (GtkWidget *menu,
1147
GMenuTreeAlias *alias)
1149
GMenuTreeItem *aliased_item;
1151
aliased_item = gmenu_tree_alias_get_item (alias);
1153
switch (gmenu_tree_item_get_type (aliased_item)) {
1154
case GMENU_TREE_ITEM_DIRECTORY:
1155
create_submenu (menu,
1156
GMENU_TREE_DIRECTORY (aliased_item),
1157
gmenu_tree_alias_get_directory (alias));
1160
case GMENU_TREE_ITEM_ENTRY:
1161
create_menuitem (menu,
1162
GMENU_TREE_ENTRY (aliased_item),
1163
gmenu_tree_alias_get_directory (alias));
1170
gmenu_tree_item_unref (aliased_item);
1174
handle_gmenu_tree_changed (GMenuTree *tree,
1180
/* Remove existing items */
1181
list = gtk_container_get_children (GTK_CONTAINER (menu));
1182
for (l = list; l; l = l->next)
1183
gtk_widget_destroy (l->data);
1186
g_object_set_data_full (G_OBJECT (menu),
1187
"panel-menu-tree-directory",
1190
g_object_set_data (G_OBJECT (menu),
1191
"panel-menu-needs-loading",
1192
GUINT_TO_POINTER (TRUE));
1194
idle_id = g_idle_add_full (G_PRIORITY_LOW,
1195
submenu_to_display_in_idle,
1198
g_object_set_data_full (G_OBJECT (menu),
1199
"panel-menu-idle-id",
1200
GUINT_TO_POINTER (idle_id),
1201
remove_submenu_to_display_idle);
1205
remove_gmenu_tree_monitor (GtkWidget *menu,
1208
gmenu_tree_remove_monitor (tree,
1209
(GMenuTreeChangedFunc) handle_gmenu_tree_changed,
1214
create_applications_menu (const char *menu_file,
1215
const char *menu_path,
1216
gboolean always_show_image)
1222
menu = create_empty_menu ();
1224
if (always_show_image)
1225
g_object_set_data (G_OBJECT (menu),
1226
"panel-menu-force-icon-for-categories",
1227
GINT_TO_POINTER (TRUE));
1229
tree = gmenu_tree_lookup (menu_file, GMENU_TREE_FLAGS_NONE);
1230
gmenu_tree_set_sort_key (tree, GMENU_TREE_SORT_DISPLAY_NAME);
1232
g_object_set_data_full (G_OBJECT (menu),
1234
gmenu_tree_ref (tree),
1235
(GDestroyNotify) gmenu_tree_unref);
1237
g_object_set_data_full (G_OBJECT (menu),
1238
"panel-menu-tree-path",
1239
g_strdup (menu_path ? menu_path : "/"),
1240
(GDestroyNotify) g_free);
1242
g_object_set_data (G_OBJECT (menu),
1243
"panel-menu-needs-loading",
1244
GUINT_TO_POINTER (TRUE));
1246
g_signal_connect (menu, "show",
1247
G_CALLBACK (submenu_to_display), NULL);
1249
idle_id = g_idle_add_full (G_PRIORITY_LOW,
1250
submenu_to_display_in_idle,
1253
g_object_set_data_full (G_OBJECT (menu),
1254
"panel-menu-idle-id",
1255
GUINT_TO_POINTER (idle_id),
1256
remove_submenu_to_display_idle);
1258
g_signal_connect (menu, "button_press_event",
1259
G_CALLBACK (menu_dummy_button_press_event), NULL);
1261
gmenu_tree_add_monitor (tree,
1262
(GMenuTreeChangedFunc) handle_gmenu_tree_changed,
1264
g_signal_connect (menu, "destroy",
1265
G_CALLBACK (remove_gmenu_tree_monitor), tree);
1267
gmenu_tree_unref (tree);
1273
populate_menu_from_directory (GtkWidget *menu,
1274
GMenuTreeDirectory *directory)
1279
gboolean add_separator;
1281
children = gtk_container_get_children (GTK_CONTAINER (menu));
1282
add_separator = (children != NULL);
1283
g_list_free (children);
1285
items = gmenu_tree_directory_get_contents (directory);
1287
for (l = items; l; l = l->next) {
1288
GMenuTreeItem *item = l->data;
1290
if (add_separator ||
1291
gmenu_tree_item_get_type (item) == GMENU_TREE_ITEM_SEPARATOR) {
1292
add_menu_separator (menu);
1293
add_separator = FALSE;
1296
switch (gmenu_tree_item_get_type (item)) {
1297
case GMENU_TREE_ITEM_DIRECTORY:
1298
create_submenu (menu, GMENU_TREE_DIRECTORY (item), NULL);
1301
case GMENU_TREE_ITEM_ENTRY:
1302
create_menuitem (menu, GMENU_TREE_ENTRY (item), NULL);
1305
case GMENU_TREE_ITEM_SEPARATOR :
1309
case GMENU_TREE_ITEM_ALIAS:
1310
create_menuitem_from_alias (menu, GMENU_TREE_ALIAS (item));
1313
case GMENU_TREE_ITEM_HEADER:
1314
create_header (menu, GMENU_TREE_HEADER (item));
1321
gmenu_tree_item_unref (item);
1324
g_slist_free (items);
1330
setup_menu_item_with_icon (GtkWidget *item,
1331
GtkIconSize icon_size,
1332
const char *icon_name,
1333
const char *stock_id,
1337
if (icon_name || gicon || stock_id)
1338
panel_load_menu_image_deferred (item, icon_size,
1342
setup_menuitem (item, icon_size, NULL, title);
1346
main_menu_append (GtkWidget *main_menu,
1351
gboolean add_separator;
1355
panel = PANEL_WIDGET (data);
1357
add_separator = FALSE;
1358
children = gtk_container_get_children (GTK_CONTAINER (main_menu));
1359
last = g_list_last (children);
1361
add_separator = !GTK_IS_SEPARATOR (GTK_WIDGET (last->data));
1363
g_list_free (children);
1366
add_menu_separator (main_menu);
1368
item = panel_place_menu_item_new (TRUE);
1369
panel_place_menu_item_set_panel (item, panel);
1370
gtk_menu_shell_append (GTK_MENU_SHELL (main_menu), item);
1371
gtk_widget_show (item);
1373
item = panel_desktop_menu_item_new (TRUE, FALSE);
1374
panel_desktop_menu_item_set_panel (item, panel);
1375
gtk_menu_shell_append (GTK_MENU_SHELL (main_menu), item);
1376
gtk_widget_show (item);
1378
panel_menu_items_append_lock_logout (main_menu);
1382
create_main_menu (PanelWidget *panel)
1384
GtkWidget *main_menu;
1386
main_menu = create_applications_menu ("applications.menu", NULL, TRUE);
1388
g_object_set_data (G_OBJECT (main_menu), "menu_panel", panel);
1389
/* FIXME need to update the panel on parent_set */
1391
g_object_set_data (G_OBJECT (main_menu),
1392
"panel-menu-append-callback",
1394
g_object_set_data (G_OBJECT (main_menu),
1395
"panel-menu-append-callback-data",
1402
find_in_load_list (GtkWidget *image)
1405
for (li = icons_to_load; li != NULL; li = li->next) {
1406
IconToLoad *icon = li->data;
1407
if (icon->pixmap == image)
1414
image_menu_shown (GtkWidget *image, gpointer data)
1416
IconToLoad *new_icon;
1419
icon = (IconToLoad *) data;
1421
/* if we've already handled this */
1422
if (gtk_image_get_storage_type (GTK_IMAGE (image)) != GTK_IMAGE_EMPTY)
1425
if (find_in_load_list (image) == NULL) {
1426
new_icon = icon_to_load_copy (icon);
1427
new_icon->icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (image));
1428
icons_to_load = g_list_append (icons_to_load, new_icon);
1430
if (load_icons_id == 0)
1431
load_icons_id = g_idle_add (load_icons_handler, NULL);
1435
image_menu_destroy (GtkWidget *image, gpointer data)
1437
image_menu_items = g_slist_remove (image_menu_items, image);
1441
panel_load_menu_image_deferred (GtkWidget *image_menu_item,
1442
GtkIconSize icon_size,
1443
const char *stock_id,
1445
const char *image_filename,
1446
const char *fallback_image_filename)
1450
int icon_height = PANEL_DEFAULT_MENU_ICON_SIZE;
1452
icon = g_new (IconToLoad, 1);
1454
gtk_icon_size_lookup (icon_size, NULL, &icon_height);
1456
image = gtk_image_new ();
1457
gtk_widget_set_size_request (image, icon_height, icon_height);
1459
/* this takes over the floating ref */
1460
icon->pixmap = g_object_ref_sink (G_OBJECT (image));
1462
icon->stock_id = stock_id;
1464
icon->gicon = g_object_ref (gicon);
1467
icon->image = g_strdup (image_filename);
1468
icon->fallback_image = g_strdup (fallback_image_filename);
1469
icon->icon_size = icon_size;
1471
gtk_widget_show (image);
1473
g_object_set_data_full (G_OBJECT (image_menu_item),
1475
g_object_ref (image),
1476
(GDestroyNotify) g_object_unref);
1478
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (image_menu_item),
1481
g_signal_connect_data (image, "map",
1482
G_CALLBACK (image_menu_shown), icon,
1483
(GClosureNotify) icon_to_load_free, 0);
1485
g_signal_connect (image, "destroy",
1486
G_CALLBACK (image_menu_destroy), NULL);
1488
image_menu_items = g_slist_prepend (image_menu_items, image);