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