1
/* Gnome panel: general applet functionality
2
* (C) 1997 the Free Software Foundation
14
#include <glib/gi18n.h>
17
#include <libpanel-util/panel-show.h>
19
#include "button-widget.h"
22
#include "panel-addto.h"
23
#include "panel-gconf.h"
24
#include "panel-config-global.h"
25
#include "panel-applet-frame.h"
26
#include "panel-action-button.h"
27
#include "panel-menu-bar.h"
28
#include "panel-separator.h"
29
#include "panel-compatibility.h"
30
#include "panel-toplevel.h"
31
#include "panel-util.h"
32
#include "panel-profile.h"
33
#include "panel-menu-button.h"
34
#include "panel-globals.h"
35
#include "panel-properties-dialog.h"
36
#include "panel-lockdown.h"
38
#define SMALL_ICON_SIZE 20
40
static GSList *registered_applets = NULL;
41
static GSList *queued_position_saves = NULL;
42
static guint queued_position_source = 0;
45
static inline PanelWidget *
46
panel_applet_get_panel_widget (AppletInfo *info)
48
return PANEL_WIDGET (gtk_widget_get_parent (info->widget));
52
panel_applet_set_dnd_enabled (AppletInfo *info,
56
case PANEL_OBJECT_DRAWER:
57
panel_drawer_set_dnd_enabled (info->data, dnd_enabled);
59
case PANEL_OBJECT_MENU:
60
panel_menu_button_set_dnd_enabled (PANEL_MENU_BUTTON (info->widget),
63
case PANEL_OBJECT_LAUNCHER:
64
panel_launcher_set_dnd_enabled (info->data, dnd_enabled);
66
case PANEL_OBJECT_APPLET:
68
case PANEL_OBJECT_LOGOUT:
69
case PANEL_OBJECT_LOCK:
70
case PANEL_OBJECT_ACTION:
71
panel_action_button_set_dnd_enabled (PANEL_ACTION_BUTTON (info->widget),
74
case PANEL_OBJECT_MENU_BAR:
75
case PANEL_OBJECT_SEPARATOR:
78
g_assert_not_reached ();
85
panel_applet_toggle_locked (AppletInfo *info)
87
PanelWidget *panel_widget;
90
panel_widget = panel_applet_get_panel_widget (info);
92
locked = panel_widget_toggle_applet_locked (panel_widget, info->widget);
94
panel_applet_save_position (info, info->id, TRUE);
95
panel_applet_set_dnd_enabled (info, !locked);
101
panel_applet_lock (GtkCheckMenuItem *menuitem,
106
locked = panel_applet_toggle_locked (info);
108
gtk_check_menu_item_set_active (menuitem, locked);
111
gtk_widget_set_sensitive (info->move_item, !locked);
115
move_applet_callback (GtkWidget *widget, AppletInfo *info)
120
g_return_if_fail (info != NULL);
121
g_return_if_fail (info->widget != NULL);
123
parent = gtk_widget_get_parent (info->widget);
125
g_return_if_fail (parent != NULL);
126
g_return_if_fail (PANEL_IS_WIDGET (parent));
128
panel = PANEL_WIDGET (parent);
130
panel_widget_applet_drag_start (panel, info->widget,
135
/* permanently remove an applet - all non-permanent
136
* cleanups should go in panel_applet_destroy()
139
panel_applet_clean (AppletInfo *info)
141
g_return_if_fail (info != NULL);
143
if (info->type == PANEL_OBJECT_LAUNCHER)
144
panel_launcher_delete (info->data);
147
GtkWidget *widget = info->widget;
150
gtk_widget_destroy (widget);
155
panel_applet_recreate_menu (AppletInfo *info)
162
for (l = info->user_menu; l; l = l->next) {
163
AppletUserMenu *menu = l->data;
165
menu->menuitem =NULL;
169
g_object_unref (info->menu);
170
info->menu = panel_applet_create_menu (info);
174
panel_applet_locked_change_notify (GConfClient *client,
181
gboolean applet_locked;
183
PanelWidget *panel_widget;
185
g_assert (applet != NULL);
187
info = (AppletInfo *) g_object_get_data (G_OBJECT (applet),
192
value = gconf_entry_get_value (entry);
193
if (value == NULL || value->type != GCONF_VALUE_BOOL)
196
locked = gconf_value_get_bool (value);
198
panel_widget = panel_applet_get_panel_widget (info);
199
applet_locked = panel_widget_get_applet_locked (panel_widget,
202
if ((locked && applet_locked) || !(locked || applet_locked))
205
panel_applet_toggle_locked (info);
207
if (info->type == PANEL_OBJECT_APPLET)
208
panel_applet_frame_sync_menu_state (PANEL_APPLET_FRAME (info->widget));
210
panel_applet_recreate_menu (info);
214
applet_remove_callback (GtkWidget *widget,
218
if (info->type == PANEL_OBJECT_DRAWER)
219
drawer_query_deletion (info->data);
221
panel_profile_delete_object (info);
224
static inline GdkScreen *
225
applet_user_menu_get_screen (AppletUserMenu *menu)
227
PanelWidget *panel_widget;
229
panel_widget = panel_applet_get_panel_widget (menu->info);
231
return gtk_window_get_screen (GTK_WINDOW (panel_widget->toplevel));
235
applet_callback_callback (GtkWidget *widget,
236
AppletUserMenu *menu)
240
g_return_if_fail (menu->info != NULL);
242
screen = applet_user_menu_get_screen (menu);
244
switch (menu->info->type) {
245
case PANEL_OBJECT_LAUNCHER:
246
if (!strcmp (menu->name, "launch"))
247
launcher_launch (menu->info->data, widget);
248
else if (!strcmp (menu->name, "properties"))
249
launcher_properties (menu->info->data);
251
case PANEL_OBJECT_DRAWER:
252
if (strcmp (menu->name, "add") == 0) {
253
Drawer *drawer = menu->info->data;
255
panel_addto_present (GTK_MENU_ITEM (widget),
256
panel_toplevel_get_panel_widget (drawer->toplevel));
257
} else if (strcmp (menu->name, "properties") == 0) {
258
Drawer *drawer = menu->info->data;
260
panel_properties_dialog_present (drawer->toplevel);
261
} else if (strcmp (menu->name, "help") == 0) {
262
panel_show_help (screen,
263
"user-guide", "gospanel-18", NULL);
266
case PANEL_OBJECT_MENU:
267
panel_menu_button_invoke_menu (
268
PANEL_MENU_BUTTON (menu->info->widget), menu->name);
270
case PANEL_OBJECT_ACTION:
271
case PANEL_OBJECT_LOGOUT:
272
case PANEL_OBJECT_LOCK:
273
panel_action_button_invoke_menu (
274
PANEL_ACTION_BUTTON (menu->info->widget), menu->name);
276
case PANEL_OBJECT_MENU_BAR:
277
panel_menu_bar_invoke_menu (
278
PANEL_MENU_BAR (menu->info->widget), menu->name);
281
case PANEL_OBJECT_APPLET:
283
* Applet's menu's are handled differently
286
case PANEL_OBJECT_SEPARATOR:
289
g_assert_not_reached ();
295
applet_menu_show (GtkWidget *w,
298
PanelWidget *panel_widget;
300
panel_widget = panel_applet_get_panel_widget (info);
302
panel_toplevel_push_autohide_disabler (panel_widget->toplevel);
307
applet_menu_deactivate (GtkWidget *w,
310
PanelWidget *panel_widget;
312
panel_widget = panel_applet_get_panel_widget (info);
314
panel_toplevel_pop_autohide_disabler (panel_widget->toplevel);
318
panel_applet_get_callback (GList *user_menu,
323
for (l = user_menu; l; l = l->next) {
324
AppletUserMenu *menu = l->data;
326
if (strcmp (menu->name, name) == 0)
334
panel_applet_add_callback (AppletInfo *info,
335
const char *callback_name,
336
const char *stock_item,
337
const char *menuitem_text,
338
CallbackEnabledFunc is_enabled_func)
340
AppletUserMenu *menu;
342
g_return_if_fail (info != NULL);
343
g_return_if_fail (panel_applet_get_callback (info->user_menu,
344
callback_name) == NULL);
346
menu = g_new0 (AppletUserMenu, 1);
347
menu->name = g_strdup (callback_name);
348
menu->stock_item = g_strdup (stock_item);
349
menu->text = g_strdup (menuitem_text);
350
menu->is_enabled_func = is_enabled_func;
351
menu->sensitive = TRUE;
353
menu->menuitem = NULL;
354
menu->submenu = NULL;
356
info->user_menu = g_list_append (info->user_menu, menu);
358
panel_applet_recreate_menu (info);
362
setup_an_item (AppletUserMenu *menu,
366
GtkWidget *image = NULL;
368
menu->menuitem = gtk_image_menu_item_new_with_mnemonic (menu->text);
369
if (menu->stock_item && menu->stock_item [0]) {
370
image = gtk_image_new_from_stock (menu->stock_item,
372
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu->menuitem),
375
gtk_widget_show (menu->menuitem);
377
g_signal_connect (G_OBJECT (menu->menuitem), "destroy",
378
G_CALLBACK (gtk_widget_destroyed),
382
gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menu->menuitem);
384
/*if an item not a submenu*/
386
g_signal_connect (menu->menuitem, "activate",
387
G_CALLBACK (applet_callback_callback),
389
g_signal_connect (submenu, "destroy",
390
G_CALLBACK (gtk_widget_destroyed),
392
/* if the item is a submenu and doesn't have it's menu
394
} else if (!menu->submenu) {
395
menu->submenu = gtk_menu_new ();
399
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu->menuitem),
401
g_signal_connect (G_OBJECT (menu->submenu), "destroy",
402
G_CALLBACK (gtk_widget_destroyed),
406
gtk_widget_set_sensitive(menu->menuitem,menu->sensitive);
410
add_to_submenus (AppletInfo *info,
413
AppletUserMenu *menu,
417
char *n = g_strdup (name);
418
char *p = strchr (n, '/');
420
AppletUserMenu *s_menu;
422
/*this is the last one*/
425
setup_an_item (menu, submenu, FALSE);
429
/*this is the last one and we are a submenu, we have already been
431
if(p==(n + strlen(n) - 1)) {
439
t = g_strconcat (path, n, "/", NULL);
440
s_menu = panel_applet_get_callback (user_menu, t);
441
/*the user did not give us this sub menu, whoops, will create an empty
443
if (s_menu == NULL) {
444
s_menu = g_new0 (AppletUserMenu,1);
445
s_menu->name = g_strdup (t);
446
s_menu->stock_item = NULL;
447
s_menu->text = g_strdup (_("???"));
448
s_menu->sensitive = TRUE;
450
s_menu->menuitem = NULL;
451
s_menu->submenu = NULL;
452
info->user_menu = g_list_append (info->user_menu,s_menu);
453
user_menu = info->user_menu;
456
if (s_menu->submenu == NULL) {
457
s_menu->submenu = gtk_menu_new ();
458
/*a more elegant way to do this should be done
459
when I don't want to go to sleep */
460
if (s_menu->menuitem != NULL) {
461
gtk_widget_destroy (s_menu->menuitem);
462
s_menu->menuitem = NULL;
465
if (s_menu->menuitem == NULL)
466
setup_an_item (s_menu, submenu, TRUE);
468
add_to_submenus (info, t, p, menu, s_menu->submenu, user_menu);
475
panel_applet_create_menu (AppletInfo *info)
480
PanelWidget *panel_widget;
481
gboolean added_anything = FALSE;
483
panel_widget = panel_applet_get_panel_widget (info);
485
menu = g_object_ref_sink (gtk_menu_new ());
487
/* connect the show & deactivate signal, so that we can "disallow" and
488
* "re-allow" autohide when the menu is shown/deactivated.
490
g_signal_connect (menu, "show",
491
G_CALLBACK (applet_menu_show), info);
492
g_signal_connect (menu, "deactivate",
493
G_CALLBACK (applet_menu_deactivate), info);
495
for (l = info->user_menu; l; l = l->next) {
496
AppletUserMenu *user_menu = l->data;
498
if (user_menu->is_enabled_func && !user_menu->is_enabled_func ())
501
add_to_submenus (info, "", user_menu->name, user_menu,
502
menu, info->user_menu);
504
added_anything = TRUE;
507
if (!panel_lockdown_get_locked_down ()) {
514
lockable = panel_applet_lockable (info);
515
movable = panel_applet_can_freely_move (info);
516
removable = panel_profile_id_lists_are_writable ();
518
locked = panel_widget_get_applet_locked (panel_widget, info->widget);
520
if (added_anything) {
521
menuitem = gtk_separator_menu_item_new ();
522
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
523
gtk_widget_show (menuitem);
526
menuitem = gtk_image_menu_item_new_with_mnemonic (_("_Remove From Panel"));
527
image = gtk_image_new_from_stock (GTK_STOCK_REMOVE,
529
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem),
531
g_signal_connect (menuitem, "activate",
532
G_CALLBACK (applet_remove_callback), info);
533
gtk_widget_show (menuitem);
534
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
535
gtk_widget_set_sensitive (menuitem, (!locked || lockable) && removable);
537
menuitem = gtk_menu_item_new_with_mnemonic (_("_Move"));
538
g_signal_connect (menuitem, "activate",
539
G_CALLBACK (move_applet_callback), info);
540
gtk_widget_show (menuitem);
541
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
542
gtk_widget_set_sensitive (menuitem, !locked && movable);
544
g_assert (info->move_item == NULL);
546
info->move_item = menuitem;
547
g_object_add_weak_pointer (G_OBJECT (menuitem),
548
(gpointer *) &info->move_item);
550
menuitem = gtk_separator_menu_item_new ();
551
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
552
gtk_widget_show (menuitem);
554
menuitem = gtk_check_menu_item_new_with_mnemonic (_("Loc_k To Panel"));
555
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem),
557
g_signal_connect (menuitem, "toggled",
558
G_CALLBACK (panel_applet_lock), info);
559
gtk_widget_show (menuitem);
560
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
561
gtk_widget_set_sensitive (menuitem, lockable);
563
added_anything = TRUE;
566
if ( ! added_anything) {
567
g_object_unref (menu);
575
panel_applet_menu_set_recurse (GtkMenu *menu,
582
g_object_set_data (G_OBJECT (menu), key, data);
584
children = gtk_container_get_children (GTK_CONTAINER (menu));
586
for (l = children; l; l = l->next) {
587
GtkWidget *submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (l->data));
590
panel_applet_menu_set_recurse (
591
GTK_MENU (submenu), key, data);
594
g_list_free (children);
598
panel_applet_position_menu (GtkMenu *menu,
604
GtkAllocation allocation;
605
GtkRequisition requisition;
613
parent = gtk_widget_get_parent (applet);
615
g_return_if_fail (PANEL_IS_WIDGET (parent));
617
screen = gtk_widget_get_screen (applet);
619
gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
621
gdk_window_get_origin (gtk_widget_get_window (applet), &menu_x, &menu_y);
622
gtk_widget_get_pointer (applet, &pointer_x, &pointer_y);
624
gtk_widget_get_allocation (applet, &allocation);
626
if (!gtk_widget_get_has_window (applet)) {
627
menu_x += allocation.x;
628
menu_y += allocation.y;
631
if (PANEL_WIDGET (parent)->orient == GTK_ORIENTATION_HORIZONTAL) {
632
if (gtk_widget_get_direction (GTK_WIDGET (menu)) != GTK_TEXT_DIR_RTL) {
633
if (pointer_x < allocation.width &&
634
requisition.width < pointer_x)
635
menu_x += MIN (pointer_x,
636
allocation.width - requisition.width);
638
menu_x += allocation.width - requisition.width;
639
if (pointer_x > 0 && pointer_x < allocation.width &&
640
pointer_x < allocation.width - requisition.width) {
641
menu_x -= MIN (allocation.width - pointer_x,
642
allocation.width - requisition.width);
645
menu_x = MIN (menu_x, gdk_screen_get_width (screen) - requisition.width);
647
if (menu_y > gdk_screen_get_height (screen) / 2)
648
menu_y -= requisition.height;
650
menu_y += allocation.height;
652
if (pointer_y < allocation.height &&
653
requisition.height < pointer_y)
654
menu_y += MIN (pointer_y, allocation.height - requisition.height);
655
menu_y = MIN (menu_y, gdk_screen_get_height (screen) - requisition.height);
657
if (menu_x > gdk_screen_get_width (screen) / 2)
658
menu_x -= requisition.width;
660
menu_x += allocation.width;
669
applet_show_menu (AppletInfo *info,
670
GdkEventButton *event)
672
PanelWidget *panel_widget;
674
g_return_if_fail (info != NULL);
676
panel_widget = panel_applet_get_panel_widget (info);
678
if (info->menu == NULL)
679
info->menu = panel_applet_create_menu (info);
681
if (info->menu == NULL)
684
panel_applet_menu_set_recurse (GTK_MENU (info->menu),
688
gtk_menu_set_screen (GTK_MENU (info->menu),
689
gtk_window_get_screen (GTK_WINDOW (panel_widget->toplevel)));
691
if (!gtk_widget_get_realized (info->menu))
692
gtk_widget_show (info->menu);
694
gtk_menu_popup (GTK_MENU (info->menu),
697
(GtkMenuPositionFunc) panel_applet_position_menu,
704
applet_do_popup_menu (GtkWidget *widget,
705
GdkEventButton *event,
708
if (panel_applet_is_in_drag ())
711
if (info->type == PANEL_OBJECT_APPLET)
714
applet_show_menu (info, event);
720
applet_popup_menu (GtkWidget *widget,
723
GdkEventButton event;
726
event.time = GDK_CURRENT_TIME;
728
return applet_do_popup_menu (widget, &event, info);
732
applet_button_press (GtkWidget *widget,
733
GdkEventButton *event,
736
if (event->button == 3)
737
return applet_do_popup_menu (widget, event, info);
743
panel_applet_destroy (GtkWidget *widget,
748
g_return_if_fail (info != NULL);
752
registered_applets = g_slist_remove (registered_applets, info);
754
queued_position_saves =
755
g_slist_remove (queued_position_saves, info);
757
if (info->type == PANEL_OBJECT_DRAWER) {
758
Drawer *drawer = info->data;
760
if (drawer->toplevel) {
761
PanelWidget *panel_widget;
763
panel_widget = panel_toplevel_get_panel_widget (
765
panel_widget->master_widget = NULL;
767
gtk_widget_destroy (GTK_WIDGET (drawer->toplevel));
768
drawer->toplevel = NULL;
772
if (info->type != PANEL_OBJECT_APPLET)
773
panel_lockdown_notify_remove (G_CALLBACK (panel_applet_recreate_menu),
777
g_object_unref (info->menu);
780
if (info->data_destroy)
781
info->data_destroy (info->data);
784
for (l = info->user_menu; l != NULL; l = l->next) {
785
AppletUserMenu *umenu = l->data;
787
g_free (umenu->name);
788
g_free (umenu->stock_item);
789
g_free (umenu->text);
794
g_list_free (info->user_menu);
795
info->user_menu = NULL;
805
PanelObjectType type;
808
guint right_stick : 1;
812
/* Each time those lists get both empty,
813
* panel_applet_queue_initial_unhide_toplevels() should be called */
814
static GSList *panel_applets_to_load = NULL;
815
static GSList *panel_applets_loading = NULL;
816
/* We have a timeout to always unhide toplevels after a delay, in case of some
818
#define UNHIDE_TOPLEVELS_TIMEOUT_SECONDS 5
819
static guint panel_applet_unhide_toplevels_timeout = 0;
821
static gboolean panel_applet_have_load_idle = FALSE;
824
free_applet_to_load (PanelAppletToLoad *applet)
829
g_free (applet->toplevel_id);
830
applet->toplevel_id = NULL;
836
panel_applet_on_load_queue (const char *id)
839
for (li = panel_applets_to_load; li != NULL; li = li->next) {
840
PanelAppletToLoad *applet = li->data;
841
if (strcmp (applet->id, id) == 0)
844
for (li = panel_applets_loading; li != NULL; li = li->next) {
845
PanelAppletToLoad *applet = li->data;
846
if (strcmp (applet->id, id) == 0)
852
/* This doesn't do anything if the initial unhide already happened */
854
panel_applet_queue_initial_unhide_toplevels (gpointer user_data)
858
if (panel_applet_unhide_toplevels_timeout != 0) {
859
g_source_remove (panel_applet_unhide_toplevels_timeout);
860
panel_applet_unhide_toplevels_timeout = 0;
863
for (l = panel_toplevel_list_toplevels (); l != NULL; l = l->next)
864
panel_toplevel_queue_initial_unhide ((PanelToplevel *) l->data);
870
panel_applet_stop_loading (const char *id)
872
PanelAppletToLoad *applet;
875
for (l = panel_applets_loading; l; l = l->next) {
878
if (strcmp (applet->id, id) == 0)
882
/* this can happen if we reload an applet after it crashed,
885
panel_applets_loading = g_slist_delete_link (panel_applets_loading, l);
886
free_applet_to_load (applet);
889
if (panel_applets_loading == NULL && panel_applets_to_load == NULL)
890
panel_applet_queue_initial_unhide_toplevels (NULL);
894
panel_applet_load_idle_handler (gpointer dummy)
896
PanelObjectType applet_type;
897
PanelAppletToLoad *applet = NULL;
898
PanelToplevel *toplevel = NULL;
899
PanelWidget *panel_widget;
902
if (!panel_applets_to_load) {
903
panel_applet_have_load_idle = FALSE;
907
for (l = panel_applets_to_load; l; l = l->next) {
910
toplevel = panel_profile_get_toplevel_by_id (applet->toplevel_id);
916
/* All the remaining applets don't have a panel */
917
for (l = panel_applets_to_load; l; l = l->next)
918
free_applet_to_load (l->data);
919
g_slist_free (panel_applets_to_load);
920
panel_applets_to_load = NULL;
921
panel_applet_have_load_idle = FALSE;
923
if (panel_applets_loading == NULL) {
924
/* unhide any potential initially hidden toplevel */
925
panel_applet_queue_initial_unhide_toplevels (NULL);
931
panel_applets_to_load = g_slist_delete_link (panel_applets_to_load, l);
932
panel_applets_loading = g_slist_append (panel_applets_loading, applet);
934
panel_widget = panel_toplevel_get_panel_widget (toplevel);
936
if (applet->right_stick) {
937
if (!panel_widget->packed)
938
applet->position = panel_widget->size - applet->position;
940
applet->position = -1;
943
/* We load applets asynchronously, so we specifically don't call
944
* panel_applet_stop_loading() for this type. However, in case of
945
* failure during the load, we might call panel_applet_stop_loading()
946
* synchronously, which will make us lose the content of the applet
947
* variable. So we save the type to be sure we always ignore the
949
applet_type = applet->type;
951
switch (applet_type) {
952
case PANEL_OBJECT_APPLET:
953
panel_applet_frame_load_from_gconf (
959
case PANEL_OBJECT_DRAWER:
960
drawer_load_from_gconf (panel_widget,
965
case PANEL_OBJECT_MENU:
966
panel_menu_button_load_from_gconf (panel_widget,
972
case PANEL_OBJECT_LAUNCHER:
973
launcher_load_from_gconf (panel_widget,
978
case PANEL_OBJECT_LOGOUT:
979
case PANEL_OBJECT_LOCK:
980
panel_action_button_load_compatible (
988
case PANEL_OBJECT_ACTION:
989
panel_action_button_load_from_gconf (
996
case PANEL_OBJECT_MENU_BAR:
997
panel_menu_bar_load_from_gconf (
1004
case PANEL_OBJECT_SEPARATOR:
1005
panel_separator_load_from_gconf (panel_widget,
1011
g_assert_not_reached ();
1015
/* Only the real applets will do a late stop_loading */
1016
if (applet_type != PANEL_OBJECT_APPLET)
1017
panel_applet_stop_loading (applet->id);
1023
panel_applet_queue_applet_to_load (const char *id,
1024
PanelObjectType type,
1025
const char *toplevel_id,
1027
gboolean right_stick,
1030
PanelAppletToLoad *applet;
1033
g_warning ("No toplevel on which to load object '%s'\n", id);
1037
applet = g_new0 (PanelAppletToLoad, 1);
1039
applet->id = g_strdup (id);
1040
applet->type = type;
1041
applet->toplevel_id = g_strdup (toplevel_id);
1042
applet->position = position;
1043
applet->right_stick = right_stick != FALSE;
1044
applet->locked = locked != FALSE;
1046
panel_applets_to_load = g_slist_prepend (panel_applets_to_load, applet);
1050
panel_applet_compare (const PanelAppletToLoad *a,
1051
const PanelAppletToLoad *b)
1055
if ((c = strcmp (a->toplevel_id, b->toplevel_id)))
1057
else if (a->right_stick != b->right_stick)
1058
return b->right_stick ? -1 : 1;
1060
return a->position - b->position;
1064
panel_applet_load_queued_applets (gboolean initial_load)
1066
if (!panel_applets_to_load) {
1067
panel_applet_queue_initial_unhide_toplevels (NULL);
1071
if (panel_applets_to_load && panel_applet_unhide_toplevels_timeout == 0) {
1072
/* Install a timeout to make sure we don't block the
1073
* unhiding because of an applet that doesn't load */
1074
panel_applet_unhide_toplevels_timeout =
1075
g_timeout_add_seconds (UNHIDE_TOPLEVELS_TIMEOUT_SECONDS,
1076
panel_applet_queue_initial_unhide_toplevels,
1080
panel_applets_to_load = g_slist_sort (panel_applets_to_load,
1081
(GCompareFunc) panel_applet_compare);
1083
if ( ! panel_applet_have_load_idle) {
1084
/* on panel startup, we don't care about redraws of the
1085
* toplevels since they are hidden, so we give a higher
1086
* priority to loading of applets */
1088
g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1089
panel_applet_load_idle_handler,
1092
g_idle_add (panel_applet_load_idle_handler, NULL);
1094
panel_applet_have_load_idle = TRUE;
1098
static G_CONST_RETURN char *
1099
panel_applet_get_toplevel_id (AppletInfo *applet)
1101
PanelWidget *panel_widget;
1103
g_return_val_if_fail (applet != NULL, NULL);
1104
g_return_val_if_fail (GTK_IS_WIDGET (applet->widget), NULL);
1106
panel_widget = panel_applet_get_panel_widget (applet);
1110
return panel_profile_get_toplevel_id (panel_widget->toplevel);
1114
panel_applet_position_save_timeout (gpointer dummy)
1118
queued_position_source = 0;
1120
for (l = queued_position_saves; l; l = l->next) {
1121
AppletInfo *info = l->data;
1123
panel_applet_save_position (info, info->id, TRUE);
1126
g_slist_free (queued_position_saves);
1127
queued_position_saves = NULL;
1133
panel_applet_save_position (AppletInfo *applet_info,
1137
PanelGConfKeyType key_type;
1138
GConfClient *client;
1139
PanelWidget *panel_widget;
1141
const char *toplevel_id;
1142
char *old_toplevel_id;
1143
gboolean right_stick;
1147
g_return_if_fail (applet_info != NULL);
1150
if (!queued_position_source)
1151
queued_position_source =
1152
g_timeout_add_seconds (1,
1153
(GSourceFunc) panel_applet_position_save_timeout,
1156
if (!g_slist_find (queued_position_saves, applet_info))
1157
queued_position_saves =
1158
g_slist_prepend (queued_position_saves, applet_info);
1163
if (!(toplevel_id = panel_applet_get_toplevel_id (applet_info)))
1166
client = panel_gconf_get_client ();
1168
key_type = applet_info->type == PANEL_OBJECT_APPLET ? PANEL_GCONF_APPLETS : PANEL_GCONF_OBJECTS;
1170
panel_widget = panel_applet_get_panel_widget (applet_info);
1172
/* FIXME: Instead of getting keys, comparing and setting, there
1173
should be a dirty flag */
1175
key = panel_gconf_full_key (key_type, id, "toplevel_id");
1176
old_toplevel_id = gconf_client_get_string (client, key, NULL);
1177
if (old_toplevel_id == NULL || strcmp (old_toplevel_id, toplevel_id) != 0)
1178
gconf_client_set_string (client, key, toplevel_id, NULL);
1179
g_free (old_toplevel_id);
1181
/* Note: changing some properties of the panel that may not be locked down
1182
(e.g. background) can change the state of the "panel_right_stick" and
1183
"position" properties of an applet that may in fact be locked down.
1184
So check if these are writable before attempting to write them */
1186
right_stick = panel_is_applet_right_stick (applet_info->widget) ? 1 : 0;
1187
key = panel_gconf_full_key (
1188
key_type, id, "panel_right_stick");
1189
if (gconf_client_key_is_writable (client, key, NULL) &&
1190
(gconf_client_get_bool (client, key, NULL) ? 1 : 0) != right_stick)
1191
gconf_client_set_bool (client, key, right_stick, NULL);
1193
position = panel_applet_get_position (applet_info);
1194
if (right_stick && !panel_widget->packed)
1195
position = panel_widget->size - position;
1197
key = panel_gconf_full_key (key_type, id, "position");
1198
if (gconf_client_key_is_writable (client, key, NULL) &&
1199
gconf_client_get_int (client, key, NULL) != position)
1200
gconf_client_set_int (client, key, position, NULL);
1202
locked = panel_widget_get_applet_locked (panel_widget, applet_info->widget) ? 1 : 0;
1203
key = panel_gconf_full_key (key_type, id, "locked");
1204
if (gconf_client_get_bool (client, key, NULL) ? 1 : 0 != locked)
1205
gconf_client_set_bool (client, key, locked, NULL);
1209
panel_applet_get_id (AppletInfo *info)
1218
panel_applet_get_id_by_widget (GtkWidget *applet_widget)
1225
for (l = registered_applets; l; l = l->next) {
1226
AppletInfo *info = l->data;
1228
if (info->widget == applet_widget)
1236
panel_applet_get_by_id (const char *id)
1240
for (l = registered_applets; l; l = l->next) {
1241
AppletInfo *info = l->data;
1243
if (!strcmp (info->id, id))
1251
panel_applet_list_applets (void)
1253
return registered_applets;
1257
panel_applet_get_by_type (PanelObjectType object_type, GdkScreen *screen)
1261
for (l = registered_applets; l; l = l->next) {
1262
AppletInfo *info = l->data;
1264
if (info->type == object_type) {
1266
if (screen == gtk_widget_get_screen (info->widget))
1277
panel_applet_register (GtkWidget *applet,
1279
GDestroyNotify data_destroy,
1284
PanelObjectType type,
1290
g_return_val_if_fail (applet != NULL && panel != NULL, NULL);
1292
if (gtk_widget_get_has_window (applet))
1293
gtk_widget_set_events (applet, (gtk_widget_get_events (applet) |
1294
APPLET_EVENT_MASK) &
1295
~( GDK_POINTER_MOTION_MASK |
1296
GDK_POINTER_MOTION_HINT_MASK));
1298
info = g_new0 (AppletInfo, 1);
1300
info->widget = applet;
1303
info->data_destroy = data_destroy;
1304
info->user_menu = NULL;
1305
info->move_item = NULL;
1306
info->id = g_strdup (id);
1308
g_object_set_data (G_OBJECT (applet), "applet_info", info);
1310
if (type != PANEL_OBJECT_APPLET)
1311
panel_lockdown_notify_add (G_CALLBACK (panel_applet_recreate_menu),
1314
key = panel_gconf_full_key ((type == PANEL_OBJECT_APPLET) ?
1315
PANEL_GCONF_APPLETS : PANEL_GCONF_OBJECTS,
1317
panel_gconf_notify_add_while_alive (key,
1318
(GConfClientNotifyFunc) panel_applet_locked_change_notify,
1321
if (type == PANEL_OBJECT_DRAWER) {
1322
Drawer *drawer = data;
1323
PanelWidget *assoc_panel;
1325
assoc_panel = panel_toplevel_get_panel_widget (drawer->toplevel);
1327
g_object_set_data (G_OBJECT (applet),
1328
PANEL_APPLET_ASSOC_PANEL_KEY, assoc_panel);
1329
assoc_panel->master_widget = applet;
1330
g_object_add_weak_pointer (
1331
G_OBJECT (applet), (gpointer *) &assoc_panel->master_widget);
1334
g_object_set_data (G_OBJECT (applet),
1335
PANEL_APPLET_FORBIDDEN_PANELS, NULL);
1337
registered_applets = g_slist_append (registered_applets, info);
1339
if (panel_widget_add (panel, applet, locked, pos, exactpos) == -1 &&
1340
panel_widget_add (panel, applet, locked, 0, TRUE) == -1) {
1343
for (l = panels; l; l = l->next) {
1344
panel = PANEL_WIDGET (l->data);
1346
if (panel_widget_add (panel, applet, locked, 0, TRUE) != -1)
1351
g_warning (_("Cannot find an empty spot"));
1352
panel_profile_delete_object (info);
1357
if (BUTTON_IS_WIDGET (applet) ||
1358
gtk_widget_get_has_window (applet)) {
1359
g_signal_connect (applet, "button_press_event",
1360
G_CALLBACK (applet_button_press),
1363
g_signal_connect (applet, "popup_menu",
1364
G_CALLBACK (applet_popup_menu),
1368
g_signal_connect (applet, "destroy",
1369
G_CALLBACK (panel_applet_destroy),
1372
panel_applet_set_dnd_enabled (info, !locked);
1374
gtk_widget_show_all (applet);
1376
orientation_change (info, panel);
1377
size_change (info, panel);
1378
back_change (info, panel);
1380
if (type != PANEL_OBJECT_APPLET)
1381
gtk_widget_grab_focus (applet);
1383
gtk_widget_child_focus (applet, GTK_DIR_TAB_FORWARD);
1389
panel_applet_get_position (AppletInfo *applet)
1391
AppletData *applet_data;
1393
g_return_val_if_fail (applet != NULL, 0);
1394
g_return_val_if_fail (G_IS_OBJECT (applet->widget), 0);
1396
applet_data = g_object_get_data (G_OBJECT (applet->widget), PANEL_APPLET_DATA);
1398
return applet_data->pos;
1402
panel_applet_can_freely_move (AppletInfo *applet)
1404
GConfClient *client;
1405
PanelGConfKeyType key_type;
1408
if (panel_lockdown_get_locked_down ())
1411
client = panel_gconf_get_client ();
1413
key_type = (applet->type == PANEL_OBJECT_APPLET) ? PANEL_GCONF_APPLETS : PANEL_GCONF_OBJECTS;
1415
key = panel_gconf_full_key (key_type, applet->id, "position");
1416
if (!gconf_client_key_is_writable (client, key, NULL))
1419
key = panel_gconf_full_key (key_type, applet->id, "toplevel_id");
1420
if (!gconf_client_key_is_writable (client, key, NULL))
1423
key = panel_gconf_full_key (key_type, applet->id, "panel_right_stick");
1424
if (!gconf_client_key_is_writable (client, key, NULL))
1431
panel_applet_lockable (AppletInfo *applet)
1433
GConfClient *client;
1434
PanelGConfKeyType key_type;
1437
if (panel_lockdown_get_locked_down ())
1440
client = panel_gconf_get_client ();
1442
key_type = (applet->type == PANEL_OBJECT_APPLET) ? PANEL_GCONF_APPLETS : PANEL_GCONF_OBJECTS;
1444
key = panel_gconf_full_key (key_type, applet->id, "locked");
1446
return gconf_client_key_is_writable (client, key, NULL);