Use <USER_CONFIG_DIR>/lxpanel/<profile>/gtkrc for panel custom style setup.
[lxde/lxpanel.git] / src / panel.c
1 /**
2 * Copyright (c) 2006 LxDE Developers, see the file AUTHORS for details.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <glib/gi18n.h>
24 #include <stdlib.h>
25 #include <glib/gstdio.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <locale.h>
31 #include <string.h>
32 #include <gdk/gdkx.h>
33 #include <libfm/fm-gtk.h>
34
35 #define __LXPANEL_INTERNALS__
36
37 #include "private.h"
38 #include "misc.h"
39 #include "bg.h"
40
41 #include "lxpanelctl.h"
42 #include "dbg.h"
43
44 static gchar *cfgfile = NULL;
45 static gchar version[] = VERSION;
46 gchar *cprofile = "default";
47
48 static GtkWindowGroup* win_grp; /* window group used to limit the scope of model dialog. */
49
50 static int config = 0;
51 FbEv *fbev = NULL;
52
53 GSList* all_panels = NULL; /* a single-linked list storing all panels */
54
55 gboolean is_restarting = FALSE;
56
57 static int panel_start(Panel *p);
58 static void panel_start_gui(Panel *p);
59
60 gboolean is_in_lxde = FALSE;
61
62 /* A hack used to be compatible with Gnome panel for gtk+ themes.
63 * Some gtk+ themes define special styles for desktop panels.
64 * http://live.gnome.org/GnomeArt/Tutorials/GtkThemes/GnomePanel
65 * So we make a derived class from GtkWindow named PanelToplevel
66 * and create the panels with it to be compatible with Gnome themes.
67 */
68 #define PANEL_TOPLEVEL_TYPE (panel_toplevel_get_type())
69
70 typedef struct _PanelToplevel PanelToplevel;
71 typedef struct _PanelToplevelClass PanelToplevelClass;
72 struct _PanelToplevel
73 {
74 GtkWindow parent;
75 };
76 struct _PanelToplevelClass
77 {
78 GtkWindowClass parent_class;
79 };
80 G_DEFINE_TYPE(PanelToplevel, panel_toplevel, GTK_TYPE_WINDOW);
81 static void panel_toplevel_class_init(PanelToplevelClass *klass)
82 {
83 }
84 static void panel_toplevel_init(PanelToplevel *self)
85 {
86 }
87
88 /* Allocate and initialize new Panel structure. */
89 static Panel* panel_allocate(void)
90 {
91 Panel* p = g_new0(Panel, 1);
92 p->allign = ALLIGN_CENTER;
93 p->edge = EDGE_NONE;
94 p->widthtype = WIDTH_PERCENT;
95 p->width = 100;
96 p->heighttype = HEIGHT_PIXEL;
97 p->height = PANEL_HEIGHT_DEFAULT;
98 p->monitor = 0;
99 p->setdocktype = 1;
100 p->setstrut = 1;
101 p->round_corners = 0;
102 p->autohide = 0;
103 p->visible = TRUE;
104 p->height_when_hidden = 2;
105 p->transparent = 0;
106 p->alpha = 255;
107 gdk_color_parse("white", &p->gtintcolor);
108 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
109 p->usefontcolor = 0;
110 p->fontcolor = 0x00000000;
111 p->usefontsize = 0;
112 p->fontsize = 10;
113 p->spacing = 0;
114 p->icon_size = PANEL_ICON_SIZE;
115 p->icon_theme = gtk_icon_theme_get_default();
116 p->config = config_new();
117 return p;
118 }
119
120 /* Normalize panel configuration after load from file or reconfiguration. */
121 static void panel_normalize_configuration(Panel* p)
122 {
123 panel_set_panel_configuration_changed( p );
124 if (p->width < 0)
125 p->width = 100;
126 if (p->widthtype == WIDTH_PERCENT && p->width > 100)
127 p->width = 100;
128 p->heighttype = HEIGHT_PIXEL;
129 if (p->heighttype == HEIGHT_PIXEL) {
130 if (p->height < PANEL_HEIGHT_MIN)
131 p->height = PANEL_HEIGHT_MIN;
132 else if (p->height > PANEL_HEIGHT_MAX)
133 p->height = PANEL_HEIGHT_MAX;
134 }
135 if (p->monitor < 0)
136 p->monitor = 0;
137 if (p->background)
138 p->transparent = 0;
139 }
140
141 /****************************************************
142 * panel's handlers for WM events *
143 ****************************************************/
144
145 void panel_set_wm_strut(Panel *p)
146 {
147 int index;
148 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
149 gulong strut_size;
150 gulong strut_lower;
151 gulong strut_upper;
152
153 #if GTK_CHECK_VERSION(2, 20, 0)
154 if (!gtk_widget_get_mapped(p->topgwin))
155 #else
156 if (!GTK_WIDGET_MAPPED(p->topgwin))
157 #endif
158 return;
159 /* most wm's tend to ignore struts of unmapped windows, and that's how
160 * lxpanel hides itself. so no reason to set it. */
161 if (p->autohide && p->height_when_hidden <= 0)
162 return;
163
164 /* Dispatch on edge to set up strut parameters. */
165 switch (p->edge)
166 {
167 case EDGE_LEFT:
168 index = 0;
169 strut_size = p->aw;
170 strut_lower = p->ay;
171 strut_upper = p->ay + p->ah;
172 break;
173 case EDGE_RIGHT:
174 index = 1;
175 strut_size = p->aw;
176 strut_lower = p->ay;
177 strut_upper = p->ay + p->ah;
178 break;
179 case EDGE_TOP:
180 index = 2;
181 strut_size = p->ah;
182 strut_lower = p->ax;
183 strut_upper = p->ax + p->aw;
184 break;
185 case EDGE_BOTTOM:
186 index = 3;
187 strut_size = p->ah;
188 strut_lower = p->ax;
189 strut_upper = p->ax + p->aw;
190 break;
191 default:
192 return;
193 }
194
195 /* Handle autohide case. EWMH recommends having the strut be the minimized size. */
196 if (p->autohide)
197 strut_size = p->height_when_hidden;
198
199 /* Set up strut value in property format. */
200 gulong desired_strut[12];
201 memset(desired_strut, 0, sizeof(desired_strut));
202 if (p->setstrut)
203 {
204 desired_strut[index] = strut_size;
205 desired_strut[4 + index * 2] = strut_lower;
206 desired_strut[5 + index * 2] = strut_upper;
207 }
208 else
209 {
210 strut_size = 0;
211 strut_lower = 0;
212 strut_upper = 0;
213 }
214
215 /* If strut value changed, set the property value on the panel window.
216 * This avoids property change traffic when the panel layout is recalculated but strut geometry hasn't changed. */
217 if ((p->strut_size != strut_size) || (p->strut_lower != strut_lower) || (p->strut_upper != strut_upper) || (p->strut_edge != p->edge))
218 {
219 p->strut_size = strut_size;
220 p->strut_lower = strut_lower;
221 p->strut_upper = strut_upper;
222 p->strut_edge = p->edge;
223
224 /* If window manager supports STRUT_PARTIAL, it will ignore STRUT.
225 * Set STRUT also for window managers that do not support STRUT_PARTIAL. */
226 if (strut_size != 0)
227 {
228 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STRUT_PARTIAL,
229 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desired_strut, 12);
230 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STRUT,
231 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desired_strut, 4);
232 }
233 else
234 {
235 XDeleteProperty(xdisplay, p->topxwin, a_NET_WM_STRUT);
236 XDeleteProperty(xdisplay, p->topxwin, a_NET_WM_STRUT_PARTIAL);
237 }
238 }
239 }
240
241 /* defined in configurator.c */
242 void panel_configure(Panel* p, int sel_page );
243 gboolean panel_edge_available(Panel* p, int edge, gint monitor);
244
245 /* built-in commands, defined in configurator.c */
246 void restart(void);
247 void gtk_run(void);
248 void panel_destroy(Panel *p);
249
250 static void process_client_msg ( XClientMessageEvent* ev )
251 {
252 int cmd = ev->data.b[0];
253 switch( cmd )
254 {
255 #ifndef DISABLE_MENU
256 case LXPANEL_CMD_SYS_MENU:
257 {
258 GSList* l;
259 for( l = all_panels; l; l = l->next )
260 {
261 Panel* p = (Panel*)l->data;
262 GList *plugins, *pl;
263
264 plugins = gtk_container_get_children(GTK_CONTAINER(p->box));
265 for (pl = plugins; pl; pl = pl->next)
266 {
267 LXPanelPluginInit *init = PLUGIN_CLASS(pl->data);
268 if (init->show_system_menu)
269 /* queue to show system menu */
270 init->show_system_menu(pl->data);
271 }
272 g_list_free(plugins);
273 }
274 break;
275 }
276 #endif
277 #ifndef DISABLE_MENU
278 case LXPANEL_CMD_RUN:
279 gtk_run();
280 break;
281 #endif
282 case LXPANEL_CMD_CONFIG:
283 {
284 Panel * p = ((all_panels != NULL) ? all_panels->data : NULL);
285 if (p != NULL)
286 panel_configure(p, 0);
287 }
288 break;
289 case LXPANEL_CMD_RESTART:
290 restart();
291 break;
292 case LXPANEL_CMD_EXIT:
293 gtk_main_quit();
294 break;
295 }
296 }
297
298 static GdkFilterReturn
299 panel_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer not_used)
300 {
301 Atom at;
302 Window win;
303 XEvent *ev = (XEvent *) xevent;
304
305 ENTER;
306 DBG("win = 0x%x\n", ev->xproperty.window);
307 if (ev->type != PropertyNotify )
308 {
309 /* private client message from lxpanelctl */
310 if( ev->type == ClientMessage && ev->xproperty.atom == a_LXPANEL_CMD )
311 {
312 process_client_msg( (XClientMessageEvent*)ev );
313 }
314 else if( ev->type == DestroyNotify )
315 {
316 fb_ev_emit_destroy( fbev, ((XDestroyWindowEvent*)ev)->window );
317 }
318 RET(GDK_FILTER_CONTINUE);
319 }
320
321 at = ev->xproperty.atom;
322 win = ev->xproperty.window;
323 if (win == GDK_ROOT_WINDOW())
324 {
325 if (at == a_NET_CLIENT_LIST)
326 {
327 fb_ev_emit(fbev, EV_CLIENT_LIST);
328 }
329 else if (at == a_NET_CURRENT_DESKTOP)
330 {
331 GSList* l;
332 for( l = all_panels; l; l = l->next )
333 ((Panel*)l->data)->curdesk = get_net_current_desktop();
334 fb_ev_emit(fbev, EV_CURRENT_DESKTOP);
335 }
336 else if (at == a_NET_NUMBER_OF_DESKTOPS)
337 {
338 GSList* l;
339 for( l = all_panels; l; l = l->next )
340 ((Panel*)l->data)->desknum = get_net_number_of_desktops();
341 fb_ev_emit(fbev, EV_NUMBER_OF_DESKTOPS);
342 }
343 else if (at == a_NET_DESKTOP_NAMES)
344 {
345 fb_ev_emit(fbev, EV_DESKTOP_NAMES);
346 }
347 else if (at == a_NET_ACTIVE_WINDOW)
348 {
349 fb_ev_emit(fbev, EV_ACTIVE_WINDOW );
350 }
351 else if (at == a_NET_CLIENT_LIST_STACKING)
352 {
353 fb_ev_emit(fbev, EV_CLIENT_LIST_STACKING);
354 }
355 else if (at == a_XROOTPMAP_ID)
356 {
357 GSList* l;
358 for( l = all_panels; l; l = l->next )
359 {
360 Panel* p = (Panel*)l->data;
361 if (p->transparent) {
362 fb_bg_notify_changed_bg(p->bg);
363 }
364 }
365 }
366 else if (at == a_NET_WORKAREA)
367 {
368 GSList* l;
369 for( l = all_panels; l; l = l->next )
370 {
371 Panel* p = (Panel*)l->data;
372 g_free( p->workarea );
373 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
374 /* print_wmdata(p); */
375 }
376 }
377 else
378 return GDK_FILTER_CONTINUE;
379
380 return GDK_FILTER_REMOVE;
381 }
382 return GDK_FILTER_CONTINUE;
383 }
384
385 /****************************************************
386 * panel's handlers for GTK events *
387 ****************************************************/
388
389
390 static gint
391 panel_delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
392 {
393 ENTER;
394 RET(FALSE);
395 }
396
397 static gint
398 panel_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer data)
399 {
400 //Panel *p = (Panel *) data;
401 //if (!p->self_destroy)
402 gtk_main_quit();
403 RET(FALSE);
404 }
405
406 static void
407 on_root_bg_changed(FbBg *bg, Panel* p)
408 {
409 panel_update_background( p );
410 }
411
412 void panel_determine_background_pixmap(Panel * p, GtkWidget * widget, GdkWindow * window)
413 {
414 GdkPixmap * pixmap = NULL;
415
416 /* Free p->bg if it is not going to be used. */
417 if (( ! p->transparent) && (p->bg != NULL))
418 {
419 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, p);
420 g_object_unref(p->bg);
421 p->bg = NULL;
422 }
423
424 if (p->background)
425 {
426 /* User specified background pixmap. */
427 if (p->background_file != NULL)
428 pixmap = fb_bg_get_pix_from_file(widget, p->background_file);
429 }
430
431 else if (p->transparent)
432 {
433 /* Transparent. Determine the appropriate value from the root pixmap. */
434 if (p->bg == NULL)
435 {
436 p->bg = fb_bg_get_for_display();
437 g_signal_connect(G_OBJECT(p->bg), "changed", G_CALLBACK(on_root_bg_changed), p);
438 }
439 pixmap = fb_bg_get_xroot_pix_for_win(p->bg, widget);
440 if ((pixmap != NULL) && (pixmap != GDK_NO_BG) && (p->alpha != 0))
441 fb_bg_composite(pixmap, &p->gtintcolor, p->alpha);
442 }
443
444 if (pixmap != NULL)
445 {
446 gtk_widget_set_app_paintable(widget, TRUE );
447 gdk_window_set_back_pixmap(window, pixmap, FALSE);
448 g_object_unref(pixmap);
449 }
450 else
451 gtk_widget_set_app_paintable(widget, FALSE);
452 }
453
454 /* Update the background of the entire panel.
455 * This function should only be called after the panel has been realized. */
456 void panel_update_background(Panel * p)
457 {
458 GList *plugins, *l;
459
460 /* Redraw the top level widget. */
461 panel_determine_background_pixmap(p, p->topgwin, gtk_widget_get_window(p->topgwin));
462 gdk_window_clear(gtk_widget_get_window(p->topgwin));
463 gtk_widget_queue_draw(p->topgwin);
464
465 /* Loop over all plugins redrawing each plugin. */
466 plugins = gtk_container_get_children(GTK_CONTAINER(p->box));
467 for (l = plugins; l != NULL; l = l->next)
468 plugin_widget_set_background(l->data, p);
469 g_list_free(plugins);
470 }
471
472 static gboolean delay_update_background( Panel* p )
473 {
474 /* Panel could be destroyed while background update scheduled */
475 #if GTK_CHECK_VERSION(2, 20, 0)
476 if (p->topgwin && gtk_widget_get_realized(p->topgwin)) {
477 #else
478 if ( p->topgwin && GTK_WIDGET_REALIZED ( p->topgwin ) ) {
479 #endif
480 gdk_display_sync( gtk_widget_get_display(p->topgwin) );
481 panel_update_background( p );
482 }
483
484 return FALSE;
485 }
486
487 static void
488 panel_realize(GtkWidget *widget, Panel *p)
489 {
490 g_idle_add_full( G_PRIORITY_LOW,
491 (GSourceFunc)delay_update_background, p, NULL );
492 }
493
494 static void
495 panel_style_set(GtkWidget *widget, GtkStyle* prev, Panel *p)
496 {
497 /* FIXME: This dirty hack is used to fix the background of systray... */
498 #if GTK_CHECK_VERSION(2, 20, 0)
499 if (gtk_widget_get_realized(widget))
500 #else
501 if( GTK_WIDGET_REALIZED( widget ) )
502 #endif
503 g_idle_add_full( G_PRIORITY_LOW,
504 (GSourceFunc)delay_update_background, p, NULL );
505 }
506
507 static gint
508 panel_size_req(GtkWidget *widget, GtkRequisition *req, Panel *p)
509 {
510 ENTER;
511
512 if (!p->visible)
513 /* When the panel is in invisible state, the content box also got hidden, thus always
514 * report 0 size. Ask the content box instead for its size. */
515 gtk_widget_size_request(p->box, req);
516
517 if (p->widthtype == WIDTH_REQUEST)
518 p->width = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? req->width : req->height;
519 if (p->heighttype == HEIGHT_REQUEST)
520 p->height = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? req->height : req->width;
521
522 calculate_position(p);
523
524 gtk_widget_set_size_request( widget, p->aw, p->ah );
525
526 RET( TRUE );
527 }
528
529 static gint
530 panel_size_alloc(GtkWidget *widget, GtkAllocation *a, Panel *p)
531 {
532 ENTER;
533 if (p->widthtype == WIDTH_REQUEST)
534 p->width = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? a->width : a->height;
535 if (p->heighttype == HEIGHT_REQUEST)
536 p->height = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? a->height : a->width;
537 calculate_position(p);
538
539 if (a->width == p->aw && a->height == p->ah && a->x == p->ax && a->y == p ->ay) {
540 RET(TRUE);
541 }
542
543 gtk_window_move(GTK_WINDOW(p->topgwin), p->ax, p->ay);
544 panel_set_wm_strut(p);
545 RET(TRUE);
546 }
547
548 static gboolean
549 panel_configure_event (GtkWidget *widget, GdkEventConfigure *e, Panel *p)
550 {
551 ENTER;
552 if (e->width == p->cw && e->height == p->ch && e->x == p->cx && e->y == p->cy)
553 RET(TRUE);
554 p->cw = e->width;
555 p->ch = e->height;
556 p->cx = e->x;
557 p->cy = e->y;
558
559 if (p->transparent)
560 fb_bg_notify_changed_bg(p->bg);
561
562 RET(FALSE);
563 }
564
565 /****************************************************
566 * autohide : borrowed from fbpanel *
567 ****************************************************/
568
569 /* Autohide is behaviour when panel hides itself when mouse is "far enough"
570 * and pops up again when mouse comes "close enough".
571 * Formally, it's a state machine with 3 states that driven by mouse
572 * coordinates and timer:
573 * 1. VISIBLE - ensures that panel is visible. When/if mouse goes "far enough"
574 * switches to WAITING state
575 * 2. WAITING - starts timer. If mouse comes "close enough", stops timer and
576 * switches to VISIBLE. If timer expires, switches to HIDDEN
577 * 3. HIDDEN - hides panel. When mouse comes "close enough" switches to VISIBLE
578 *
579 * Note 1
580 * Mouse coordinates are queried every PERIOD milisec
581 *
582 * Note 2
583 * If mouse is less then GAP pixels to panel it's considered to be close,
584 * otherwise it's far
585 */
586
587 #define GAP 2
588 #define PERIOD 300
589
590 typedef enum
591 {
592 AH_STATE_VISIBLE,
593 AH_STATE_WAITING,
594 AH_STATE_HIDDEN
595 } PanelAHState;
596
597 static void ah_state_set(Panel *p, PanelAHState ah_state);
598
599 static gboolean
600 mouse_watch(Panel *p)
601 {
602 gint x, y;
603
604 if (g_source_is_destroyed(g_main_current_source()))
605 return FALSE;
606
607 ENTER;
608 gdk_display_get_pointer(gdk_display_get_default(), NULL, &x, &y, NULL);
609
610 /* Reduce sensitivity area
611 p->ah_far = ((x < p->cx - GAP) || (x > p->cx + p->cw + GAP)
612 || (y < p->cy - GAP) || (y > p->cy + p->ch + GAP));
613 */
614
615 gint cx, cy, cw, ch, gap;
616
617 cx = p->cx;
618 cy = p->cy;
619 cw = p->aw;
620 ch = p->ah;
621
622 /* reduce area which will raise panel so it does not interfere with apps */
623 if (p->ah_state == AH_STATE_HIDDEN) {
624 gap = MAX(p->height_when_hidden, GAP);
625 switch (p->edge) {
626 case EDGE_LEFT:
627 cw = gap;
628 break;
629 case EDGE_RIGHT:
630 cx = cx + cw - gap;
631 cw = gap;
632 break;
633 case EDGE_TOP:
634 ch = gap;
635 break;
636 case EDGE_BOTTOM:
637 cy = cy + ch - gap;
638 ch = gap;
639 break;
640 }
641 }
642 p->ah_far = ((x < cx) || (x > cx + cw) || (y < cy) || (y > cy + ch));
643
644 ah_state_set(p, p->ah_state);
645 RET(TRUE);
646 }
647
648 static gboolean ah_state_hide_timeout(gpointer p)
649 {
650 if (!g_source_is_destroyed(g_main_current_source()))
651 {
652 ah_state_set(p, AH_STATE_HIDDEN);
653 ((Panel *)p)->hide_timeout = 0;
654 }
655 return FALSE;
656 }
657
658 static void ah_state_set(Panel *p, PanelAHState ah_state)
659 {
660 ENTER;
661 if (p->ah_state != ah_state) {
662 p->ah_state = ah_state;
663 switch (ah_state) {
664 case AH_STATE_VISIBLE:
665 gtk_widget_show(p->topgwin);
666 gtk_widget_show(p->box);
667 gtk_window_stick(GTK_WINDOW(p->topgwin));
668 p->visible = TRUE;
669 break;
670 case AH_STATE_WAITING:
671 p->hide_timeout = g_timeout_add(2 * PERIOD, ah_state_hide_timeout, p);
672 break;
673 case AH_STATE_HIDDEN:
674 if (p->height_when_hidden > 0)
675 gtk_widget_hide(p->box);
676 else
677 gtk_widget_hide(p->topgwin);
678 p->visible = FALSE;
679 }
680 } else if (p->autohide && p->ah_far) {
681 switch (ah_state) {
682 case AH_STATE_VISIBLE:
683 ah_state_set(p, AH_STATE_WAITING);
684 break;
685 case AH_STATE_WAITING:
686 break;
687 case AH_STATE_HIDDEN:
688 /* configurator might change height_when_hidden value */
689 if (p->height_when_hidden > 0)
690 {
691 if (gtk_widget_get_visible(p->box))
692 {
693 gtk_widget_hide(p->box);
694 gtk_widget_show(p->topgwin);
695 }
696 }
697 else
698 if (gtk_widget_get_visible(p->topgwin))
699 {
700 gtk_widget_hide(p->topgwin);
701 gtk_widget_show(p->box);
702 }
703 }
704 } else {
705 switch (ah_state) {
706 case AH_STATE_VISIBLE:
707 break;
708 case AH_STATE_WAITING:
709 if (p->hide_timeout)
710 g_source_remove(p->hide_timeout);
711 p->hide_timeout = 0;
712 /* continue with setting visible */
713 case AH_STATE_HIDDEN:
714 ah_state_set(p, AH_STATE_VISIBLE);
715 }
716 }
717 RET();
718 }
719
720 /* starts autohide behaviour */
721 static void ah_start(Panel *p)
722 {
723 ENTER;
724 if (!p->mouse_timeout)
725 p->mouse_timeout = g_timeout_add(PERIOD, (GSourceFunc) mouse_watch, p);
726 RET();
727 }
728
729 /* stops autohide */
730 static void ah_stop(Panel *p)
731 {
732 ENTER;
733 if (p->mouse_timeout) {
734 g_source_remove(p->mouse_timeout);
735 p->mouse_timeout = 0;
736 }
737 if (p->hide_timeout) {
738 g_source_remove(p->hide_timeout);
739 p->hide_timeout = 0;
740 }
741 RET();
742 }
743
744 static gboolean
745 panel_map_event(GtkWidget *widget, GdkEvent *event, Panel *p)
746 {
747 ENTER;
748 if (p->autohide)
749 ah_start(p);
750 RET(FALSE);
751 }
752 /* end of the autohide code
753 * ------------------------------------------------------------- */
754
755 static gint
756 panel_popupmenu_configure(GtkWidget *widget, gpointer user_data)
757 {
758 panel_configure( (Panel*)user_data, 0 );
759 return TRUE;
760 }
761
762 /* Handler for "button_press_event" signal with Panel as parameter. */
763 static gboolean panel_button_press_event_with_panel(GtkWidget *widget, GdkEventButton *event, Panel *panel)
764 {
765 if (event->button == 3) /* right button */
766 {
767 GtkMenu* popup = (GtkMenu*) lxpanel_get_plugin_menu(panel, NULL, FALSE);
768 gtk_menu_popup(popup, NULL, NULL, NULL, NULL, event->button, event->time);
769 return TRUE;
770 }
771 return FALSE;
772 }
773
774 static void panel_popupmenu_config_plugin( GtkMenuItem* item, GtkWidget* plugin )
775 {
776 Panel *panel = PLUGIN_PANEL(plugin);
777
778 lxpanel_plugin_show_config_dialog(plugin);
779
780 /* FIXME: this should be more elegant */
781 panel->config_changed = TRUE;
782 }
783
784 static void panel_popupmenu_add_item( GtkMenuItem* item, Panel* panel )
785 {
786 /* panel_add_plugin( panel, panel->topgwin ); */
787 panel_configure( panel, 2 );
788 }
789
790 static void panel_popupmenu_remove_item( GtkMenuItem* item, GtkWidget* plugin )
791 {
792 Panel* panel = PLUGIN_PANEL(plugin);
793
794 /* If the configuration dialog is open, there will certainly be a crash if the
795 * user manipulates the Configured Plugins list, after we remove this entry.
796 * Close the configuration dialog if it is open. */
797 if (panel->pref_dialog != NULL)
798 {
799 gtk_widget_destroy(panel->pref_dialog);
800 panel->pref_dialog = NULL;
801 }
802 config_setting_destroy(g_object_get_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf));
803 /* reset conf pointer because the widget still may be referenced by configurator */
804 g_object_set_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf, NULL);
805
806 panel_config_save(panel);
807 gtk_widget_destroy(plugin);
808 }
809
810 /* FIXME: Potentially we can support multiple panels at the same edge,
811 * but currently this cannot be done due to some positioning problems. */
812 static char* gen_panel_name( int edge, gint monitor )
813 {
814 const char* edge_str = num2str( edge_pair, edge, "" );
815 char* name = NULL;
816 char* dir = _user_config_file_name("panels", NULL);
817 int i;
818 for( i = 0; i < G_MAXINT; ++i )
819 {
820 char* f;
821 if(monitor != 0)
822 name = g_strdup_printf( "%s-m%d-%d", edge_str, monitor, i );
823 else if( G_LIKELY( i > 0 ) )
824 name = g_strdup_printf( "%s%d", edge_str, i );
825 else
826 name = g_strdup( edge_str );
827
828 f = g_build_filename( dir, name, NULL );
829 if( ! g_file_test( f, G_FILE_TEST_EXISTS ) )
830 {
831 g_free( f );
832 break;
833 }
834 g_free( name );
835 g_free( f );
836 }
837 g_free( dir );
838 return name;
839 }
840
841 /* FIXME: Potentially we can support multiple panels at the same edge,
842 * but currently this cannot be done due to some positioning problems. */
843 static void panel_popupmenu_create_panel( GtkMenuItem* item, Panel* panel )
844 {
845 gint m, e, monitors;
846 GdkScreen *screen;
847 GtkWidget *err;
848 Panel* new_panel = panel_allocate();
849
850 /* Allocate the edge. */
851 screen = gdk_screen_get_default();
852 g_assert(screen);
853 monitors = gdk_screen_get_n_monitors(screen);
854 for(m=0; m<monitors; ++m)
855 {
856 /* try each of the four edges */
857 for(e=1; e<5; ++e)
858 {
859 if(panel_edge_available(new_panel,e,m)) {
860 new_panel->edge = e;
861 new_panel->monitor = m;
862 goto found_edge;
863 }
864 }
865 }
866
867 panel_destroy(new_panel);
868 ERR("Error adding panel: There is no room for another panel. All the edges are taken.\n");
869 err = gtk_message_dialog_new(NULL,0,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("There is no room for another panel. All the edges are taken."));
870 gtk_dialog_run(GTK_DIALOG(err));
871 gtk_widget_destroy(err);
872 return;
873
874 found_edge:
875 new_panel->name = gen_panel_name(new_panel->edge,new_panel->monitor);
876
877 /* create new config with first group "Global" */
878 config_group_add_subgroup(config_root_setting(new_panel->config), "Global");
879 panel_configure(new_panel, 0);
880 panel_normalize_configuration(new_panel);
881 panel_start_gui(new_panel);
882 gtk_widget_show_all(new_panel->topgwin);
883
884 panel_config_save(new_panel);
885 all_panels = g_slist_prepend(all_panels, new_panel);
886 }
887
888 static void panel_popupmenu_delete_panel( GtkMenuItem* item, Panel* panel )
889 {
890 GtkWidget* dlg;
891 gboolean ok;
892 dlg = gtk_message_dialog_new_with_markup( GTK_WINDOW(panel->topgwin),
893 GTK_DIALOG_MODAL,
894 GTK_MESSAGE_QUESTION,
895 GTK_BUTTONS_OK_CANCEL,
896 _("Really delete this panel?\n<b>Warning: This can not be recovered.</b>") );
897 panel_apply_icon(GTK_WINDOW(dlg));
898 gtk_window_set_title( (GtkWindow*)dlg, _("Confirm") );
899 ok = ( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK );
900 gtk_widget_destroy( dlg );
901 if( ok )
902 {
903 gchar *fname;
904 all_panels = g_slist_remove( all_panels, panel );
905
906 /* delete the config file of this panel */
907 fname = _user_config_file_name("panels", panel->name);
908 g_unlink( fname );
909 g_free(fname);
910 panel->config_changed = 0;
911 panel_destroy( panel );
912 }
913 }
914
915 static void panel_popupmenu_about( GtkMenuItem* item, Panel* panel )
916 {
917 GtkWidget *about;
918 const gchar* authors[] = {
919 "Hong Jen Yee (PCMan) <pcman.tw@gmail.com>",
920 "Jim Huang <jserv.tw@gmail.com>",
921 "Greg McNew <gmcnew@gmail.com> (battery plugin)",
922 "Fred Chien <cfsghost@gmail.com>",
923 "Daniel Kesler <kesler.daniel@gmail.com>",
924 "Juergen Hoetzel <juergen@archlinux.org>",
925 "Marty Jack <martyj19@comcast.net>",
926 "Martin Bagge <brother@bsnet.se>",
927 NULL
928 };
929 /* TRANSLATORS: Replace this string with your names, one name per line. */
930 gchar *translators = _( "translator-credits" );
931
932 about = gtk_about_dialog_new();
933 panel_apply_icon(GTK_WINDOW(about));
934 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), VERSION);
935 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about), _("LXPanel"));
936
937 if(gtk_icon_theme_has_icon(panel->icon_theme, "video-display"))
938 {
939 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
940 gtk_icon_theme_load_icon(panel->icon_theme, "video-display", 48, 0, NULL));
941 }
942 else if (gtk_icon_theme_has_icon(panel->icon_theme, "start-here"))
943 {
944 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
945 gtk_icon_theme_load_icon(panel->icon_theme, "start-here", 48, 0, NULL));
946 }
947 else
948 {
949 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
950 gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL));
951 }
952
953 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about), _("Copyright (C) 2008-2013"));
954 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), _( "Desktop panel for LXDE project"));
955 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "This program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.");
956 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://lxde.org/");
957 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about), authors);
958 gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about), translators);
959 gtk_dialog_run(GTK_DIALOG(about));
960 gtk_widget_destroy(about);
961 }
962
963 void panel_apply_icon( GtkWindow *w )
964 {
965 GdkPixbuf* window_icon;
966
967 if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "video-display"))
968 {
969 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "video-display", 24, 0, NULL);
970 }
971 else if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "start-here"))
972 {
973 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "start-here", 24, 0, NULL);
974 }
975 else
976 {
977 window_icon = gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL);
978 }
979 gtk_window_set_icon(w, window_icon);
980 }
981
982 GtkMenu* lxpanel_get_plugin_menu( Panel* panel, GtkWidget* plugin, gboolean use_sub_menu )
983 {
984 GtkWidget *menu_item, *img;
985 GtkMenu *ret,*menu;
986 LXPanelPluginInit *init;
987 char* tmp;
988
989 ret = menu = GTK_MENU(gtk_menu_new());
990
991 if (plugin)
992 {
993 init = PLUGIN_CLASS(plugin);
994 /* create single item - plugin instance settings */
995 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
996 tmp = g_strdup_printf( _("\"%s\" Settings"), _(init->name) );
997 menu_item = gtk_image_menu_item_new_with_label( tmp );
998 g_free( tmp );
999 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1000 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
1001 if( init->config )
1002 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
1003 else
1004 gtk_widget_set_sensitive( menu_item, FALSE );
1005 /* add custom items by plugin if requested */
1006 if (init->update_context_menu != NULL)
1007 use_sub_menu = init->update_context_menu(plugin, ret);
1008 /* append a separator */
1009 menu_item = gtk_separator_menu_item_new();
1010 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
1011 }
1012 if (use_sub_menu)
1013 menu = GTK_MENU(gtk_menu_new());
1014
1015 img = gtk_image_new_from_stock( GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU );
1016 menu_item = gtk_image_menu_item_new_with_label(_("Add / Remove Panel Items"));
1017 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1018 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1019 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
1020
1021 if( plugin )
1022 {
1023 img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
1024 tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(init->name) );
1025 menu_item = gtk_image_menu_item_new_with_label( tmp );
1026 g_free( tmp );
1027 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1028 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1029 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_remove_item), plugin );
1030 }
1031
1032 menu_item = gtk_separator_menu_item_new();
1033 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1034
1035 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
1036 menu_item = gtk_image_menu_item_new_with_label(_("Panel Settings"));
1037 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1038 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1039 g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_popupmenu_configure), panel );
1040
1041 img = gtk_image_new_from_stock( GTK_STOCK_NEW, GTK_ICON_SIZE_MENU );
1042 menu_item = gtk_image_menu_item_new_with_label(_("Create New Panel"));
1043 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1044 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1045 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_create_panel), panel );
1046
1047 img = gtk_image_new_from_stock( GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU );
1048 menu_item = gtk_image_menu_item_new_with_label(_("Delete This Panel"));
1049 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1050 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1051 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_delete_panel), panel );
1052 if( ! all_panels->next ) /* if this is the only panel */
1053 gtk_widget_set_sensitive( menu_item, FALSE );
1054
1055 menu_item = gtk_separator_menu_item_new();
1056 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1057
1058 img = gtk_image_new_from_stock( GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU );
1059 menu_item = gtk_image_menu_item_new_with_label(_("About"));
1060 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1061 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1062 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_about), panel );
1063
1064 if( use_sub_menu )
1065 {
1066 menu_item = gtk_image_menu_item_new_with_label(_("Panel"));
1067 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
1068 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), GTK_WIDGET(menu) );
1069 }
1070
1071 gtk_widget_show_all(GTK_WIDGET(ret));
1072
1073 g_signal_connect( ret, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
1074 return ret;
1075 }
1076
1077 /* for old plugins compatibility */
1078 GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
1079 {
1080 return lxpanel_get_plugin_menu(panel, plugin->pwid, use_sub_menu);
1081 }
1082
1083 /****************************************************
1084 * panel creation *
1085 ****************************************************/
1086
1087 static void
1088 make_round_corners(Panel *p)
1089 {
1090 /* FIXME: This should be re-written with shape extension of X11 */
1091 /* gdk_window_shape_combine_mask() can be used */
1092 }
1093
1094 void panel_set_dock_type(Panel *p)
1095 {
1096 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1097
1098 if (p->setdocktype) {
1099 Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
1100 XChangeProperty(xdisplay, p->topxwin,
1101 a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
1102 PropModeReplace, (unsigned char *) &state, 1);
1103 }
1104 else {
1105 XDeleteProperty( xdisplay, p->topxwin, a_NET_WM_WINDOW_TYPE );
1106 }
1107 }
1108
1109 void panel_establish_autohide(Panel *p)
1110 {
1111 if (p->autohide)
1112 ah_start(p);
1113 else
1114 {
1115 ah_stop(p);
1116 ah_state_set(p, AH_STATE_VISIBLE);
1117 }
1118 }
1119
1120 /* Set an image from a file with scaling to the panel icon size. */
1121 void panel_image_set_from_file(Panel * p, GtkWidget * image, const char * file)
1122 {
1123 GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file_at_scale(file, p->icon_size, p->icon_size, TRUE, NULL);
1124 if (pixbuf != NULL)
1125 {
1126 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
1127 g_object_unref(pixbuf);
1128 }
1129 }
1130
1131 /* Set an image from a icon theme with scaling to the panel icon size. */
1132 gboolean panel_image_set_icon_theme(Panel * p, GtkWidget * image, const gchar * icon)
1133 {
1134 if (gtk_icon_theme_has_icon(p->icon_theme, icon))
1135 {
1136 GdkPixbuf * pixbuf = gtk_icon_theme_load_icon(p->icon_theme, icon, p->icon_size, 0, NULL);
1137 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
1138 g_object_unref(pixbuf);
1139 return TRUE;
1140 }
1141 return FALSE;
1142 }
1143
1144 static void
1145 panel_start_gui(Panel *p)
1146 {
1147 Atom state[3];
1148 XWMHints wmhints;
1149 guint32 val;
1150 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1151
1152 ENTER;
1153
1154 p->curdesk = get_net_current_desktop();
1155 p->desknum = get_net_number_of_desktops();
1156 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
1157
1158 /* main toplevel window */
1159 /* p->topgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); */
1160 p->topgwin = (GtkWidget*)g_object_new(PANEL_TOPLEVEL_TYPE, NULL);
1161 gtk_widget_set_name(p->topgwin, "PanelToplevel");
1162 p->display = gdk_display_get_default();
1163 gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
1164 gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
1165 gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "lxpanel");
1166 gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
1167 gtk_window_set_position(GTK_WINDOW(p->topgwin), GTK_WIN_POS_NONE);
1168 gtk_window_set_decorated(GTK_WINDOW(p->topgwin), FALSE);
1169
1170 gtk_window_group_add_window( win_grp, (GtkWindow*)p->topgwin );
1171
1172 g_signal_connect(G_OBJECT(p->topgwin), "delete-event",
1173 G_CALLBACK(panel_delete_event), p);
1174 g_signal_connect(G_OBJECT(p->topgwin), "destroy-event",
1175 G_CALLBACK(panel_destroy_event), p);
1176 g_signal_connect (G_OBJECT (p->topgwin), "size-request",
1177 (GCallback) panel_size_req, p);
1178 g_signal_connect (G_OBJECT (p->topgwin), "size-allocate",
1179 (GCallback) panel_size_alloc, p);
1180 g_signal_connect (G_OBJECT (p->topgwin), "configure-event",
1181 (GCallback) panel_configure_event, p);
1182 g_signal_connect(G_OBJECT(p->topgwin), "map-event",
1183 G_CALLBACK(panel_map_event), p);
1184
1185 gtk_widget_add_events( p->topgwin, GDK_BUTTON_PRESS_MASK );
1186 g_signal_connect(G_OBJECT (p->topgwin), "button-press-event",
1187 (GCallback) panel_button_press_event_with_panel, p);
1188
1189 g_signal_connect (G_OBJECT (p->topgwin), "realize",
1190 (GCallback) panel_realize, p);
1191
1192 g_signal_connect (G_OBJECT (p->topgwin), "style-set",
1193 (GCallback)panel_style_set, p);
1194 gtk_widget_realize(p->topgwin);
1195 //gdk_window_set_decorations(gtk_widget_get_window(p->topgwin), 0);
1196
1197 // main layout manager as a single child of panel
1198 p->box = panel_box_new(p, FALSE, 0);
1199 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
1200 // gtk_container_add(GTK_CONTAINER(p->bbox), p->box);
1201 gtk_container_add(GTK_CONTAINER(p->topgwin), p->box);
1202 gtk_widget_show(p->box);
1203 if (p->round_corners)
1204 make_round_corners(p);
1205
1206 p->topxwin = GDK_WINDOW_XWINDOW(gtk_widget_get_window(p->topgwin));
1207 DBG("topxwin = %x\n", p->topxwin);
1208
1209 /* the settings that should be done before window is mapped */
1210 wmhints.flags = InputHint;
1211 wmhints.input = 0;
1212 XSetWMHints (xdisplay, p->topxwin, &wmhints);
1213 #define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
1214 val = WIN_HINTS_SKIP_FOCUS;
1215 XChangeProperty(xdisplay, p->topxwin,
1216 XInternAtom(xdisplay, "_WIN_HINTS", False), XA_CARDINAL, 32,
1217 PropModeReplace, (unsigned char *) &val, 1);
1218
1219 panel_set_dock_type(p);
1220
1221 /* window mapping point */
1222 gtk_widget_show_all(p->topgwin);
1223
1224 /* the settings that should be done after window is mapped */
1225 panel_establish_autohide(p);
1226
1227 /* send it to running wm */
1228 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
1229 /* and assign it ourself just for case when wm is not running */
1230 val = 0xFFFFFFFF;
1231 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
1232 PropModeReplace, (unsigned char *) &val, 1);
1233
1234 state[0] = a_NET_WM_STATE_SKIP_PAGER;
1235 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
1236 state[2] = a_NET_WM_STATE_STICKY;
1237 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STATE, XA_ATOM,
1238 32, PropModeReplace, (unsigned char *) state, 3);
1239
1240 calculate_position(p);
1241 gdk_window_move_resize(gtk_widget_get_window(p->topgwin), p->ax, p->ay, p->aw, p->ah);
1242 panel_set_wm_strut(p);
1243 p->initialized = TRUE;
1244
1245 RET();
1246 }
1247
1248 /* Exchange the "width" and "height" terminology for vertical and horizontal panels. */
1249 void panel_adjust_geometry_terminology(Panel * p)
1250 {
1251 if ((p->height_label != NULL) && (p->width_label != NULL)
1252 && (p->alignment_left_label != NULL) && (p->alignment_right_label != NULL))
1253 {
1254 if ((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM))
1255 {
1256 gtk_label_set_text(GTK_LABEL(p->height_label), _("Height:"));
1257 gtk_label_set_text(GTK_LABEL(p->width_label), _("Width:"));
1258 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Left"));
1259 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Right"));
1260 }
1261 else
1262 {
1263 gtk_label_set_text(GTK_LABEL(p->height_label), _("Width:"));
1264 gtk_label_set_text(GTK_LABEL(p->width_label), _("Height:"));
1265 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Top"));
1266 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Bottom"));
1267 }
1268 }
1269 }
1270
1271 /* Draw text into a label, with the user preference color and optionally bold. */
1272 void panel_draw_label_text(Panel * p, GtkWidget * label, const char * text,
1273 gboolean bold, float custom_size_factor,
1274 gboolean custom_color)
1275 {
1276 if (text == NULL)
1277 {
1278 /* Null string. */
1279 gtk_label_set_text(GTK_LABEL(label), NULL);
1280 return;
1281 }
1282
1283 /* Compute an appropriate size so the font will scale with the panel's icon size. */
1284 int font_desc;
1285 if (p->usefontsize)
1286 font_desc = p->fontsize;
1287 else
1288 {
1289 if (p->icon_size < 20)
1290 font_desc = 9;
1291 else if (p->icon_size >= 20 && p->icon_size < 36)
1292 font_desc = 10;
1293 else
1294 font_desc = 12;
1295 }
1296 font_desc *= custom_size_factor;
1297
1298 /* Check the string for characters that need to be escaped.
1299 * If any are found, create the properly escaped string and use it instead. */
1300 const char * valid_markup = text;
1301 char * escaped_text = NULL;
1302 const char * q;
1303 for (q = text; *q != '\0'; q += 1)
1304 {
1305 if ((*q == '<') || (*q == '>') || (*q == '&'))
1306 {
1307 escaped_text = g_markup_escape_text(text, -1);
1308 valid_markup = escaped_text;
1309 break;
1310 }
1311 }
1312
1313 gchar * formatted_text;
1314 if ((custom_color) && (p->usefontcolor))
1315 {
1316 /* Color, optionally bold. */
1317 formatted_text = g_strdup_printf("<span font_desc=\"%d\" color=\"#%06x\">%s%s%s</span>",
1318 font_desc,
1319 gcolor2rgb24(&p->gfontcolor),
1320 ((bold) ? "<b>" : ""),
1321 valid_markup,
1322 ((bold) ? "</b>" : ""));
1323 }
1324 else
1325 {
1326 /* No color, optionally bold. */
1327 formatted_text = g_strdup_printf("<span font_desc=\"%d\">%s%s%s</span>",
1328 font_desc,
1329 ((bold) ? "<b>" : ""),
1330 valid_markup,
1331 ((bold) ? "</b>" : ""));
1332 }
1333
1334 gtk_label_set_markup(GTK_LABEL(label), formatted_text);
1335 g_free(formatted_text);
1336 g_free(escaped_text);
1337 }
1338
1339 void panel_set_panel_configuration_changed(Panel *p)
1340 {
1341 GList *plugins, *l;
1342
1343 GtkOrientation previous_orientation = p->orientation;
1344 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
1345 ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
1346
1347 /* either first run or orientation was changed */
1348 if (!p->initialized || previous_orientation != p->orientation)
1349 {
1350 panel_adjust_geometry_terminology(p);
1351 if (p->initialized)
1352 p->height = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? PANEL_HEIGHT_DEFAULT : PANEL_WIDTH_DEFAULT);
1353 if (p->height_control != NULL)
1354 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->height_control), p->height);
1355 if ((p->widthtype == WIDTH_PIXEL) && (p->width_control != NULL))
1356 {
1357 int value = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? gdk_screen_width() : gdk_screen_height());
1358 gtk_spin_button_set_range(GTK_SPIN_BUTTON(p->width_control), 0, value);
1359 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->width_control), value);
1360 }
1361 }
1362
1363 /* FIXME: it's deprecated, kept for binary compatibility */
1364 if (p->orientation == GTK_ORIENTATION_HORIZONTAL) {
1365 p->my_box_new = gtk_hbox_new;
1366 p->my_separator_new = gtk_vseparator_new;
1367 } else {
1368 p->my_box_new = gtk_vbox_new;
1369 p->my_separator_new = gtk_hseparator_new;
1370 }
1371
1372 /* recreate the main layout box */
1373 if (p->box != NULL)
1374 {
1375 gtk_orientable_set_orientation(GTK_ORIENTABLE(p->box), p->orientation);
1376 }
1377
1378 /* NOTE: This loop won't be executed when panel started since
1379 plugins are not loaded at that time.
1380 This is used when the orientation of the panel is changed
1381 from the config dialog, and plugins should be re-layout.
1382 */
1383 plugins = p->box ? gtk_container_get_children(GTK_CONTAINER(p->box)) : NULL;
1384 for( l = plugins; l; l = l->next ) {
1385 GtkWidget *w = (GtkWidget*)l->data;
1386 LXPanelPluginInit *init = PLUGIN_CLASS(w);
1387 if (init->reconfigure)
1388 init->reconfigure(p, w);
1389 }
1390 g_list_free(plugins);
1391 /* panel geometry changed? update panel background then */
1392 g_idle_add_full( G_PRIORITY_LOW,
1393 (GSourceFunc)delay_update_background, p, NULL );
1394 }
1395
1396 static int
1397 panel_parse_global(Panel *p, config_setting_t *cfg)
1398 {
1399 const char *str;
1400 gint i;
1401
1402 /* check Global config */
1403 if (!cfg || strcmp(config_setting_get_name(cfg), "Global") != 0)
1404 {
1405 ERR( "lxpanel: Global section not found\n");
1406 RET(0);
1407 }
1408 if (config_setting_lookup_string(cfg, "edge", &str))
1409 p->edge = str2num(edge_pair, str, EDGE_NONE);
1410 if (config_setting_lookup_string(cfg, "allign", &str))
1411 p->allign = str2num(allign_pair, str, ALLIGN_NONE);
1412 config_setting_lookup_int(cfg, "monitor", &p->monitor);
1413 config_setting_lookup_int(cfg, "margin", &p->margin);
1414 if (config_setting_lookup_string(cfg, "widthtype", &str))
1415 p->widthtype = str2num(width_pair, str, WIDTH_NONE);
1416 config_setting_lookup_int(cfg, "width", &p->width);
1417 if (config_setting_lookup_string(cfg, "heighttype", &str))
1418 p->heighttype = str2num(height_pair, str, HEIGHT_NONE);
1419 config_setting_lookup_int(cfg, "height", &p->height);
1420 if (config_setting_lookup_int(cfg, "spacing", &i) && i > 0)
1421 p->spacing = i;
1422 if (config_setting_lookup_int(cfg, "setdocktype", &i))
1423 p->setdocktype = i != 0;
1424 if (config_setting_lookup_int(cfg, "setpartialstrut", &i))
1425 p->setstrut = i != 0;
1426 if (config_setting_lookup_int(cfg, "RoundCorners", &i))
1427 p->round_corners = i != 0;
1428 if (config_setting_lookup_int(cfg, "transparent", &i))
1429 p->transparent = i != 0;
1430 if (config_setting_lookup_int(cfg, "alpha", &p->alpha))
1431 {
1432 if (p->alpha > 255)
1433 p->alpha = 255;
1434 }
1435 if (config_setting_lookup_int(cfg, "autohide", &i))
1436 p->autohide = i != 0;
1437 if (config_setting_lookup_int(cfg, "heightwhenhidden", &i))
1438 p->height_when_hidden = MAX(0, i);
1439 if (config_setting_lookup_string(cfg, "tintcolor", &str))
1440 {
1441 if (!gdk_color_parse (str, &p->gtintcolor))
1442 gdk_color_parse ("white", &p->gtintcolor);
1443 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
1444 DBG("tintcolor=%x\n", p->tintcolor);
1445 }
1446 if (config_setting_lookup_int(cfg, "usefontcolor", &i))
1447 p->usefontcolor = i != 0;
1448 if (config_setting_lookup_string(cfg, "fontcolor", &str))
1449 {
1450 if (!gdk_color_parse (str, &p->gfontcolor))
1451 gdk_color_parse ("black", &p->gfontcolor);
1452 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
1453 DBG("fontcolor=%x\n", p->fontcolor);
1454 }
1455 if (config_setting_lookup_int(cfg, "usefontsize", &i))
1456 p->usefontsize = i != 0;
1457 if (config_setting_lookup_int(cfg, "fontsize", &i) && i > 0)
1458 p->fontsize = i;
1459 if (config_setting_lookup_int(cfg, "background", &i))
1460 p->background = i != 0;
1461 if (config_setting_lookup_string(cfg, "backgroundfile", &str))
1462 p->background_file = g_strdup(str);
1463 config_setting_lookup_int(cfg, "iconsize", &p->icon_size);
1464 if (config_setting_lookup_int(cfg, "loglevel", &configured_log_level))
1465 {
1466 if (!log_level_set_on_commandline)
1467 log_level = configured_log_level;
1468 }
1469
1470 panel_normalize_configuration(p);
1471
1472 return 1;
1473 }
1474
1475 static int
1476 panel_parse_plugin(Panel *p, config_setting_t *cfg)
1477 {
1478 const char *type = NULL;
1479
1480 ENTER;
1481 config_setting_lookup_string(cfg, "type", &type);
1482 DBG("plug %s\n", type);
1483
1484 if (!type || lxpanel_add_plugin(p, type, cfg, -1) == NULL) {
1485 ERR( "lxpanel: can't load %s plugin\n", type);
1486 goto error;
1487 }
1488 RET(1);
1489
1490 error:
1491 RET(0);
1492 }
1493
1494 int panel_start( Panel *p )
1495 {
1496 config_setting_t *list, *s;
1497 int i;
1498
1499 /* parse global section */
1500 ENTER;
1501
1502 list = config_setting_get_member(config_root_setting(p->config), "");
1503 if (!list || !panel_parse_global(p, config_setting_get_elem(list, 0)))
1504 RET(0);
1505
1506 panel_start_gui(p);
1507
1508 for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
1509 if (strcmp(config_setting_get_name(s), "Plugin") == 0 &&
1510 panel_parse_plugin(p, s)) /* success on plugin start */
1511 i++;
1512 else /* remove invalid data from config */
1513 config_setting_remove_elem(list, i);
1514
1515 /* update backgrond of panel and all plugins */
1516 panel_update_background( p );
1517 return 1;
1518 }
1519
1520 void panel_destroy(Panel *p)
1521 {
1522 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1523 ENTER;
1524
1525 if (p->autohide)
1526 ah_stop(p);
1527 if (p->pref_dialog != NULL)
1528 gtk_widget_destroy(p->pref_dialog);
1529 if (p->plugin_pref_dialog != NULL)
1530 /* just close the dialog, it will do all required cleanup */
1531 gtk_dialog_response(GTK_DIALOG(p->plugin_pref_dialog), GTK_RESPONSE_CLOSE);
1532
1533 if (p->bg != NULL)
1534 {
1535 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, p);
1536 g_object_unref(p->bg);
1537 }
1538
1539 if( p->config_changed )
1540 panel_config_save( p );
1541 config_destroy(p->config);
1542
1543 if( p->topgwin )
1544 {
1545 gtk_window_group_remove_window( win_grp, GTK_WINDOW( p->topgwin ) );
1546 gtk_widget_destroy(p->topgwin);
1547 }
1548 g_free(p->workarea);
1549 g_free( p->background_file );
1550 g_slist_free( p->system_menus );
1551 gdk_flush();
1552 XFlush(xdisplay);
1553 XSync(xdisplay, True);
1554
1555 g_free( p->name );
1556 g_free(p);
1557 RET();
1558 }
1559
1560 Panel* panel_new( const char* config_file, const char* config_name )
1561 {
1562 Panel* panel = NULL;
1563
1564 if (G_LIKELY(config_file))
1565 {
1566 panel = panel_allocate();
1567 panel->name = g_strdup(config_name);
1568 g_debug("starting panel from file %s",config_file);
1569 if (!config_read_file(panel->config, config_file) ||
1570 !panel_start(panel))
1571 {
1572 ERR( "lxpanel: can't start panel\n");
1573 panel_destroy( panel );
1574 panel = NULL;
1575 }
1576 }
1577 return panel;
1578 }
1579
1580 static void
1581 usage()
1582 {
1583 g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
1584 g_print(_("Command line options:\n"));
1585 g_print(_(" --help -- print this help and exit\n"));
1586 g_print(_(" --version -- print version and exit\n"));
1587 g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
1588 // g_print(_(" --configure -- launch configuration utility\n"));
1589 g_print(_(" --profile name -- use specified profile\n"));
1590 g_print("\n");
1591 g_print(_(" -h -- same as --help\n"));
1592 g_print(_(" -p -- same as --profile\n"));
1593 g_print(_(" -v -- same as --version\n"));
1594 // g_print(_(" -C -- same as --configure\n"));
1595 g_print(_("\nVisit http://lxde.org/ for detail.\n\n"));
1596 }
1597
1598 int panel_handle_x_error(Display * d, XErrorEvent * ev)
1599 {
1600 char buf[256];
1601
1602 if (log_level >= LOG_WARN) {
1603 XGetErrorText(d, ev->error_code, buf, 256);
1604 LOG(LOG_WARN, "lxpanel : X error: %s\n", buf);
1605 }
1606 return 0; /* Ignored */
1607 }
1608
1609 int panel_handle_x_error_swallow_BadWindow_BadDrawable(Display * d, XErrorEvent * ev)
1610 {
1611 if ((ev->error_code != BadWindow) && (ev->error_code != BadDrawable))
1612 panel_handle_x_error(d, ev);
1613 return 0; /* Ignored */
1614 }
1615
1616 /* Lightweight lock related functions - X clipboard hacks */
1617
1618 #define CLIPBOARD_NAME "LXPANEL_SELECTION"
1619
1620 /*
1621 * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
1622 */
1623 static void
1624 clipboard_get_func(
1625 GtkClipboard *clipboard G_GNUC_UNUSED,
1626 GtkSelectionData *selection_data G_GNUC_UNUSED,
1627 guint info G_GNUC_UNUSED,
1628 gpointer user_data_or_owner G_GNUC_UNUSED)
1629 {
1630 }
1631
1632 /*
1633 * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
1634 */
1635 static void clipboard_clear_func(
1636 GtkClipboard *clipboard G_GNUC_UNUSED,
1637 gpointer user_data_or_owner G_GNUC_UNUSED)
1638 {
1639 }
1640
1641 /*
1642 * Lightweight version for checking single instance.
1643 * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
1644 *
1645 * Returns TRUE if successfully retrieved and FALSE otherwise.
1646 */
1647 static gboolean check_main_lock()
1648 {
1649 static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
1650 gboolean retval = FALSE;
1651 GtkClipboard *clipboard;
1652 Atom atom;
1653 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1654
1655 atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
1656
1657 XGrabServer(xdisplay);
1658
1659 if (XGetSelectionOwner(xdisplay, atom) != None)
1660 goto out;
1661
1662 clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
1663
1664 if (gtk_clipboard_set_with_data(clipboard, targets,
1665 G_N_ELEMENTS (targets),
1666 clipboard_get_func,
1667 clipboard_clear_func, NULL))
1668 retval = TRUE;
1669
1670 out:
1671 XUngrabServer (xdisplay);
1672 gdk_flush ();
1673
1674 return retval;
1675 }
1676 #undef CLIPBOARD_NAME
1677
1678 static void _start_panels_from_dir(const char *panel_dir)
1679 {
1680 GDir* dir = g_dir_open( panel_dir, 0, NULL );
1681 const gchar* name;
1682
1683 if( ! dir )
1684 {
1685 return;
1686 }
1687
1688 while((name = g_dir_read_name(dir)) != NULL)
1689 {
1690 char* panel_config = g_build_filename( panel_dir, name, NULL );
1691 if (strchr(panel_config, '~') == NULL) /* Skip editor backup files in case user has hand edited in this directory */
1692 {
1693 Panel* panel = panel_new( panel_config, name );
1694 if( panel )
1695 all_panels = g_slist_prepend( all_panels, panel );
1696 }
1697 g_free( panel_config );
1698 }
1699 g_dir_close( dir );
1700 }
1701
1702 static gboolean start_all_panels( )
1703 {
1704 char *panel_dir;
1705
1706 /* try user panels */
1707 panel_dir = _user_config_file_name("panels", NULL);
1708 _start_panels_from_dir(panel_dir);
1709 g_free(panel_dir);
1710 if (all_panels != NULL)
1711 return TRUE;
1712 /* else try XDG fallback */
1713 panel_dir = _system_config_file_name("panels");
1714 _start_panels_from_dir(panel_dir);
1715 g_free(panel_dir);
1716 if (all_panels != NULL)
1717 return TRUE;
1718 /* last try at old fallback for compatibility reasons */
1719 panel_dir = _old_system_config_file_name("panels");
1720 _start_panels_from_dir(panel_dir);
1721 g_free(panel_dir);
1722 return all_panels != NULL;
1723 }
1724
1725 void load_global_config();
1726 void free_global_config();
1727
1728 static void _ensure_user_config_dirs(void)
1729 {
1730 char *dir = g_build_filename(g_get_user_config_dir(), "lxpanel", cprofile,
1731 "panels", NULL);
1732
1733 /* make sure the private profile and panels dir exists */
1734 g_mkdir_with_parents(dir, 0700);
1735 g_free(dir);
1736 }
1737
1738 int main(int argc, char *argv[], char *env[])
1739 {
1740 int i;
1741 const char* desktop_name;
1742 char *file;
1743
1744 setlocale(LC_CTYPE, "");
1745
1746 g_thread_init(NULL);
1747 /* gdk_threads_init();
1748 gdk_threads_enter(); */
1749
1750 /* Add a gtkrc file to be parsed too. */
1751 file = _user_config_file_name("gtkrc", NULL);
1752 gtk_rc_add_default_file(file);
1753 g_free(file);
1754
1755 gtk_init(&argc, &argv);
1756
1757 #ifdef ENABLE_NLS
1758 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
1759 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
1760 textdomain ( GETTEXT_PACKAGE );
1761 #endif
1762
1763 XSetLocaleModifiers("");
1764 XSetErrorHandler((XErrorHandler) panel_handle_x_error);
1765
1766 resolve_atoms();
1767
1768 desktop_name = g_getenv("XDG_CURRENT_DESKTOP");
1769 is_in_lxde = desktop_name && (0 == strcmp(desktop_name, "LXDE"));
1770
1771 for (i = 1; i < argc; i++) {
1772 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
1773 usage();
1774 exit(0);
1775 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
1776 printf("lxpanel %s\n", version);
1777 exit(0);
1778 } else if (!strcmp(argv[i], "--log")) {
1779 i++;
1780 if (i == argc) {
1781 ERR( "lxpanel: missing log level\n");
1782 usage();
1783 exit(1);
1784 } else {
1785 log_level = atoi(argv[i]);
1786 log_level_set_on_commandline = true;
1787 }
1788 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
1789 config = 1;
1790 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
1791 i++;
1792 if (i == argc) {
1793 ERR( "lxpanel: missing profile name\n");
1794 usage();
1795 exit(1);
1796 } else {
1797 cprofile = g_strdup(argv[i]);
1798 }
1799 } else {
1800 printf("lxpanel: unknown option - %s\n", argv[i]);
1801 usage();
1802 exit(1);
1803 }
1804 }
1805
1806 /* Check for duplicated lxpanel instances */
1807 if (!check_main_lock() && !config) {
1808 printf("There is already an instance of LXPanel. Now to exit\n");
1809 exit(1);
1810 }
1811
1812 _ensure_user_config_dirs();
1813
1814 /* Add our own icons to the search path of icon theme */
1815 gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(), PACKAGE_DATA_DIR "/images" );
1816
1817 fbev = fb_ev_new();
1818 win_grp = gtk_window_group_new();
1819
1820 restart:
1821 is_restarting = FALSE;
1822
1823 /* init LibFM */
1824 fm_gtk_init(NULL);
1825
1826 /* prepare modules data */
1827 _prepare_modules();
1828
1829 load_global_config();
1830
1831 /* NOTE: StructureNotifyMask is required by XRandR
1832 * See init_randr_support() in gdkscreen-x11.c of gtk+ for detail.
1833 */
1834 gdk_window_set_events(gdk_get_default_root_window(), GDK_STRUCTURE_MASK |
1835 GDK_SUBSTRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK);
1836 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1837
1838 if( G_UNLIKELY( ! start_all_panels() ) )
1839 g_warning( "Config files are not found.\n" );
1840 /*
1841 * FIXME: configure??
1842 if (config)
1843 configure();
1844 */
1845 gtk_main();
1846
1847 XSelectInput (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), GDK_ROOT_WINDOW(), NoEventMask);
1848 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1849
1850 /* destroy all panels */
1851 g_slist_foreach( all_panels, (GFunc) panel_destroy, NULL );
1852 g_slist_free( all_panels );
1853 all_panels = NULL;
1854 g_free( cfgfile );
1855
1856 free_global_config();
1857
1858 _unload_modules();
1859 fm_gtk_finalize();
1860
1861 if( is_restarting )
1862 goto restart;
1863
1864 /* gdk_threads_leave(); */
1865
1866 g_object_unref(win_grp);
1867 g_object_unref(fbev);
1868
1869 return 0;
1870 }
1871
1872 GtkOrientation panel_get_orientation(Panel *panel)
1873 {
1874 return panel->orientation;
1875 }
1876
1877 gint panel_get_icon_size(Panel *panel)
1878 {
1879 return panel->icon_size;
1880 }
1881
1882 gint panel_get_height(Panel *panel)
1883 {
1884 return panel->height;
1885 }
1886
1887 GtkWindow *panel_get_toplevel_window(Panel *panel)
1888 {
1889 return GTK_WINDOW(panel->topgwin);
1890 }
1891
1892 Window panel_get_xwindow(Panel *panel)
1893 {
1894 return panel->topxwin;
1895 }
1896
1897 gint panel_get_monitor(Panel *panel)
1898 {
1899 return panel->monitor;
1900 }
1901
1902 GtkStyle *panel_get_defstyle(Panel *panel)
1903 {
1904 return panel->defstyle;
1905 }
1906
1907 GtkIconTheme *panel_get_icon_theme(Panel *panel)
1908 {
1909 return panel->icon_theme;
1910 }
1911
1912 gboolean panel_is_at_bottom(Panel *panel)
1913 {
1914 return panel->edge == EDGE_BOTTOM;
1915 }
1916
1917 GtkWidget *panel_box_new(Panel *panel, gboolean homogeneous, gint spacing)
1918 {
1919 if (panel->orientation == GTK_ORIENTATION_HORIZONTAL)
1920 return gtk_hbox_new(homogeneous, spacing);
1921 return gtk_vbox_new(homogeneous, spacing);
1922 }
1923
1924 GtkWidget *panel_separator_new(Panel *panel)
1925 {
1926 if (panel->orientation == GTK_ORIENTATION_HORIZONTAL)
1927 return gtk_vseparator_new();
1928 return gtk_hseparator_new();
1929 }
1930
1931 gboolean _class_is_present(LXPanelPluginInit *init)
1932 {
1933 GSList *sl;
1934
1935 for (sl = all_panels; sl; sl = sl->next )
1936 {
1937 Panel *panel = (Panel*)sl->data;
1938 GList *plugins, *p;
1939
1940 plugins = gtk_container_get_children(GTK_CONTAINER(panel->box));
1941 for (p = plugins; p; p = p->next)
1942 if (PLUGIN_CLASS(p->data) == init)
1943 {
1944 g_list_free(plugins);
1945 return TRUE;
1946 }
1947 g_list_free(plugins);
1948 }
1949 return FALSE;
1950 }