source: trunk/third/gnome-panel/gnome-panel/applet.c @ 18631

Revision 18631, 31.1 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18630, which included commits to RCS files with non-trunk default branches.
Line 
1/* Gnome panel: general applet functionality
2 * (C) 1997 the Free Software Foundation
3 *
4 * Authors:  George Lebl
5 *           Federico Mena
6 *           Miguel de Icaza
7 */
8
9#include <config.h>
10#include <string.h>
11#include <signal.h>
12#include <libgnome/libgnome.h>
13#include <libbonobo.h>
14#include <gdk/gdkx.h>
15
16#include "basep-widget.h"
17#include "button-widget.h"
18#include "drawer.h"
19#include "launcher.h"
20#include "menu-util.h"
21#include "menu.h"
22#include "panel-config.h"
23#include "panel-gconf.h"
24#include "panel-config-global.h"
25#include "session.h"
26#include "panel-applet-frame.h"
27#include "egg-screen-exec.h"
28#include "panel-action-button.h"
29
30#define SMALL_ICON_SIZE 20
31
32extern GSList *panels;
33
34GSList *applets = NULL;
35int applet_count = 0;
36
37/*config sync stuff*/
38extern int applets_to_sync;
39extern int need_complete_save;
40
41extern gboolean commie_mode;
42extern GlobalConfig global_config;
43
44static GConfEnumStringPair object_type_enum_map [] = {
45        { APPLET_DRAWER,   "drawer-object" },
46        { APPLET_MENU,     "menu-object" },
47        { APPLET_LAUNCHER, "launcher-object" },
48        { APPLET_BONOBO,   "bonobo-applet" },
49        { APPLET_ACTION,   "action-applet" },
50        { APPLET_LOCK,     "lock-object" },   /* FIXME:                           */
51        { APPLET_LOGOUT,   "logout-object" }, /*   Both only for backwards compat */
52};
53
54static GSList *queued_position_saves = NULL;
55static guint   queued_position_source = 0;
56
57static void
58move_applet_callback (GtkWidget *widget, AppletInfo *info)
59{
60        PanelWidget *panel;
61
62        g_return_if_fail (info != NULL);
63        g_return_if_fail (info->widget != NULL);
64        g_return_if_fail (info->widget->parent != NULL);
65        g_return_if_fail (PANEL_IS_WIDGET (info->widget->parent));
66
67        panel = PANEL_WIDGET (info->widget->parent);
68
69        panel_widget_applet_drag_start (panel, info->widget,
70                                        PW_DRAG_OFF_CENTER);
71}
72
73void
74panel_applet_clean_gconf (AppletType  type,
75                          const char *gconf_key,
76                          gboolean    clean_gconf)
77{
78        GConfClient *client;
79        GSList      *id_list, *l;
80        const char  *temp_key = NULL;
81        const char  *profile;
82
83        g_return_if_fail (gconf_key != NULL);
84
85        client  = panel_gconf_get_client ();
86        profile = panel_gconf_get_profile ();
87
88        if (type == APPLET_BONOBO)
89                temp_key = panel_gconf_general_key (profile, "applet_id_list");
90        else
91                temp_key = panel_gconf_general_key (profile, "object_id_list");
92
93        id_list = gconf_client_get_list (
94                        panel_gconf_get_client (), temp_key,
95                        GCONF_VALUE_STRING, NULL);
96
97        for (l = id_list; l; l = l->next)
98                if (strcmp (gconf_key, (char *) l->data) == 0)
99                        break;
100
101        if (l) {
102                g_free (l->data);
103                l->data = NULL;
104                id_list = g_slist_delete_link (id_list, l);
105
106                gconf_client_set_list (client, temp_key, GCONF_VALUE_STRING, id_list, NULL);
107
108                if (type == APPLET_BONOBO)
109                        temp_key = panel_gconf_sprintf (
110                                        "/apps/panel/profiles/%s/applets/%s",
111                                        profile, gconf_key);
112                else
113                        temp_key = panel_gconf_sprintf (
114                                        "/apps/panel/profiles/%s/objects/%s",
115                                        profile, gconf_key);
116
117                if (clean_gconf)
118                        panel_gconf_clean_dir (client, temp_key);
119        }
120
121        panel_g_slist_deep_free (id_list);
122}
123
124/* permanently remove an applet - all non-permanent
125 * cleanups should go in panel_applet_destroy()
126 */
127void
128panel_applet_clean (AppletInfo *info,
129                    gboolean    clean_gconf)
130{
131        g_return_if_fail (info != NULL);
132
133        if (info->type == APPLET_LAUNCHER) {
134                Launcher    *launcher = info->data;
135                const gchar *location;
136
137                location = gnome_desktop_item_get_location (launcher->ditem);
138
139                /* Launcher may not yet have been hoarded */
140                if (location)
141                        session_add_dead_launcher (location);
142        }
143
144        panel_applet_clean_gconf (info->type, info->gconf_key, clean_gconf);
145
146        if (info->widget) {
147                GtkWidget *widget = info->widget;
148
149                info->widget = NULL;
150                gtk_widget_destroy (widget);
151        }
152}
153
154static gboolean
155applet_idle_remove (gpointer data)
156{
157        AppletInfo *info = data;
158
159        info->remove_idle = 0;
160
161        panel_applet_clean (info, TRUE);
162
163        return FALSE;
164}
165
166void
167panel_applet_remove_in_idle (AppletInfo *info)
168{
169        if (info->remove_idle == 0)
170                info->remove_idle = g_idle_add (applet_idle_remove, info);
171}
172
173static void
174applet_remove_callback (GtkWidget  *widget,
175                        AppletInfo *info)
176{
177        panel_applet_remove_in_idle (info);
178}
179
180static inline GdkScreen *
181applet_user_menu_get_screen (AppletUserMenu *menu)
182{
183        return gtk_window_get_screen (
184                        GTK_WINDOW (get_panel_parent (menu->info->widget)));
185}
186
187static void
188applet_callback_callback (GtkWidget      *widget,
189                          AppletUserMenu *menu)
190{
191        GdkScreen *screen;
192
193        g_return_if_fail (menu->info != NULL);
194
195        screen = applet_user_menu_get_screen (menu);
196
197        switch (menu->info->type) {
198        case APPLET_LAUNCHER:
199                if (!strcmp (menu->name, "properties"))
200                        launcher_properties (
201                                menu->info->data, screen);
202
203                else if (!strcmp (menu->name, "help"))
204                        panel_show_help (screen, "wgospanel.xml", "gospanel-16");
205
206                else if (!strcmp (menu->name, "help_on_app"))
207                        launcher_show_help (menu->info->data, screen);
208                break;
209        case APPLET_DRAWER:
210                if (strcmp (menu->name, "properties")==0) {
211                        Drawer *drawer = menu->info->data;
212                        g_assert(drawer);
213                        panel_config(drawer->drawer);
214                } else if (strcmp (menu->name, "help") == 0) {
215                        panel_show_help (screen, "wgospanel.xml", "gospanel-18");
216                }
217                break;
218        case APPLET_MENU:
219                if (!strcmp (menu->name, "help"))
220                        panel_show_help (screen, "wgospanel.xml", "gospanel-37");
221                break;
222        case APPLET_ACTION:
223        case APPLET_LOGOUT:
224        case APPLET_LOCK:
225                panel_action_button_invoke_menu (
226                        PANEL_ACTION_BUTTON (menu->info->widget), menu->name);
227                break;
228        case APPLET_BONOBO:
229                /*
230                 * Applet's menu's are handled differently
231                 */
232                break;
233        default:
234                g_assert_not_reached ();
235                break;
236        }
237}
238
239static void
240applet_menu_deactivate(GtkWidget *w, AppletInfo *info)
241{
242        GtkWidget *panel = get_panel_parent(info->widget);
243        info->menu_age = 0;
244       
245        if(BASEP_IS_WIDGET(panel))
246                BASEP_WIDGET(panel)->autohide_inhibit = FALSE;
247}
248
249AppletUserMenu *
250panel_applet_get_callback (GList      *user_menu,
251                           const char *name)
252{
253        GList *l;
254
255        for (l = user_menu; l; l = l->next) {
256                AppletUserMenu *menu = l->data;
257
258                if (strcmp (menu->name, name) == 0)
259                        return menu;
260        }
261
262        return NULL;   
263}
264
265void
266panel_applet_add_callback (AppletInfo *info,
267                           const char *callback_name,
268                           const char *stock_item,
269                           const char *menuitem_text)
270{
271        AppletUserMenu *menu;
272
273        g_return_if_fail (info != NULL);
274
275        menu = panel_applet_get_callback (info->user_menu, callback_name);
276        if (menu == NULL) {
277                menu = g_new0 (AppletUserMenu, 1);
278                menu->name = g_strdup (callback_name);
279                menu->stock_item = g_strdup (stock_item);
280                menu->text = g_strdup (menuitem_text);
281                menu->sensitive = TRUE;
282                menu->info = info;
283                menu->menuitem = NULL;
284                menu->submenu = NULL;
285                info->user_menu = g_list_append (info->user_menu, menu);
286        } else {
287                g_free (menu->stock_item);
288                menu->stock_item = NULL;
289                g_free (menu->text);
290                menu->text = NULL;
291                menu->text = g_strdup (menuitem_text);
292                menu->stock_item = g_strdup (stock_item);
293        }
294
295        /*make sure the menu is rebuilt*/
296        if(info->menu) {
297                GList *list;
298                for(list=info->user_menu;list!=NULL;list=g_list_next(list)) {
299                        AppletUserMenu *menu = list->data;
300                        menu->menuitem=NULL;
301                        menu->submenu=NULL;
302                }
303                gtk_widget_unref(info->menu);
304                info->menu = NULL;
305                info->menu_age = 0;
306        }
307}
308
309void
310panel_applet_remove_callback (AppletInfo *info,
311                              const char *callback_name)
312{
313        AppletUserMenu *menu;
314
315        g_return_if_fail (info != NULL);
316       
317        menu = panel_applet_get_callback (info->user_menu, callback_name);
318        if (menu != NULL) {
319                info->user_menu = g_list_remove (info->user_menu, menu);
320                g_free(menu->name);
321                menu->name = NULL;
322                g_free(menu->stock_item);
323                menu->stock_item = NULL;
324                g_free(menu->text);
325                menu->text = NULL;
326                g_free(menu);
327        } else
328                return; /*it just isn't there*/
329
330        /*make sure the menu is rebuilt*/
331        if (info->menu != NULL) {
332                GList *list;
333                for (list = info->user_menu; list != NULL; list = list->next) {
334                        AppletUserMenu *menu = list->data;
335                        menu->menuitem = NULL;
336                        menu->submenu = NULL;
337                }
338                gtk_widget_unref (info->menu);
339                info->menu = NULL;
340                info->menu_age = 0;
341        }
342}
343
344static void
345setup_an_item (AppletUserMenu *menu,
346               GtkWidget      *submenu,
347               int             is_submenu)
348{
349        GtkWidget *image = NULL;
350
351        menu->menuitem = gtk_image_menu_item_new ();
352
353        g_signal_connect (G_OBJECT (menu->menuitem), "destroy",
354                          G_CALLBACK (gtk_widget_destroyed),
355                          &menu->menuitem);
356
357        if (menu->stock_item && menu->stock_item [0])
358                image = gtk_image_new_from_stock (menu->stock_item, GTK_ICON_SIZE_MENU);
359
360        setup_menuitem (menu->menuitem, GTK_ICON_SIZE_MENU, image, menu->text);
361
362        if(submenu)
363                gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menu->menuitem);
364
365        /*if an item not a submenu*/
366        if (!is_submenu) {
367                g_signal_connect (menu->menuitem, "activate",
368                                  G_CALLBACK (applet_callback_callback),
369                                  menu);
370                g_signal_connect (submenu, "destroy",
371                                  G_CALLBACK (gtk_widget_destroyed),
372                                  &menu->submenu);
373        /* if the item is a submenu and doesn't have it's menu
374           created yet*/
375        } else if (!menu->submenu) {
376                menu->submenu = panel_menu_new ();
377        }
378
379        if(menu->submenu) {
380                gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu->menuitem),
381                                          menu->submenu);
382                g_signal_connect (G_OBJECT (menu->submenu), "destroy",
383                                    G_CALLBACK (gtk_widget_destroyed),
384                                    &menu->submenu);
385        }
386       
387        gtk_widget_set_sensitive(menu->menuitem,menu->sensitive);
388}
389
390static void
391add_to_submenus (AppletInfo *info,
392                 const char *path,
393                 const char *name,
394                 AppletUserMenu *menu,
395                 GtkWidget *submenu,
396                 GList *user_menu)
397{
398        char *n = g_strdup (name);
399        char *p = strchr (n, '/');
400        char *t;
401        AppletUserMenu *s_menu;
402
403        /*this is the last one*/
404        if (p == NULL) {
405                g_free (n);
406                setup_an_item (menu, submenu, FALSE);
407                return;
408        }
409       
410        /*this is the last one and we are a submenu, we have already been
411          set up*/
412        if(p==(n + strlen(n) - 1)) {
413                g_free(n);
414                return;
415        }
416       
417        *p = '\0';
418        p++;
419       
420        t = g_strconcat (path, n, "/", NULL);
421        s_menu = panel_applet_get_callback (user_menu, t);
422        /*the user did not give us this sub menu, whoops, will create an empty
423          one then*/
424        if (s_menu == NULL) {
425                s_menu = g_new0 (AppletUserMenu,1);
426                s_menu->name = g_strdup (t);
427                s_menu->stock_item = NULL;
428                s_menu->text = g_strdup (_("???"));
429                s_menu->sensitive = TRUE;
430                s_menu->info = info;
431                s_menu->menuitem = NULL;
432                s_menu->submenu = NULL;
433                info->user_menu = g_list_append (info->user_menu,s_menu);
434                user_menu = info->user_menu;
435        }
436       
437        if (s_menu->submenu == NULL) {
438                s_menu->submenu = panel_menu_new ();
439                /*a more elegant way to do this should be done
440                  when I don't want to go to sleep */
441                if (s_menu->menuitem != NULL) {
442                        gtk_widget_destroy (s_menu->menuitem);
443                        s_menu->menuitem = NULL;
444                }
445        }
446        if (s_menu->menuitem == NULL)
447                setup_an_item (s_menu, submenu, TRUE);
448       
449        add_to_submenus (info, t, p, menu, s_menu->submenu, user_menu);
450       
451        g_free(t);
452        g_free(n);
453}
454
455static GtkWidget *
456panel_applet_create_menu (AppletInfo *info)
457{
458        GtkWidget *menu;
459        GtkWidget *menuitem;
460        GList     *l;
461
462        menu = g_object_ref (panel_menu_new ());
463        gtk_object_sink (GTK_OBJECT (menu));
464
465        /* connect the deactivate signal, so that we can "re-allow"
466         * autohide when the menu is deactivated.
467         */
468        g_signal_connect (menu, "deactivate",
469                          G_CALLBACK (applet_menu_deactivate), info);
470
471        if (info->user_menu) {
472                for (l = info->user_menu; l; l = l->next) {
473                        AppletUserMenu *user_menu = (AppletUserMenu *)l->data;
474
475                        add_to_submenus (info, "", user_menu->name, user_menu,
476                                         menu, info->user_menu);
477                }
478        }
479
480        if (!commie_mode) {
481                GtkWidget *image;
482
483                menuitem = gtk_separator_menu_item_new ();
484                gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
485                gtk_widget_show (menuitem);
486
487                menuitem = gtk_image_menu_item_new ();
488
489                image = gtk_image_new_from_stock (GTK_STOCK_REMOVE,
490                                                  GTK_ICON_SIZE_MENU);
491
492                setup_menuitem (menuitem, GTK_ICON_SIZE_MENU, image , _("_Remove From Panel"));
493
494                g_signal_connect (menuitem, "activate",
495                                  G_CALLBACK (applet_remove_callback), info);
496
497                gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
498
499                menuitem = gtk_image_menu_item_new ();
500
501                /* FIXME: should have a "Move" pixmap.
502                 */
503                image = gtk_image_new ();
504                setup_menuitem (menuitem, GTK_ICON_SIZE_MENU, image, _("_Move"));
505
506                g_signal_connect (menuitem, "activate",
507                                  G_CALLBACK (move_applet_callback), info);
508
509                gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
510        }
511
512        return menu;
513}
514
515void
516panel_applet_menu_set_recurse (GtkMenu     *menu,
517                               const gchar *key,
518                               gpointer     data)
519{
520        GList *children;
521        GList *l;
522
523        g_object_set_data (G_OBJECT (menu), key, data);
524
525        children = gtk_container_get_children (GTK_CONTAINER (menu));
526
527        for (l = children; l; l = l->next) {
528                GtkWidget *submenu = GTK_MENU_ITEM (l->data)->submenu;
529
530                if (submenu)
531                        panel_applet_menu_set_recurse (
532                                GTK_MENU (submenu), key, data);
533        }
534
535        g_list_free (children);
536}
537
538static void
539applet_show_menu (AppletInfo     *info,
540                  GdkEventButton *event)
541{
542        GtkWidget *panel;
543
544        g_return_if_fail (info != NULL);
545
546        panel = get_panel_parent (info->widget);
547
548        if (!info->menu)
549                info->menu = panel_applet_create_menu (info);
550
551        g_assert (info->menu);
552
553        if (BASEP_IS_WIDGET (panel)) {
554                BASEP_WIDGET (panel)->autohide_inhibit = TRUE;
555                basep_widget_queue_autohide (BASEP_WIDGET (panel));
556        }
557
558        info->menu_age = 0;
559
560        panel_applet_menu_set_recurse (GTK_MENU (info->menu),
561                                       "menu_panel",
562                                       info->widget->parent);
563
564        gtk_menu_set_screen (GTK_MENU (info->menu),
565                             panel_screen_from_toplevel (panel));
566
567        if (!GTK_WIDGET_REALIZED (info->menu))
568                gtk_widget_show (info->menu);
569
570        gtk_menu_popup (GTK_MENU (info->menu),
571                        NULL,
572                        NULL,
573                        (GtkMenuPositionFunc) panel_position_applet_menu,
574                        info->widget,
575                        event->button,
576                        event->time);
577}
578
579static gboolean
580applet_do_popup_menu (GtkWidget      *widget,
581                      GdkEventButton *event,
582                      AppletInfo     *info)
583{
584        if (panel_applet_in_drag)
585                return FALSE;
586
587        if (info->type == APPLET_BONOBO)
588                return FALSE;
589
590        applet_show_menu (info, event);
591
592        return TRUE;
593}
594
595static gboolean
596applet_popup_menu (GtkWidget      *widget,
597                   AppletInfo     *info)
598{
599        GdkEventButton event;
600
601        event.button = 3;
602        event.time = GDK_CURRENT_TIME;
603
604        return applet_do_popup_menu (widget, &event, info);
605}
606
607static gboolean
608applet_button_press (GtkWidget      *widget,
609                     GdkEventButton *event,
610                     AppletInfo     *info)
611{
612        if (event->button == 3)
613                return applet_do_popup_menu (widget, event, info);
614
615        return FALSE;
616}
617
618static void
619panel_applet_destroy (GtkWidget  *widget,
620                      AppletInfo *info)
621{
622        GList *l;
623
624        g_return_if_fail (info != NULL);
625
626        info->widget = NULL;
627
628        applets = g_slist_remove (applets, info);
629
630        queued_position_saves =
631                g_slist_remove (queued_position_saves, info);
632
633        if (info->remove_idle) {
634                g_source_remove (info->remove_idle);
635                info->remove_idle = 0;
636        }
637
638        if (info->type == APPLET_DRAWER) {
639                Drawer *drawer = info->data;
640
641                if (drawer->drawer) {
642                        PANEL_WIDGET (BASEP_WIDGET (drawer->drawer)->panel)->master_widget = NULL;
643
644                        gtk_widget_destroy (drawer->drawer);
645                        drawer->drawer = NULL;
646                }
647        }
648
649        if (info->menu)
650                gtk_widget_unref (info->menu);
651        info->menu = NULL;
652
653        if (info->data_destroy)
654                info->data_destroy (info->data);
655        info->data = NULL;
656
657        for (l = info->user_menu; l != NULL; l = l->next) {
658                AppletUserMenu *umenu = l->data;
659
660                g_free (umenu->name);
661                g_free (umenu->stock_item);
662                g_free (umenu->text);
663
664                g_free (umenu);
665        }
666
667        g_list_free (info->user_menu);
668        info->user_menu = NULL;
669
670        g_free (info->gconf_key);
671        info->gconf_key = NULL;
672
673        g_free (info);
674}
675
676typedef struct {
677        AppletType   type;
678        PanelWidget *panel_widget;
679        int          position;
680        char        *unique_id;
681        gulong       destroy_handler;
682} PanelAppletToLoad;
683
684static GSList *panel_applets_to_load = NULL;
685
686static void
687whack_applet_to_load (PanelAppletToLoad *applet)
688{
689        if (applet->destroy_handler > 0)
690                g_signal_handler_disconnect (applet->panel_widget,
691                                             applet->destroy_handler);
692        applet->destroy_handler = 0;
693
694        g_free (applet->unique_id);
695        applet->unique_id = NULL;
696
697        g_free (applet);
698}
699
700static gboolean
701panel_applet_load_idle_handler (gpointer dummy)
702{
703        PanelAppletToLoad *applet;
704
705        if (panel_applets_to_load == NULL)
706                return FALSE;
707
708        applet = (PanelAppletToLoad *) panel_applets_to_load->data;
709        panel_applets_to_load->data = NULL;
710        panel_applets_to_load =
711                g_slist_delete_link (panel_applets_to_load,
712                                     panel_applets_to_load);
713
714        switch (applet->type) {
715        case APPLET_BONOBO:
716                panel_applet_frame_load_from_gconf (
717                                        applet->panel_widget,
718                                        applet->position,
719                                        applet->unique_id);
720                break;
721        case APPLET_DRAWER:
722                drawer_load_from_gconf (applet->panel_widget,
723                                        applet->position,
724                                        applet->unique_id);
725                break;
726        case APPLET_MENU:
727                menu_load_from_gconf (applet->panel_widget,
728                                      applet->position,
729                                      applet->unique_id);
730                break;
731        case APPLET_LAUNCHER:
732                launcher_load_from_gconf (applet->panel_widget,
733                                          applet->position,
734                                          applet->unique_id);
735                break;
736        case APPLET_LOGOUT:  /* FIXME: This is backward compatibility only. */
737        case APPLET_LOCK:    /*        Remove at some time in the future    */
738                panel_action_button_load (
739                                applet->type == APPLET_LOGOUT ? PANEL_ACTION_LOGOUT :
740                                                                PANEL_ACTION_LOCK,
741                                applet->panel_widget,
742                                applet->position,
743                                TRUE,
744                                applet->unique_id,
745                                TRUE);
746                break;
747        case APPLET_ACTION:
748                panel_action_button_load_from_gconf (
749                                applet->panel_widget,
750                                applet->position,
751                                TRUE,
752                                applet->unique_id);
753        default:
754                break;
755        }
756
757        whack_applet_to_load (applet);
758
759        return TRUE;
760}
761
762static void
763panel_destroyed_while_loading (GtkWidget *panel, gpointer data)
764{
765        PanelAppletToLoad *applet = data;
766
767        applet->destroy_handler = 0;
768
769        panel_applets_to_load =
770                g_slist_remove (panel_applets_to_load, applet);
771
772        whack_applet_to_load (applet);
773}
774
775static void
776panel_applet_load_from_unique_id (PanelGConfKeyType  type,
777                                  GConfClient       *gconf_client,
778                                  const char        *profile,
779                                  const char        *unique_id)
780{
781        PanelAppletToLoad *applet;
782        PanelWidget       *panel_widget;
783        AppletType         applet_type = 0;
784        const char        *temp_key;
785        char              *type_string;
786        char              *panel_id;
787        int                position;
788        gboolean           right_stick;
789
790        temp_key = panel_gconf_full_key (type, profile, unique_id, "object_type");
791        type_string = gconf_client_get_string (gconf_client, temp_key, NULL);
792        if (!type_string) {
793                g_printerr (_("No object_type set for panel object with ID %s\n"), unique_id);
794                return;
795        }
796       
797        if (!gconf_string_to_enum (object_type_enum_map,
798                                   type_string,
799                                   (int *) &applet_type)) {
800                g_free (type_string);
801                g_warning ("Unkown applet type %s from %s", type_string, temp_key);
802                return;
803        }
804       
805        g_free (type_string);
806
807        temp_key = panel_gconf_full_key (type, profile, unique_id, "position");
808        position = gconf_client_get_int (gconf_client, temp_key, NULL);
809       
810        temp_key = panel_gconf_full_key (type, profile, unique_id, "panel_id");
811        panel_id = gconf_client_get_string (gconf_client, temp_key, NULL);
812        if (!panel_id) {
813                g_printerr (_("No panel_id set for panel object with ID %s\n"), unique_id);
814                return;
815        }
816
817        temp_key = panel_gconf_full_key (type, profile, unique_id, "panel_right_stick");
818        right_stick = gconf_client_get_bool (gconf_client, temp_key, NULL);
819
820        panel_widget = panel_widget_get_by_id (panel_id);
821        g_free (panel_id);
822
823        if (!panel_widget)
824                return;
825
826        if (right_stick && !panel_widget->packed)
827                position = panel_widget->size - position;
828
829        applet = g_new0 (PanelAppletToLoad, 1);
830
831        applet->type            = applet_type;
832        applet->panel_widget    = panel_widget;
833        applet->position        = position;
834        applet->unique_id       = g_strdup (unique_id);
835        applet->destroy_handler =
836                        g_signal_connect (panel_widget, "destroy",
837                                          G_CALLBACK (panel_destroyed_while_loading),
838                                          applet);
839
840        panel_applets_to_load = g_slist_prepend (panel_applets_to_load, applet);
841}
842
843static void
844panel_applet_load_list (PanelGConfKeyType type)
845{
846        GConfClient *client;
847        GSList      *id_list, *l;
848        const char  *profile;
849        const char  *temp_key = NULL;
850       
851        client  = panel_gconf_get_client ();
852        profile = panel_gconf_get_profile ();
853
854        if (type == PANEL_GCONF_APPLETS)
855                temp_key = panel_gconf_general_key (profile, "applet_id_list");
856        else
857                temp_key = panel_gconf_general_key (profile, "object_id_list");
858
859        id_list = gconf_client_get_list (
860                        panel_gconf_get_client (), temp_key,
861                        GCONF_VALUE_STRING, NULL);
862
863        for (l = id_list; l; l = l->next)
864                panel_applet_load_from_unique_id (type, client, profile, (char *) l->data);
865
866        panel_g_slist_deep_free (id_list);
867}
868
869static int
870panel_applet_compare (const PanelAppletToLoad *a,
871                      const PanelAppletToLoad *b)
872{
873        if (a->panel_widget != b->panel_widget)
874                return a->panel_widget - b->panel_widget;
875        else
876                return a->position - b->position;
877}
878
879void
880panel_applet_load_applets_from_gconf (void)
881{
882        panel_applet_load_list (PANEL_GCONF_APPLETS);
883        panel_applet_load_list (PANEL_GCONF_OBJECTS);
884
885        if (!panel_applets_to_load)
886                return;
887
888        panel_applets_to_load = g_slist_sort (panel_applets_to_load,
889                                              (GCompareFunc) panel_applet_compare);
890
891        g_idle_add (panel_applet_load_idle_handler, NULL);
892}
893
894static void
895panel_applet_load_default_applet_for_screen (PanelGConfKeyType  type,
896                                             const char        *profile,
897                                             const char        *applet_id,
898                                             int                screen)
899{
900        GConfClient *client;
901        GError      *error = NULL;
902        GSList      *id_list, *l;
903        const char  *key;
904        char        *new_applet_id;
905        char        *panel_id, *new_panel_id;
906
907        new_applet_id = panel_gconf_load_default_config_for_screen (
908                                type, profile, applet_id, screen, &error);
909        if (error) {
910                g_warning ("Could not load default config for applet '%s': '%s'\n",
911                           applet_id, error->message);
912                g_error_free (error);
913                return;
914        }
915
916        client = panel_gconf_get_client ();
917
918        key = panel_gconf_full_key (type, profile, new_applet_id, "panel_id");
919        panel_id = gconf_client_get_string (client, key, NULL);
920        if (!panel_id) {
921                g_printerr (_("No panel_id set for panel object with ID %s\n"), new_applet_id);
922                g_free (new_applet_id);
923                return;
924        }
925
926        new_panel_id = g_strdup_printf ("%s_screen%d", panel_id, screen);
927        gconf_client_set_string (client, key, new_panel_id, NULL);
928        g_free (new_panel_id);
929        g_free (panel_id);
930
931        if (type == PANEL_GCONF_APPLETS)
932                key = panel_gconf_general_key (profile, "applet_id_list");
933        else
934                key = panel_gconf_general_key (profile, "object_id_list");
935
936        id_list = gconf_client_get_list (client, key, GCONF_VALUE_STRING, NULL);
937
938        for (l = id_list; l; l = l->next)
939                if (!strcmp (new_applet_id, (char *) l->data))
940                        break;
941
942        if (!l) {
943                id_list = g_slist_prepend (id_list, new_applet_id);
944                new_applet_id = NULL;
945
946                gconf_client_set_list (client, key, GCONF_VALUE_STRING, id_list, NULL);
947        }
948
949        panel_g_slist_deep_free (id_list);
950        g_free (new_applet_id);
951}
952
953void
954panel_applet_load_defaults_for_screen (PanelGConfKeyType  type,
955                                       const char        *profile,
956                                       int                screen)
957{
958        GConfClient *client;
959        GSList      *applets, *l;
960        GError      *error = NULL;
961        const char  *subdir = NULL;
962        const char  *schemas_dir = NULL;
963
964        switch (type) {
965        case PANEL_GCONF_APPLETS:
966                subdir = "applets";
967                break;
968        case PANEL_GCONF_OBJECTS:
969                subdir = "objects";
970                break;
971        default:
972                g_assert_not_reached ();
973                break;
974        }
975
976        client = panel_gconf_get_client ();
977
978        /* FIXME: "medium" shouldn't be hardcoded.
979         */
980        schemas_dir = panel_gconf_sprintf (
981                        "/schemas/apps/panel/default_profiles/medium/%s", subdir);
982
983        applets = gconf_client_all_dirs (client, schemas_dir, &error);
984        if (error) {
985                g_warning ("Cannot list default '%s': '%s'\n", subdir, error->message);
986                g_error_free (error);
987                return;
988        }
989
990        for (l = applets; l; l = l->next) {
991                char *applet_id;
992
993                applet_id = g_path_get_basename (l->data);
994
995                panel_applet_load_default_applet_for_screen (   
996                                type, profile, applet_id, screen);
997
998                g_free (applet_id);
999                g_free (l->data);
1000        }
1001
1002        g_slist_free (applets);
1003}
1004
1005static G_CONST_RETURN char *
1006panel_applet_get_panel_id (AppletInfo *applet)
1007{
1008        PanelWidget *panel;
1009
1010        g_return_val_if_fail (applet != NULL, NULL);
1011        g_return_val_if_fail (GTK_IS_WIDGET (applet->widget), NULL);
1012
1013        panel = PANEL_WIDGET (applet->widget->parent);
1014        if (!panel)
1015                return NULL;
1016
1017        return panel->unique_id;
1018}
1019
1020static gboolean
1021panel_applet_position_save_timeout (gpointer dummy)
1022{
1023        GSList *l;
1024
1025        queued_position_source = 0;
1026
1027        for (l = queued_position_saves; l; l = l->next) {
1028                AppletInfo *info = l->data;
1029
1030                panel_applet_save_position (info, info->gconf_key, TRUE);
1031        }
1032
1033        g_slist_free (queued_position_saves);
1034        queued_position_saves = NULL;
1035
1036        return FALSE;
1037}
1038
1039void
1040panel_applet_save_position (AppletInfo *applet_info,
1041                            const char *gconf_key,
1042                            gboolean    immediate)
1043{
1044        PanelGConfKeyType  key_type;
1045        GConfClient       *client;
1046        const char        *profile;
1047        const char        *temp_key;
1048        const char        *panel_id;
1049        gboolean           right_stick;
1050        int                position;
1051
1052        g_return_if_fail (applet_info != NULL);
1053
1054        if (!immediate) {
1055                if (!queued_position_source)
1056                        queued_position_source =
1057                                g_timeout_add (1000,
1058                                               (GSourceFunc) panel_applet_position_save_timeout,
1059                                               NULL);
1060
1061                if (!g_slist_find (queued_position_saves, applet_info))
1062                        queued_position_saves =
1063                                g_slist_prepend (queued_position_saves, applet_info);
1064
1065                return;
1066        }
1067
1068        if (!(panel_id = panel_applet_get_panel_id (applet_info)))
1069                return;
1070
1071        client  = panel_gconf_get_client ();
1072        profile = panel_gconf_get_profile ();
1073
1074        if (applet_info->type == APPLET_BONOBO)
1075                key_type = PANEL_GCONF_APPLETS;
1076        else
1077                key_type = PANEL_GCONF_OBJECTS;
1078
1079        temp_key = panel_gconf_full_key (key_type, profile, gconf_key, "panel_id");
1080        gconf_client_set_string (client, temp_key, panel_id, NULL);
1081
1082        right_stick = panel_is_applet_right_stick (applet_info->widget);
1083        temp_key = panel_gconf_full_key (
1084                        key_type, profile, gconf_key, "panel_right_stick");
1085        gconf_client_set_bool (client, temp_key, right_stick, NULL);
1086
1087        position = panel_applet_get_position (applet_info);
1088        if (right_stick && !PANEL_WIDGET (applet_info->widget->parent)->packed)
1089                position = PANEL_WIDGET (applet_info->widget->parent)->size - position;
1090
1091        temp_key = panel_gconf_full_key (
1092                        key_type, profile, gconf_key, "position");
1093        gconf_client_set_int (client, temp_key, position, NULL);
1094}
1095
1096void
1097panel_applet_save_to_gconf (AppletInfo *applet_info)
1098{
1099        PanelGConfKeyType  key_type;
1100        GConfClient       *client;
1101        const char        *profile;
1102        const char        *temp_key;
1103        GSList            *id_list, *l;
1104
1105        client  = panel_gconf_get_client ();
1106        profile = panel_gconf_get_profile ();
1107
1108        if (applet_info->type == APPLET_BONOBO)
1109                temp_key = panel_gconf_general_key (profile, "applet_id_list");
1110        else
1111                temp_key = panel_gconf_general_key (profile, "object_id_list");
1112
1113        id_list = gconf_client_get_list (client, temp_key, GCONF_VALUE_STRING, NULL);
1114
1115        if (!applet_info->gconf_key)
1116                applet_info->gconf_key = gconf_unique_key ();
1117
1118        for (l = id_list; l; l = l->next)
1119                if (strcmp (applet_info->gconf_key, (char *) l->data) == 0)
1120                        break;
1121
1122        if (!l) {
1123                id_list = g_slist_prepend (id_list, g_strdup (applet_info->gconf_key));
1124
1125                gconf_client_set_list (client, temp_key, GCONF_VALUE_STRING, id_list, NULL);
1126        }
1127
1128        panel_g_slist_deep_free (id_list);
1129
1130        if (applet_info->type == APPLET_BONOBO)
1131                key_type = PANEL_GCONF_APPLETS;
1132        else
1133                key_type = PANEL_GCONF_OBJECTS;
1134
1135        temp_key = panel_gconf_full_key (
1136                        key_type, profile, applet_info->gconf_key, "object_type");
1137        gconf_client_set_string (
1138                client, temp_key,
1139                gconf_enum_to_string (object_type_enum_map, applet_info->type),
1140                NULL);
1141
1142        panel_applet_save_position (applet_info, applet_info->gconf_key, TRUE);
1143
1144        switch (applet_info->type) {
1145        case APPLET_BONOBO:
1146                panel_applet_frame_save_to_gconf (PANEL_APPLET_FRAME (applet_info->widget),
1147                                                  applet_info->gconf_key);
1148                break;
1149        case APPLET_DRAWER:
1150                drawer_save_to_gconf ((Drawer *) applet_info->data,
1151                                      applet_info->gconf_key);
1152                break;
1153        case APPLET_MENU:
1154                menu_save_to_gconf ((Menu *) applet_info->data,
1155                                    applet_info->gconf_key);
1156                break;
1157        case APPLET_LAUNCHER:
1158                launcher_save_to_gconf ((Launcher *) applet_info->data,
1159                                        applet_info->gconf_key);
1160                break;
1161        case APPLET_ACTION:
1162        case APPLET_LOGOUT:
1163        case APPLET_LOCK:
1164                panel_action_button_save_to_gconf (
1165                        PANEL_ACTION_BUTTON (applet_info->widget),
1166                        applet_info->gconf_key);
1167                break;
1168        default:
1169                break;
1170        }
1171}
1172
1173AppletInfo *
1174panel_applet_register (GtkWidget      *applet,
1175                       gpointer        data,
1176                       GDestroyNotify  data_destroy,
1177                       PanelWidget    *panel,
1178                       gint            pos,
1179                       gboolean        exactpos,
1180                       AppletType      type,
1181                       const char     *gconf_key)
1182{
1183        AppletInfo *info;
1184        int newpos;
1185        gboolean insert_at_pos;
1186        gboolean expand_major = FALSE, expand_minor = FALSE;
1187       
1188        g_return_val_if_fail (applet != NULL && panel != NULL, NULL);
1189
1190        if ( ! GTK_WIDGET_NO_WINDOW (applet))
1191                gtk_widget_set_events (applet, (gtk_widget_get_events (applet) |
1192                                                APPLET_EVENT_MASK) &
1193                                       ~( GDK_POINTER_MOTION_MASK |
1194                                          GDK_POINTER_MOTION_HINT_MASK));
1195
1196        info = g_new0 (AppletInfo, 1);
1197        info->applet_id = applet_count;
1198        info->type = type;
1199        info->widget = applet;
1200        info->menu = NULL;
1201        info->menu_age = 0;
1202        info->data = data;
1203        info->data_destroy = data_destroy;
1204        info->user_menu = NULL;
1205
1206        g_object_set_data (G_OBJECT (applet), "applet_info", info);
1207
1208        if (type == APPLET_DRAWER) {
1209                Drawer *drawer = data;
1210                PanelWidget *assoc_panel =
1211                        PANEL_WIDGET (BASEP_WIDGET (drawer->drawer)->panel);
1212
1213                g_object_set_data (G_OBJECT (applet),
1214                                   PANEL_APPLET_ASSOC_PANEL_KEY, assoc_panel);
1215                assoc_panel->master_widget = applet;
1216                g_object_add_weak_pointer (
1217                        G_OBJECT (applet), (gpointer *) &assoc_panel->master_widget);
1218        }
1219
1220        g_object_set_data (G_OBJECT (applet),
1221                           PANEL_APPLET_FORBIDDEN_PANELS, NULL);
1222
1223        if (type == APPLET_BONOBO)
1224                panel_applet_frame_get_expand_flags (PANEL_APPLET_FRAME (applet),
1225                                                     &expand_major,
1226                                                     &expand_minor);
1227       
1228        applets = g_slist_append (applets, info);
1229
1230        applet_count++;
1231
1232        /*we will need to save this applet's config now*/
1233        applets_to_sync = TRUE;
1234
1235        /*add at the beginning if pos == -1*/
1236        if (pos >= 0) {
1237                newpos = pos;
1238                insert_at_pos = FALSE;
1239        } else {
1240                newpos = 0;
1241                insert_at_pos = FALSE;
1242        }
1243        /* if exact pos is on then insert at that precise location */
1244        if (exactpos)
1245                insert_at_pos = TRUE;
1246
1247        if (panel_widget_add (panel, applet, newpos,
1248                              insert_at_pos, expand_major, expand_minor) == -1) {
1249                GSList *l;
1250
1251                for (l = panels; l; l = l->next)
1252                        if (panel_widget_add (panel, applet, 0, TRUE,
1253                                              expand_major, expand_minor) != -1)
1254                                break;
1255
1256                if (!l) {
1257                        panel_applet_clean (info, TRUE);
1258                        g_warning (_("Can't find an empty spot"));
1259                        return NULL;
1260                }
1261
1262                panel = PANEL_WIDGET (l->data);
1263        }
1264
1265        if (BUTTON_IS_WIDGET (applet) ||
1266            !GTK_WIDGET_NO_WINDOW (applet)) {
1267                g_signal_connect (applet, "button_press_event",
1268                                  G_CALLBACK (applet_button_press),
1269                                  info);
1270
1271                g_signal_connect (applet, "popup_menu",
1272                                  G_CALLBACK (applet_popup_menu),
1273                                  info);
1274        }
1275
1276        g_signal_connect (applet, "destroy",
1277                          G_CALLBACK (panel_applet_destroy),
1278                          info);
1279
1280        gtk_widget_show_all (applet);
1281
1282        orientation_change (info, panel);
1283        size_change (info, panel);
1284        back_change (info, panel);
1285
1286        if (gconf_key)
1287                info->gconf_key = g_strdup (gconf_key);
1288
1289        panel_applet_save_to_gconf (info);
1290
1291        if (type != APPLET_BONOBO)
1292                gtk_widget_grab_focus (applet);
1293        else
1294                gtk_widget_child_focus (applet, GTK_DIR_TAB_FORWARD);
1295
1296        return info;
1297}
1298
1299int
1300panel_applet_get_position (AppletInfo *applet)
1301{
1302        AppletData *applet_data;
1303
1304        g_return_val_if_fail (applet != NULL, 0);
1305        g_return_val_if_fail (G_IS_OBJECT (applet->widget), 0);
1306
1307        applet_data = g_object_get_data (G_OBJECT (applet->widget), PANEL_APPLET_DATA);
1308
1309        return applet_data->pos;
1310}
Note: See TracBrowser for help on using the repository browser.