source: trunk/third/gnome-core/panel/foobar-widget.c @ 17167

Revision 17167, 33.4 KB checked in by ghudson, 23 years ago (diff)
Merge with gnome-core 1.4.0.6.
Line 
1/* GNOME panel: foobar widget
2 * Copyright 1999,2000 Helix Code, Inc.
3 * Copyright 2000 Eazel, Inc.
4 *
5 * Author: Jacob Berkman
6 *
7 */
8
9/* since IS_BASEP_WIDGET() is used throughout, it makes life easier if we
10 * have a GtkWindow of our own.
11 */
12
13#include <config.h>
14#include <unistd.h>
15
16#include "foobar-widget.h"
17
18#include "menu.h"
19#include "menu-util.h"
20#include "session.h"
21#include "panel-widget.h"
22#include "xstuff.h"
23#include "basep-widget.h"
24#include "panel_config_global.h"
25#include "panel-util.h"
26#include "drawer-widget.h"
27#include "gnome-run.h"
28#include "scroll-menu.h"
29#include "gwmh.h"
30#include "tasklist_icon.h"
31#include "multiscreen-stuff.h"
32
33#define SMALL_ICON_SIZE 20
34
35extern GlobalConfig global_config;
36extern GSList *panel_list;
37
38extern GtkTooltips *panel_tooltips;
39
40static void foobar_widget_class_init    (FoobarWidgetClass      *klass);
41static void foobar_widget_init          (FoobarWidget           *foo);
42static void foobar_widget_realize       (GtkWidget              *w);
43static void foobar_widget_destroy       (GtkObject              *o);
44static void foobar_widget_size_allocate (GtkWidget              *w,
45                                         GtkAllocation          *alloc);
46static gboolean foobar_leave_notify     (GtkWidget *widget,
47                                         GdkEventCrossing *event);
48static gboolean foobar_enter_notify     (GtkWidget *widget,
49                                         GdkEventCrossing *event);
50static void append_task_menu (FoobarWidget *foo, GtkMenuBar *menu_bar);
51static void setup_task_menu (FoobarWidget *foo);
52
53static GList *foobars = NULL;
54
55static GtkWindowClass *parent_class = NULL;
56
57
58
59GtkType
60foobar_widget_get_type (void)
61{
62        static GtkType foobar_widget_type = 0;
63
64        if (!foobar_widget_type) {
65                GtkTypeInfo foobar_widget_info = {
66                        "FoobarWidget",
67                        sizeof (FoobarWidget),
68                        sizeof (FoobarWidgetClass),
69                        (GtkClassInitFunc) foobar_widget_class_init,
70                        (GtkObjectInitFunc) foobar_widget_init,
71                        (GtkArgSetFunc) NULL,
72                        (GtkArgGetFunc) NULL
73                };
74
75                foobar_widget_type = gtk_type_unique (gtk_window_get_type (),
76                                                      &foobar_widget_info);
77
78        }
79
80        return foobar_widget_type;
81}
82
83static void
84foobar_widget_class_init (FoobarWidgetClass *klass)
85{
86        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
87        GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
88
89        parent_class = gtk_type_class (gtk_window_get_type ());
90
91        object_class->destroy = foobar_widget_destroy;
92
93        widget_class->realize = foobar_widget_realize;
94        widget_class->size_allocate = foobar_widget_size_allocate;
95        widget_class->enter_notify_event = foobar_enter_notify;
96        widget_class->leave_notify_event = foobar_leave_notify;
97}
98
99static GtkWidget *
100pixmap_menu_item_new (const char *text, const char *try_file)
101{
102        GtkWidget *item;
103        GtkWidget *label;
104
105        item = gtk_pixmap_menu_item_new ();
106
107        if (try_file && gnome_preferences_get_menus_have_icons ()) {
108                GtkWidget *pixmap;
109                pixmap = gnome_stock_pixmap_widget_at_size (
110                        NULL, try_file, SMALL_ICON_SIZE, SMALL_ICON_SIZE);
111
112                if(pixmap) {
113                        gtk_widget_show (pixmap);
114                        gtk_pixmap_menu_item_set_pixmap
115                                (GTK_PIXMAP_MENU_ITEM (item), pixmap);
116                }
117        }
118
119        if (text) {
120                label = gtk_label_new (text);
121                gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
122                gtk_container_add (GTK_CONTAINER (item), label);
123        }
124
125        return item;
126}
127
128static void
129add_tearoff (GtkMenu *menu)
130{
131        GtkWidget *item;
132
133        if (!gnome_preferences_get_menus_have_tearoff ())
134                return;
135       
136        item = gtk_tearoff_menu_item_new ();
137        gtk_widget_show (item);
138        gtk_menu_prepend (menu, item);
139}
140
141static gboolean
142foobar_leave_notify (GtkWidget *widget,
143                     GdkEventCrossing *event)
144{
145        if (GTK_WIDGET_CLASS (parent_class)->leave_notify_event)
146                GTK_WIDGET_CLASS (parent_class)->leave_notify_event (widget,
147                                                                     event);
148
149        return FALSE;
150}
151
152static gboolean
153foobar_enter_notify (GtkWidget *widget,
154                     GdkEventCrossing *event)
155{
156        if (GTK_WIDGET_CLASS (parent_class)->enter_notify_event)
157                GTK_WIDGET_CLASS (parent_class)->enter_notify_event (widget,
158                                                                     event);
159
160        if (global_config.autoraise)
161                gdk_window_raise (widget->window);
162
163        return FALSE;
164}
165
166#if 0
167static void
168url_show (GtkWidget *w, const char *url)
169{
170        gnome_url_show (_(url));
171}
172
173static GtkWidget *
174url_menu_item (const char *label, const char *url, const char *pixmap)
175{
176        GtkWidget *item;
177        item = pixmap_menu_item_new (label, pixmap);
178        if (!label) gtk_widget_set_sensitive (item, FALSE);
179        gtk_signal_connect (GTK_OBJECT (item), "activate",
180                            GTK_SIGNAL_FUNC (url_show),
181                            (gpointer *)url);
182        return item;
183}
184
185static void
186about_cb (GtkWidget *w, gpointer data)
187{
188        char *v[2] = { "gnome-about" };
189        gnome_execute_async (g_get_home_dir (), 1, v);
190}
191#endif
192
193static void
194gmc_client (GtkWidget *w, gpointer data)
195{
196        char *v[3] = { "gmc-client" };
197        v[1] = data;
198        if(gnome_execute_async (g_get_home_dir (), 2, v) < 0)
199                panel_error_dialog(_("Cannot execute the gmc-client program,\n"
200                                     "perhaps gmc is not installed"));
201}
202
203static void
204gnomecal_client (GtkWidget *w, gpointer data)
205{
206        char *v[4] = { "gnomecal", "--view" };
207        v[2] = data;
208        if(gnome_execute_async (g_get_home_dir (), 3, v) < 0)
209                panel_error_dialog(_("Cannot execute the gnome calendar,\n"
210                                     "perhaps it's not installed.\n"
211                                     "It is in the gnome-pim package."));
212}
213
214#if 0
215static GtkWidget *
216append_gnome_menu (FoobarWidget *foo, GtkWidget *menu_bar)
217{
218        GtkWidget *item;
219        GtkWidget *menu;
220        int i;
221        char *url[][3] = {
222                { N_("News (www)"),                N_("http://gnotices.gnome.org/gnome-news/"),          "gnome-news.png" },
223                { N_("FAQ (www)"),                 N_("http://www.gnome.org/gnomefaq/html/"),            GNOME_STOCK_PIXMAP_HELP },
224                { N_("Mailing Lists (www)"),       N_("http://mail.gnome.org/mailman/listinfo/"),        GNOME_STOCK_PIXMAP_MAIL },
225                { NULL, "" },
226                { N_("Software (www)"),            N_("http://www.gnome.org/applist/list-martin.phtml"), GNOME_STOCK_PIXMAP_SAVE },
227                { N_("Development (www)"),         N_("http://developer.gnome.org/"),                    "gnome-devel.png" },
228                { N_("Bug Tracking System (www)"), N_("http://bugzilla.gnome.org/"),                         "bug-buddy.png" },
229                { NULL }
230        };
231       
232       
233        menu = hack_scroll_menu_new ();
234       
235        for (i=0; url[i][1]; i++)
236                gtk_menu_append (GTK_MENU (menu),
237                                 url_menu_item (_(url[i][0]), url[i][1],
238                                                url[i][2]));
239               
240        add_menu_separator (menu);
241
242        item = pixmap_menu_item_new (_("About GNOME"), GNOME_STOCK_MENU_ABOUT);
243        gtk_menu_append (GTK_MENU (menu), item);
244        gtk_signal_connect (GTK_OBJECT (item), "activate",
245                            GTK_SIGNAL_FUNC (about_cb), NULL);
246
247        add_tearoff (GTK_MENU (menu));
248
249        item = pixmap_menu_item_new ("", "gnome-spider.png");
250
251        gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
252        gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), item);
253        return item;
254}
255#endif
256
257static GtkWidget *
258append_gmc_item (GtkWidget *menu, const char *label, char *flag)
259{
260        GtkWidget *item;
261
262        item = gtk_menu_item_new_with_label (label);
263        gtk_menu_append (GTK_MENU (menu), item);
264        gtk_signal_connect (GTK_OBJECT (item), "activate",
265                            GTK_SIGNAL_FUNC (gmc_client), flag);
266
267        return item;
268}
269
270static gboolean
271display_gmc_menu (void)
272{
273        static gboolean checked_path = FALSE;
274        static gboolean got_gmc = FALSE;
275
276        if ( ! checked_path) {
277                char *gmc_client;
278                gmc_client = panel_is_program_in_path ("gmc-client");
279
280                if (gmc_client == NULL)
281                        got_gmc = FALSE;
282                else
283                        got_gmc = TRUE;
284
285                g_free (gmc_client);
286                checked_path = TRUE;
287        }
288
289        if ( ! got_gmc)
290                return FALSE;
291
292        if (xstuff_nautilus_desktop_present ())
293                return FALSE;
294
295        return TRUE;
296}
297
298static void
299desktop_selected (GtkWidget *widget, gpointer data)
300{
301        GList *gmc_menu_items = data;
302        GList *li;
303        gboolean gmc_menu = display_gmc_menu ();
304
305        for (li = gmc_menu_items; li != NULL; li = li->next) {
306                GtkWidget *item = li->data;
307
308                if (gmc_menu)
309                        gtk_widget_show (item);
310                else
311                        gtk_widget_hide (item);
312        }
313}
314
315static void
316append_desktop_menu (GtkWidget *menu_bar)
317{
318        GtkWidget *menu, *item;
319        char *char_tmp;
320        int i;
321        static char *arrange[] = {
322                N_("By Name"), "--arrange-desktop-icons=name",
323                N_("By Type"), "--arrange-desktop-icons=type",
324                N_("By Size"), "--arrange-desktop-icons=size",
325                N_("By Time Last Accessed"), "--arrange-desktop-icons=atime",
326                N_("By Time Last Modified"), "--arrange-desktop-icons=mtime",
327                N_("By Time Last Changed"),  "--arrange-desktop-icons=ctime",
328                NULL
329        };
330        GList *gmc_menu_items = NULL;
331
332        menu = hack_scroll_menu_new ();
333
334        for (i=0; arrange[i]; i+=2)
335                append_gmc_item (menu, _(arrange[i]), arrange[i+1]);
336
337        item = gtk_menu_item_new_with_label (_("Arrange Icons"));
338        gmc_menu_items = g_list_prepend (gmc_menu_items, item);
339        gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
340
341        add_tearoff (GTK_MENU (menu));
342
343        menu = hack_scroll_menu_new ();
344
345        gtk_menu_append (GTK_MENU (menu), item);
346
347        item = add_menu_separator (menu);
348        gmc_menu_items = g_list_prepend (gmc_menu_items, item);
349
350        item = append_gmc_item (menu, _("Rescan Desktop Directory"),
351                                "--rescan-desktop");
352        gmc_menu_items = g_list_prepend (gmc_menu_items, item);
353        item = append_gmc_item (menu, _("Rescan Desktop Devices"),
354                                "--rescan-desktop-devices");
355        gmc_menu_items = g_list_prepend (gmc_menu_items, item);
356
357        item = add_menu_separator (menu);
358        gmc_menu_items = g_list_prepend (gmc_menu_items, item);
359       
360        char_tmp = panel_is_program_in_path ("xss");
361        if (char_tmp) {
362                item = pixmap_menu_item_new (_("Lock Screen"),
363                                               "gnome-lockscreen.png");
364                gtk_menu_append (GTK_MENU (menu), item);
365                gtk_signal_connect (GTK_OBJECT (item), "activate",
366                                    GTK_SIGNAL_FUNC (panel_lock), 0);
367                setup_internal_applet_drag(item, "LOCK:NEW");
368
369                g_free (char_tmp);
370        }
371
372        item = pixmap_menu_item_new (_("Log Out"), "gnome-term-night.png");
373        gtk_menu_append (GTK_MENU (menu), item);
374        gtk_signal_connect (GTK_OBJECT (item), "activate",
375                            GTK_SIGNAL_FUNC(panel_quit), 0);
376        setup_internal_applet_drag (item, "LOGOUT:NEW");
377
378        add_tearoff (GTK_MENU (menu));
379
380        item = gtk_menu_item_new_with_label (_(" Desktop "));
381        gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
382        gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), item);
383
384        gtk_signal_connect_full (GTK_OBJECT (menu), "show",
385                                 GTK_SIGNAL_FUNC (desktop_selected),
386                                 NULL,
387                                 gmc_menu_items,
388                                 (GtkDestroyNotify) g_list_free,
389                                 FALSE,
390                                 FALSE);
391}
392
393static GtkWidget *
394append_folder_menu (GtkWidget *menu_bar, const char *label,
395                    const char *pixmap, gboolean system, const char *path)
396{
397        GtkWidget *item, *menu;
398        char *real_path;
399
400        real_path = system
401                ? gnome_unconditional_datadir_file (path)
402                : gnome_util_home_file (path);
403
404        if (real_path == NULL) {
405                g_warning (_("can't find real path"));
406                return NULL;
407        }
408
409        menu = create_fake_menu_at (real_path,
410                                    FALSE /* applets */,
411                                    FALSE /* launcher_add */,
412                                    FALSE /* favourites_add */,
413                                    label /* dir_name */,
414                                    NULL /* pixmap_name */,
415                                    FALSE /* title */);
416        g_free (real_path);
417        if (path != NULL && strcmp (path, "apps") == 0)
418                /* This will add the add submenu thingie */
419                start_favourites_menu (menu, TRUE /* fake_submenus */);
420
421        if (menu == NULL) {
422                g_warning (_("menu wasn't created"));
423                return NULL;
424        }
425
426        if (pixmap)
427                item = pixmap_menu_item_new (label, pixmap);
428        else
429                item = gtk_menu_item_new_with_label (label);
430        gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
431        gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), item);
432
433        gtk_signal_connect (GTK_OBJECT (menu), "show",
434                            GTK_SIGNAL_FUNC (submenu_to_display),
435                            NULL);
436
437        return menu;
438}
439
440static void
441append_gnomecal_item (GtkWidget *menu, const char *label, const char *flag)
442{
443        GtkWidget *item = gtk_menu_item_new_with_label (label);
444        gtk_menu_append (GTK_MENU (menu), item);
445        gtk_signal_connect (GTK_OBJECT (item), "activate",
446                            GTK_SIGNAL_FUNC (gnomecal_client), (gpointer)flag);
447}
448
449static void
450update_clock (FoobarWidget *foo)
451{
452        static int day = 0;
453        struct tm *das_tm;
454        time_t das_time;
455        char hour[256];
456
457        if (foo->clock_label == NULL)
458                return;
459
460        time (&das_time);
461        das_tm = localtime (&das_time);
462
463        if (das_tm->tm_mday != day) {
464                if(strftime(hour, sizeof(hour), _("%A %B %d"), das_tm) == 0) {
465                        /* according to docs, if the string does not fit, the
466                         * contents of tmp2 are undefined, thus just use
467                         * ??? */
468                        strcpy(hour, "???");
469                }
470                hour[sizeof(hour)-1] = '\0'; /* just for sanity */
471
472                gtk_tooltips_set_tip (panel_tooltips, foo->clock_ebox,
473                                      hour, NULL);
474
475                day = das_tm->tm_mday;
476        }
477
478        if(strftime(hour, sizeof(hour), foo->clock_format, das_tm) == 0) {
479                /* according to docs, if the string does not fit, the
480                 * contents of tmp2 are undefined, thus just use
481                 * ??? */
482                strcpy(hour, "???");
483        }
484        hour[sizeof(hour)-1] = '\0'; /* just for sanity */
485
486        gtk_label_set_text (GTK_LABEL (foo->clock_label), hour);
487}
488
489static int
490timeout_cb (gpointer data)
491{
492        FoobarWidget *foo = FOOBAR_WIDGET (data);
493
494        if (foo->clock_label == NULL) {
495                foo->clock_timeout = 0;
496                return FALSE;
497        }
498
499        update_clock (foo);
500
501        return TRUE;
502}
503
504static void
505set_fooclock_format (GtkWidget *w, char *format)
506{
507        GList *li;
508
509        for (li = foobars; li != NULL; li = li->next) {
510                foobar_widget_set_clock_format (FOOBAR_WIDGET (li->data),
511                                                _(format));
512        }
513}
514
515static void
516append_format_item (GtkWidget *menu, const char *format)
517{
518        char hour[256];
519        GtkWidget *item;
520        struct tm *das_tm;
521        time_t das_time = 43200;
522
523        das_tm = localtime (&das_time);
524        if (strftime (hour, sizeof(hour), _(format), das_tm) == 0) {
525                /* according to docs, if the string does not fit, the
526                 * contents of tmp2 are undefined, thus just use
527                 * ??? */
528                strcpy(hour, "???");
529        }
530        hour[sizeof(hour)-1] = '\0'; /* just for sanity */
531
532        item = gtk_menu_item_new_with_label (hour);
533        gtk_menu_append (GTK_MENU (menu), item);
534        gtk_signal_connect (GTK_OBJECT (item), "activate",
535                            GTK_SIGNAL_FUNC (set_fooclock_format),
536                            (gpointer)format);
537}
538
539static void
540set_time_cb (GtkWidget *menu_item, char *path)
541{
542        char *v[2] = { path };
543       
544        if (gnome_execute_async (g_get_home_dir (), 1, v) < 0)
545                panel_error_dialog (_("Could not call time-admin\n"
546                                                  "Perhaps time-admin is not installed"));
547}
548
549static GtkWidget *
550append_clock_menu (FoobarWidget *foo, GtkWidget *menu_bar)
551{
552        GtkWidget *item, *menu, *menu2;
553        gchar *time_admin_path;
554        int i;
555        const char *cals[] = {
556                N_("Today"),      "dayview",
557                N_("This Week"),  "weekview",
558                N_("This Month"), "monthview",
559                NULL
560        };
561
562        const char *formats[] = {
563                N_("%H:%M"),
564                N_("%H:%M:%S"),
565                N_("%l:%M %p"),
566                N_("%l:%M:%S %p"),
567                NULL
568        };
569
570        menu = hack_scroll_menu_new ();
571       
572#if 0 /* put back when evolution can do this */
573        item = gtk_menu_item_new_with_label (_("Add appointement..."));
574        gtk_menu_append (GTK_MENU (menu), item);
575
576        add_menu_separator (menu);
577#endif
578
579        time_admin_path = gnome_is_program_in_path ("time-admin");
580        if (time_admin_path) {
581                item = gtk_menu_item_new_with_label (_("Set Time"));
582                gtk_signal_connect (GTK_OBJECT (item), "activate",
583                                                GTK_SIGNAL_FUNC (set_time_cb), time_admin_path);
584                gtk_menu_append (GTK_MENU (menu), item);
585                add_menu_separator (menu);
586        }
587
588        for (i=0; cals[i]; i+=2)
589                append_gnomecal_item (menu, _(cals[i]), cals[i+1]);
590
591        add_menu_separator (menu);
592
593        menu2 = hack_scroll_menu_new ();
594        for (i=0; formats[i]; i++)
595                append_format_item (menu2, formats[i]);
596
597        add_tearoff (GTK_MENU (menu2));
598
599        item = gtk_menu_item_new_with_label (_("Format"));
600        gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu2);
601        gtk_menu_append (GTK_MENU (menu), item);
602
603        add_tearoff (GTK_MENU (menu));
604
605        item = gtk_menu_item_new ();
606
607        foo->clock_label = gtk_label_new ("");
608        foo->clock_timeout = gtk_timeout_add (1000, timeout_cb, foo);
609
610        foo->clock_ebox = item;
611        gtk_container_add (GTK_CONTAINER (item), foo->clock_label);
612        gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
613
614        gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), item);
615
616        return item;
617}
618
619void
620foobar_widget_global_set_clock_format (const char *format)
621{
622        GList *li;
623
624        for (li = foobars; li != NULL; li = li->next) {
625                foobar_widget_set_clock_format (FOOBAR_WIDGET (li->data),
626                                                format);
627        }
628}
629
630void
631foobar_widget_set_clock_format (FoobarWidget *foo, const char *clock_format)
632{
633        g_free (foo->clock_format);
634        foo->clock_format = g_strdup (clock_format);
635
636        update_clock (foo);
637}
638
639void
640foobar_widget_update_winhints (FoobarWidget *foo)
641{
642        GtkWidget *w = GTK_WIDGET (foo);
643        GnomeWinLayer layer;
644
645        if ( ! foo->compliant_wm)
646                return;
647
648        xstuff_set_pos_size (w->window,
649                             multiscreen_x (foo->screen),
650                             multiscreen_y (foo->screen),
651                             w->allocation.width,
652                             w->allocation.height);
653
654        gnome_win_hints_set_expanded_size (w, 0, 0, 0, 0);
655        gdk_window_set_decorations (w->window, 0);
656        gnome_win_hints_set_state (w, WIN_STATE_STICKY |
657                                   WIN_STATE_FIXED_POSITION);
658       
659        gnome_win_hints_set_hints (w, GNOME_PANEL_HINTS |
660                                   WIN_HINTS_DO_NOT_COVER);     
661        if (global_config.normal_layer) {
662                layer = WIN_LAYER_NORMAL;
663        } else if (global_config.keep_bottom) {
664                layer = WIN_LAYER_BELOW;
665        } else {
666                layer = WIN_LAYER_DOCK;
667        }
668        gnome_win_hints_set_layer (w, layer);
669}
670
671static void
672foobar_widget_realize (GtkWidget *w)
673{
674        gtk_window_set_wmclass (GTK_WINDOW (w),
675                                "panel_window", "Panel");
676
677        if (GTK_WIDGET_CLASS (parent_class)->realize)
678                GTK_WIDGET_CLASS (parent_class)->realize (w);
679
680        foobar_widget_update_winhints (FOOBAR_WIDGET (w));
681        xstuff_set_no_group_and_no_input (w->window);
682
683        setup_task_menu (FOOBAR_WIDGET (w));
684}
685
686static void
687programs_menu_to_display(GtkWidget *menu)
688{
689        if(menu_need_reread(menu)) {
690                int flags;
691
692                while(GTK_MENU_SHELL(menu)->children)
693                        gtk_widget_destroy(GTK_MENU_SHELL(menu)->children->data);
694                flags = (get_default_menu_flags() &
695                         ~(MAIN_MENU_SYSTEM_SUB | MAIN_MENU_USER |
696                           MAIN_MENU_USER_SUB | MAIN_MENU_PANEL |
697                           MAIN_MENU_PANEL_SUB | MAIN_MENU_DESKTOP |
698                           MAIN_MENU_DESKTOP_SUB)) |
699                        MAIN_MENU_SYSTEM;
700                create_root_menu (menu, TRUE, flags, TRUE, FALSE, FALSE);
701        }
702}
703
704static void
705set_the_task_submenu (FoobarWidget *foo, GtkWidget *item)
706{
707        foo->task_menu = hack_scroll_menu_new ();
708        gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), foo->task_menu);
709        /*g_message ("setting...");*/
710}
711
712static void
713focus_task (GtkWidget *w, GwmhTask *task)
714{
715        gwmh_desk_set_current_area (task->desktop, task->harea, task->varea);
716        if (GWMH_TASK_ICONIFIED (task))
717                gwmh_task_deiconify (task);
718        gwmh_task_show  (task);
719        gwmh_task_raise (task);
720        gwmh_task_focus (task);
721}
722
723static void
724add_task (GwmhTask *task, FoobarWidget *foo)
725{
726        GtkWidget *item, *label;
727        char *title = NULL;
728        int slen;
729        GtkWidget *pixmap  = NULL;
730
731        static GwmhDesk *desk = NULL;
732
733        g_assert (foo->tasks);
734
735        if (GWMH_TASK_SKIP_WINLIST (task))
736                return;
737        if (task->name != NULL) {
738                slen = strlen (task->name);
739                if (slen > 443)
740                        title = g_strdup_printf ("%.420s...%s", task->name, task->name+slen-20);
741                else
742                        title = g_strdup (task->name);
743        } else {
744                /* Translators: Task with no name, should not really happen, so
745                 * this should signal that the panel is confused by this task
746                 * (thus question marks) */
747                title = g_strdup (_("???"));
748        }
749
750        if (GWMH_TASK_ICONIFIED (task)) {
751                char *tmp = title;
752                title = g_strdup_printf ("[%s]", title);
753                g_free (tmp);
754        }
755       
756        item = gtk_pixmap_menu_item_new ();
757        pixmap = get_task_icon (task, GTK_WIDGET (foo));
758        if (pixmap != NULL) {
759                gtk_widget_show (pixmap);
760                gtk_pixmap_menu_item_set_pixmap (GTK_PIXMAP_MENU_ITEM (item),
761                                                 pixmap);
762        }
763
764        label = gtk_label_new (title);
765        g_free (title);
766
767        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
768        gtk_container_add (GTK_CONTAINER (item), label);
769        g_hash_table_insert (foo->tasks, task, item);
770        gtk_signal_connect (GTK_OBJECT (item), "activate",
771                            GTK_SIGNAL_FUNC (focus_task),
772                            task);
773        gtk_widget_show_all (item);
774       
775        if (!desk)
776                desk = gwmh_desk_get_config ();
777
778        if (task->desktop == desk->current_desktop &&
779            task->harea   == desk->current_harea   &&
780            task->varea   == desk->current_varea)
781                gtk_menu_prepend (GTK_MENU (foo->task_menu), item);
782        else
783                gtk_menu_append (GTK_MENU (foo->task_menu), item);
784}
785
786static void
787create_task_menu (GtkWidget *w, gpointer data)
788{
789        FoobarWidget *foo = FOOBAR_WIDGET (data);
790        GList *tasks = gwmh_task_list_get ();
791        GList *list;
792        GtkWidget *separator;
793
794        /*g_message ("creating...");*/
795        foo->tasks = g_hash_table_new (g_direct_hash, g_direct_equal);
796
797        separator = add_menu_separator (foo->task_menu);
798
799        g_list_foreach (tasks, (GFunc)add_task, foo);
800
801        list = g_list_last (GTK_MENU_SHELL (foo->task_menu)->children);
802
803        if (list != NULL &&
804            separator == list->data) {
805                /* if the separator is the last item wipe it.
806                 * We leave it as the first though */
807                gtk_widget_destroy (separator);
808        }
809
810        /* Owen: don't read the next line */
811        GTK_MENU_SHELL (GTK_MENU_ITEM (w)->submenu)->active = 1;
812        our_gtk_menu_position (GTK_MENU (GTK_MENU_ITEM (w)->submenu));
813}
814
815static void
816destroy_task_menu (GtkWidget *w, gpointer data)
817{
818        FoobarWidget *foo = FOOBAR_WIDGET (data);
819        /*g_message ("removing...");*/
820        gtk_menu_item_remove_submenu (GTK_MENU_ITEM (w));
821        g_hash_table_destroy (foo->tasks);
822        foo->tasks = NULL;
823        set_the_task_submenu (foo, w);
824}
825
826static GtkWidget *
827get_default_pixmap (void)
828{
829        GtkWidget *widget;
830        static GdkPixmap *pixmap = NULL;
831        static GdkBitmap *mask   = NULL;
832        static gboolean looked   = FALSE;
833
834        if ( ! looked) {
835                GdkPixbuf *pb = NULL, *scaled = NULL;
836                pb = gdk_pixbuf_new_from_file (GNOME_ICONDIR"/gnome-tasklist.png");
837               
838                if (pb != NULL) {
839                        scaled = gdk_pixbuf_scale_simple (pb, 20, 20,
840                                                          GDK_INTERP_BILINEAR);
841                        gdk_pixbuf_unref (pb);
842                }
843
844                if (scaled != NULL) {
845                        gdk_pixbuf_render_pixmap_and_mask (scaled,
846                                                           &pixmap, &mask, 128);
847                        gdk_pixbuf_unref (scaled);
848                       
849                        if (pixmap != NULL)
850                                gdk_pixmap_ref (pixmap);
851
852                        if (mask != NULL)
853                                gdk_bitmap_ref (mask);
854                }
855
856                looked = TRUE;
857        }
858        if (pixmap != NULL)
859                widget = gtk_pixmap_new (pixmap, mask);
860        else
861                widget = gtk_label_new ("*");
862        gtk_widget_show (widget);
863
864        return widget;
865}
866
867static void
868set_das_pixmap (FoobarWidget *foo, GwmhTask *task)
869{
870        if (!GTK_WIDGET_REALIZED (foo))
871                return;
872
873        foo->icon_task = NULL;
874
875        if (foo->task_pixmap != NULL)
876                gtk_widget_destroy (foo->task_pixmap);
877        foo->task_pixmap = NULL;
878
879        if (task != NULL) {
880                foo->task_pixmap = get_task_icon (task, GTK_WIDGET (foo));
881                foo->icon_task = task;
882        }
883
884        if (foo->task_pixmap == NULL) {
885                foo->task_pixmap = get_default_pixmap ();
886        }
887
888        if (foo->task_pixmap != NULL) {
889                gtk_container_add (GTK_CONTAINER (foo->task_bin),
890                                   foo->task_pixmap);
891        }
892}
893
894static gboolean
895task_notify (gpointer data,
896             GwmhTask *task,
897             GwmhTaskNotifyType ntype,
898             GwmhTaskInfoMask imask)
899{
900        FoobarWidget *foo = FOOBAR_WIDGET (data);
901        GtkWidget *item;
902
903        switch (ntype) {
904        case GWMH_NOTIFY_INFO_CHANGED:
905                if (imask & GWMH_TASK_INFO_WM_HINTS &&
906                    GWMH_TASK_FOCUSED (task)) {
907                        /* icon might have changed */
908                        set_das_pixmap (foo, task);
909                } else if (imask & GWMH_TASK_INFO_FOCUSED) {
910                        if (GWMH_TASK_FOCUSED (task) &&
911                            foo->icon_task != task) {
912                                /* Focused and not set in the top thingie,
913                                 * so setup */
914                                set_das_pixmap (foo, task);
915                        } else if ( ! GWMH_TASK_FOCUSED (task) &&
916                                   task == foo->icon_task) {
917                                /* Just un-focused and currently the
918                                 * icon_task, so set the pixmap to
919                                 * the default (nothing) */
920                                set_das_pixmap (foo, NULL);
921                        }
922                }
923                break;
924        case GWMH_NOTIFY_NEW:
925                if (foo->tasks != NULL)
926                        add_task (task, foo);
927                break;
928        case GWMH_NOTIFY_DESTROY:
929                if (task == foo->icon_task)
930                        set_das_pixmap (foo, NULL);
931                /* FIXME: Whoa; leak? */
932                if (foo->tasks != NULL) {
933                        item = g_hash_table_lookup (foo->tasks, task);
934                        if (item) {
935                                g_hash_table_remove (foo->tasks, task);
936                                gtk_widget_hide (item);
937                        } else {
938                                g_warning ("Could not find item for task '%s'",
939                                           sure_string (task->name));
940                        }
941                }
942                break;
943        default:
944                break;
945        }
946        return TRUE;
947}
948
949static void
950append_task_menu (FoobarWidget *foo, GtkMenuBar *menu_bar)
951{
952        foo->task_item = gtk_menu_item_new ();
953
954        foo->task_bin = gtk_alignment_new (0.3, 0.5, 0.0, 0.0);
955        gtk_widget_set_usize (foo->task_bin, 25, 20);
956        gtk_widget_show (foo->task_bin);
957        gtk_container_add (GTK_CONTAINER (foo->task_item), foo->task_bin);
958
959        gtk_menu_bar_append (menu_bar, foo->task_item);
960}
961
962static void
963setup_task_menu (FoobarWidget *foo)
964{
965        GList *tasks;
966        g_assert (foo->task_item != NULL);
967
968        gtk_signal_connect (GTK_OBJECT (foo->task_item), "select",
969                            GTK_SIGNAL_FUNC (create_task_menu), foo);
970        gtk_signal_connect (GTK_OBJECT (foo->task_item), "deselect",
971                            GTK_SIGNAL_FUNC (destroy_task_menu), foo);
972
973        set_the_task_submenu (foo, foo->task_item);
974
975        /* setup the pixmap to the focused task */
976        tasks = gwmh_task_list_get ();
977        while (tasks != NULL) {
978                if (GWMH_TASK_FOCUSED (tasks->data)) {
979                        set_das_pixmap  (foo, tasks->data);
980                        break;
981                }
982                tasks = tasks->next;
983        }
984
985        /* if no focused task found, then just set it to default */
986        if (tasks == NULL)
987                set_das_pixmap  (foo, NULL);
988
989        foo->notify = gwmh_task_notifier_add (task_notify, foo);
990}
991
992static void
993foobar_widget_init (FoobarWidget *foo)
994{
995        /*gchar *path;*/
996        GtkWindow *window = GTK_WINDOW (foo);
997        /*GtkWidget *bufmap;*/
998        GtkWidget *menu_bar, *bar;
999        GtkWidget *menu, *menuitem;
1000        /*GtkWidget *align;*/
1001        gint flags;
1002
1003        foo->screen = 0;
1004
1005        foo->task_item = NULL;
1006        foo->task_menu = NULL;
1007        foo->task_pixmap = NULL;
1008        foo->task_bin = NULL;
1009        foo->icon_task = NULL;
1010
1011        foo->clock_format = g_strdup (_("%H:%M"));
1012        foo->clock_timeout = 0;
1013        foo->clock_label = NULL;
1014
1015        foo->compliant_wm = xstuff_is_compliant_wm ();
1016        if(foo->compliant_wm)
1017                GTK_WINDOW(foo)->type = GTK_WINDOW_TOPLEVEL;
1018        else
1019                GTK_WINDOW(foo)->type = GTK_WINDOW_POPUP;
1020
1021        window->allow_shrink = TRUE;
1022        window->allow_grow   = TRUE;
1023        window->auto_shrink  = TRUE;
1024
1025        gtk_signal_connect (GTK_OBJECT (foo), "delete_event",
1026                            GTK_SIGNAL_FUNC (gtk_true), NULL);
1027
1028        gtk_widget_set_uposition (GTK_WIDGET (foo),
1029                                  multiscreen_x (foo->screen),
1030                                  multiscreen_y (foo->screen));
1031        gtk_widget_set_usize (GTK_WIDGET (foo),
1032                              multiscreen_width (foo->screen), -2);
1033
1034        foo->ebox = gtk_event_box_new ();
1035        foo->hbox = gtk_hbox_new (FALSE, 0);
1036        gtk_container_add(GTK_CONTAINER(foo->ebox), foo->hbox);
1037
1038#if 0   
1039        path = gnome_pixmap_file ("panel/corner1.png");
1040        bufmap = gnome_pixmap_new_from_file (path);
1041        g_free (path);
1042        align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
1043        gtk_container_add (GTK_CONTAINER (align), bufmap);
1044        gtk_box_pack_start (GTK_BOX (foo->hbox), align, FALSE, FALSE, 0);
1045#endif
1046
1047        menu_bar = gtk_menu_bar_new ();
1048        gtk_menu_bar_set_shadow_type (GTK_MENU_BAR (menu_bar),
1049                                      GTK_SHADOW_NONE);
1050       
1051       
1052        menuitem = pixmap_menu_item_new (_("Programs"),
1053                                         "gnome-logo-icon-transparent.png");
1054        flags = (get_default_menu_flags() &
1055                 ~(MAIN_MENU_SYSTEM_SUB | MAIN_MENU_USER | MAIN_MENU_USER_SUB |
1056                   MAIN_MENU_PANEL | MAIN_MENU_PANEL_SUB | MAIN_MENU_DESKTOP |
1057                   MAIN_MENU_DESKTOP_SUB)) | MAIN_MENU_SYSTEM;
1058        menu = create_root_menu (NULL, TRUE, flags, TRUE, FALSE, FALSE);
1059        gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu);
1060        gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), menuitem);
1061        gtk_signal_connect (GTK_OBJECT (menu), "show",
1062                            GTK_SIGNAL_FUNC (programs_menu_to_display),
1063                            NULL);
1064        foo->programs = menu;
1065
1066        foo->favorites =
1067                append_folder_menu(menu_bar, _("Favorites"), NULL,
1068                                   FALSE, "apps");
1069        foo->settings =
1070                append_folder_menu(menu_bar, _("Settings"),  NULL, TRUE,
1071                                   "gnome/apps/Settings");
1072        append_desktop_menu (menu_bar);
1073
1074        gtk_box_pack_start (GTK_BOX (foo->hbox), menu_bar, FALSE, FALSE, 0);
1075       
1076       
1077        /* panel widget */
1078        foo->panel = panel_widget_new (FALSE, PANEL_HORIZONTAL,
1079                                       SIZE_TINY, PANEL_BACK_NONE,
1080                                       NULL, FALSE, FALSE, FALSE, TRUE, NULL);
1081        PANEL_WIDGET (foo->panel)->panel_parent = GTK_WIDGET (foo);
1082        PANEL_WIDGET (foo->panel)->drop_widget = GTK_WIDGET (foo);
1083
1084        gtk_container_add (GTK_CONTAINER (foo->hbox), foo->panel);
1085
1086        gtk_object_set_data (GTK_OBJECT (menu_bar), "menu_panel", foo->panel);
1087
1088#if 0
1089        path = gnome_pixmap_file ("panel/corner2.png");
1090        bufmap = gnome_pixmap_new_from_file (path);
1091        g_free (path);
1092        align = gtk_alignment_new (1.0, 0.0, 1.0, 0.0);
1093        gtk_container_add (GTK_CONTAINER (align), bufmap);
1094        gtk_box_pack_end (GTK_BOX (foo->hbox), align, FALSE, FALSE, 0);
1095#endif
1096
1097        bar = menu_bar = gtk_menu_bar_new ();
1098        gtk_menu_bar_set_shadow_type (GTK_MENU_BAR (menu_bar),
1099                                      GTK_SHADOW_NONE);
1100        append_clock_menu (foo, menu_bar);
1101#if 0
1102        /* TODO: use the gnome menu if no gnome compliant WM or tasklist disabled */
1103        append_gnome_menu (foo, menu_bar);
1104#endif
1105        append_task_menu (foo, GTK_MENU_BAR (bar));
1106
1107
1108        gtk_box_pack_end (GTK_BOX (foo->hbox), menu_bar, FALSE, FALSE, 0);
1109        gtk_container_add (GTK_CONTAINER (foo), foo->ebox);
1110        gtk_widget_show_all (foo->ebox);
1111}
1112
1113static void
1114queue_panel_resize (gpointer data, gpointer user_data)
1115{
1116        PanelData *pd = data;
1117        GtkWidget *panel;
1118
1119        g_assert (pd);
1120
1121        panel = pd->panel;
1122
1123        g_return_if_fail (GTK_IS_WIDGET (panel));
1124
1125        if (!IS_DRAWER_WIDGET (panel) && !IS_FOOBAR_WIDGET (panel))
1126                gtk_widget_queue_resize (panel);
1127}
1128
1129static void
1130foobar_widget_destroy (GtkObject *o)
1131{
1132        FoobarWidget *foo = FOOBAR_WIDGET (o);
1133
1134        foobars = g_list_remove (foobars, foo);
1135
1136        if (foo->clock_timeout != 0)
1137                gtk_timeout_remove (foo->clock_timeout);
1138        foo->clock_timeout = 0;
1139       
1140        foo->clock_label = NULL;
1141
1142        g_free (foo->clock_format);
1143        foo->clock_format = NULL;
1144
1145        g_slist_foreach (panel_list, queue_panel_resize, NULL);
1146
1147        if (foo->tasks != NULL)
1148                g_hash_table_destroy (foo->tasks);
1149        foo->tasks = NULL;
1150        if (foo->notify > 0)
1151                gwmh_task_notifier_remove (foo->notify);
1152        foo->notify = 0;
1153
1154        if (GTK_OBJECT_CLASS (parent_class)->destroy)
1155                GTK_OBJECT_CLASS (parent_class)->destroy (o);
1156}
1157
1158static void
1159foobar_widget_size_allocate (GtkWidget *w, GtkAllocation *alloc)
1160{
1161        if (GTK_WIDGET_CLASS (parent_class)->size_allocate)
1162                GTK_WIDGET_CLASS (parent_class)->size_allocate (w, alloc);
1163
1164        if (GTK_WIDGET_REALIZED (w)) {
1165                FoobarWidget *foo = FOOBAR_WIDGET (w);
1166                xstuff_set_pos_size (w->window,
1167                                     multiscreen_x (foo->screen),
1168                                     multiscreen_y (foo->screen),
1169                                     alloc->width,
1170                                     alloc->height);
1171
1172                g_slist_foreach (panel_list, queue_panel_resize, NULL);
1173                basep_border_queue_recalc (foo->screen);
1174        }
1175}
1176
1177GtkWidget *
1178foobar_widget_new (int screen)
1179{
1180        FoobarWidget *foo;
1181
1182        g_return_val_if_fail (screen >= 0, NULL);
1183
1184        if (foobar_widget_exists (screen))
1185                return NULL;
1186
1187        foo = gtk_type_new (TYPE_FOOBAR_WIDGET);
1188
1189        foo->screen = screen;
1190        gtk_widget_set_uposition (GTK_WIDGET (foo),
1191                                  multiscreen_x (foo->screen),
1192                                  multiscreen_y (foo->screen));
1193        gtk_widget_set_usize (GTK_WIDGET (foo),
1194                              multiscreen_width (foo->screen), -2);
1195
1196        foobars = g_list_prepend (foobars, foo);
1197
1198        return GTK_WIDGET (foo);
1199}
1200
1201gboolean
1202foobar_widget_exists (int screen)
1203{
1204        GList *li;
1205
1206        for (li = foobars; li != NULL; li = li->next) {
1207                FoobarWidget *foo = li->data;
1208
1209                if (foo->screen == screen)
1210                        return TRUE;
1211        }
1212        return FALSE;
1213}
1214
1215void
1216foobar_widget_force_menu_remake (void)
1217{
1218        FoobarWidget *foo;
1219        GList *li;
1220
1221        for (li = foobars; li != NULL; li = li->next) {
1222                foo = FOOBAR_WIDGET(li->data);
1223
1224                if (foo->programs != NULL)
1225                        gtk_object_set_data (GTK_OBJECT(foo->programs),
1226                                             "need_reread", GINT_TO_POINTER(1));
1227                if (foo->settings != NULL)
1228                        gtk_object_set_data (GTK_OBJECT(foo->settings),
1229                                             "need_reread", GINT_TO_POINTER(1));
1230                if (foo->favorites != NULL)
1231                        gtk_object_set_data (GTK_OBJECT(foo->favorites),
1232                                             "need_reread", GINT_TO_POINTER(1));
1233        }
1234}
1235
1236gint
1237foobar_widget_get_height (int screen)
1238{
1239        GList *li;
1240
1241        g_return_val_if_fail (screen >= 0, 0);
1242
1243        for (li = foobars; li != NULL; li = li->next) {
1244                FoobarWidget *foo = FOOBAR_WIDGET(li->data);
1245
1246                if (foo->screen == screen)
1247                        return GTK_WIDGET (foo)->allocation.height;
1248        }
1249        return 0;
1250}
1251
1252static void
1253reparent_button_widgets(GtkWidget *w, gpointer data)
1254{
1255        GdkWindow *newwin = data;
1256        if (IS_BUTTON_WIDGET (w)) {
1257                ButtonWidget *button = BUTTON_WIDGET(w);
1258                /* we can just reparent them all to 0,0 as the next thing
1259                 * that will happen is a queue_resize and on size allocate
1260                 * they will be put into their proper place */
1261                gdk_window_reparent (button->event_window, newwin, 0, 0);
1262        }
1263}
1264
1265void
1266foobar_widget_redo_window(FoobarWidget *foo)
1267{
1268        GtkWindow *window;
1269        GtkWidget *widget;
1270        GdkWindowAttr attributes;
1271        gint attributes_mask;
1272        GdkWindow *oldwin;
1273        GdkWindow *newwin;
1274        gboolean comp;
1275
1276        comp = xstuff_is_compliant_wm();
1277        if (comp == foo->compliant_wm)
1278                return;
1279
1280        window = GTK_WINDOW(foo);
1281        widget = GTK_WIDGET(foo);
1282
1283        foo->compliant_wm = comp;
1284        if (foo->compliant_wm) {
1285                window->type = GTK_WINDOW_TOPLEVEL;
1286                attributes.window_type = GDK_WINDOW_TOPLEVEL;
1287        } else {
1288                window->type = GTK_WINDOW_POPUP;
1289                attributes.window_type = GDK_WINDOW_TEMP;
1290        }
1291
1292        if (widget->window == NULL)
1293                return;
1294
1295        /* this is mostly copied from gtkwindow.c realize method */
1296        attributes.title = window->title;
1297        attributes.wmclass_name = window->wmclass_name;
1298        attributes.wmclass_class = window->wmclass_class;
1299        attributes.width = widget->allocation.width;
1300        attributes.height = widget->allocation.height;
1301        attributes.wclass = GDK_INPUT_OUTPUT;
1302        attributes.visual = gtk_widget_get_visual (widget);
1303        attributes.colormap = gtk_widget_get_colormap (widget);
1304        attributes.event_mask = gtk_widget_get_events (widget);
1305        attributes.event_mask |= (GDK_EXPOSURE_MASK |
1306                                  GDK_KEY_PRESS_MASK |
1307                                  GDK_ENTER_NOTIFY_MASK |
1308                                  GDK_LEAVE_NOTIFY_MASK |
1309                                  GDK_FOCUS_CHANGE_MASK |
1310                                  GDK_STRUCTURE_MASK);
1311
1312        attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
1313        attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
1314        attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
1315   
1316        oldwin = widget->window;
1317
1318        newwin = gdk_window_new(NULL, &attributes, attributes_mask);
1319        gdk_window_set_user_data(newwin, window);
1320
1321        xstuff_set_no_group_and_no_input (newwin);
1322
1323        /* reparent our main panel window */
1324        gdk_window_reparent(foo->ebox->window, newwin, 0, 0);
1325        /* reparent all the base event windows as they are also children of
1326         * the foobar */
1327        gtk_container_foreach(GTK_CONTAINER(foo->panel),
1328                              reparent_button_widgets,
1329                              newwin);
1330
1331
1332        widget->window = newwin;
1333
1334        gdk_window_set_user_data(oldwin, NULL);
1335        gdk_window_destroy(oldwin);
1336
1337        widget->style = gtk_style_attach(widget->style, widget->window);
1338        gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
1339
1340        GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1341
1342        gtk_widget_queue_resize(widget);
1343
1344        foobar_widget_update_winhints (foo);
1345
1346        gtk_drag_dest_set (widget, 0, NULL, 0, 0);
1347
1348        gtk_widget_map(widget);
1349}
Note: See TracBrowser for help on using the repository browser.