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