Don't connect on signals on LXPanel - it's an object, use built-in handlers.
[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 static int panel_start(LXPanel *p);
58 static void panel_start_gui(LXPanel *p);
59 static void ah_stop(LXPanel *p);
60 static void on_root_bg_changed(FbBg *bg, LXPanel* p);
61
62 gboolean is_in_lxde = FALSE;
63
64 static void lxpanel_size_request(GtkWidget *widget, GtkRequisition *req);
65 static void lxpanel_realize(GtkWidget *widget);
66 static gboolean lxpanel_button_press(GtkWidget *widget, GdkEventButton *event);
67 static void lxpanel_size_allocate(GtkWidget *widget, GtkAllocation *a);
68 static gboolean lxpanel_configure_event (GtkWidget *widget, GdkEventConfigure *e);
69 static gboolean lxpanel_map_event(GtkWidget *widget, GdkEventAny *event);
70 static void lxpanel_style_set(GtkWidget *widget, GtkStyle *prev);
71
72 G_DEFINE_TYPE(PanelToplevel, lxpanel, GTK_TYPE_WINDOW);
73
74 static void lxpanel_finalize(GObject *object)
75 {
76 LXPanel *self = LXPANEL(object);
77 Panel *p = self->priv;
78
79 if( p->config_changed )
80 lxpanel_config_save( self );
81 config_destroy(p->config);
82
83 g_free(p->workarea);
84 g_free( p->background_file );
85 g_slist_free( p->system_menus );
86
87 g_free( p->name );
88 g_free(p);
89
90 G_OBJECT_CLASS(lxpanel_parent_class)->finalize(object);
91 }
92
93 static void lxpanel_destroy(GtkObject *object)
94 {
95 LXPanel *self = LXPANEL(object);
96 Panel *p = self->priv;
97 Display *xdisplay;
98
99 if (p->autohide)
100 ah_stop(self);
101
102 if (p->pref_dialog != NULL)
103 gtk_widget_destroy(p->pref_dialog);
104 p->pref_dialog = NULL;
105
106 if (p->plugin_pref_dialog != NULL)
107 /* just close the dialog, it will do all required cleanup */
108 gtk_dialog_response(GTK_DIALOG(p->plugin_pref_dialog), GTK_RESPONSE_CLOSE);
109
110 if (p->bg != NULL)
111 {
112 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, self);
113 g_object_unref(p->bg);
114 p->bg = NULL;
115 }
116
117 if (p->initialized)
118 {
119 gtk_window_group_remove_window(win_grp, GTK_WINDOW(self));
120 xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
121 gdk_flush();
122 XFlush(xdisplay);
123 XSync(xdisplay, True);
124 p->initialized = FALSE;
125 }
126
127 GTK_OBJECT_CLASS(lxpanel_parent_class)->destroy(object);
128 }
129
130 static void lxpanel_class_init(PanelToplevelClass *klass)
131 {
132 GObjectClass *gobject_class = (GObjectClass *)klass;
133 GtkObjectClass *gtk_object_class = (GtkObjectClass *)klass;
134 GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
135
136 gobject_class->finalize = lxpanel_finalize;
137 gtk_object_class->destroy = lxpanel_destroy;
138 widget_class->size_request = lxpanel_size_request;
139 widget_class->size_allocate = lxpanel_size_allocate;
140 widget_class->realize = lxpanel_realize;
141 widget_class->button_press_event = lxpanel_button_press;
142 widget_class->configure_event = lxpanel_configure_event;
143 widget_class->map_event = lxpanel_map_event;
144 widget_class->style_set = lxpanel_style_set;
145 }
146
147 static void lxpanel_init(PanelToplevel *self)
148 {
149 Panel *p = g_new0(Panel, 1);
150
151 self->priv = p;
152 p->topgwin = self;
153 p->allign = ALLIGN_CENTER;
154 p->edge = EDGE_NONE;
155 p->widthtype = WIDTH_PERCENT;
156 p->width = 100;
157 p->heighttype = HEIGHT_PIXEL;
158 p->height = PANEL_HEIGHT_DEFAULT;
159 p->monitor = 0;
160 p->setdocktype = 1;
161 p->setstrut = 1;
162 p->round_corners = 0;
163 p->autohide = 0;
164 p->visible = TRUE;
165 p->height_when_hidden = 2;
166 p->transparent = 0;
167 p->alpha = 255;
168 gdk_color_parse("white", &p->gtintcolor);
169 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
170 p->usefontcolor = 0;
171 p->fontcolor = 0x00000000;
172 p->usefontsize = 0;
173 p->fontsize = 10;
174 p->spacing = 0;
175 p->icon_size = PANEL_ICON_SIZE;
176 p->icon_theme = gtk_icon_theme_get_default();
177 p->config = config_new();
178 gtk_window_set_type_hint(GTK_WINDOW(self), GDK_WINDOW_TYPE_HINT_DOCK);
179 }
180
181 /* Allocate and initialize new Panel structure. */
182 static LXPanel* panel_allocate(void)
183 {
184 return g_object_new(LX_TYPE_PANEL, NULL);
185 }
186
187 /* Normalize panel configuration after load from file or reconfiguration. */
188 static void panel_normalize_configuration(Panel* p)
189 {
190 panel_set_panel_configuration_changed( p );
191 if (p->width < 0)
192 p->width = 100;
193 if (p->widthtype == WIDTH_PERCENT && p->width > 100)
194 p->width = 100;
195 p->heighttype = HEIGHT_PIXEL;
196 if (p->heighttype == HEIGHT_PIXEL) {
197 if (p->height < PANEL_HEIGHT_MIN)
198 p->height = PANEL_HEIGHT_MIN;
199 else if (p->height > PANEL_HEIGHT_MAX)
200 p->height = PANEL_HEIGHT_MAX;
201 }
202 if (p->monitor < 0)
203 p->monitor = 0;
204 if (p->background)
205 p->transparent = 0;
206 }
207
208 /****************************************************
209 * panel's handlers for WM events *
210 ****************************************************/
211
212 void panel_set_wm_strut(Panel *p)
213 {
214 _panel_set_wm_strut(p->topgwin);
215 }
216
217 void _panel_set_wm_strut(LXPanel *panel)
218 {
219 int index;
220 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
221 Panel *p = panel->priv;
222 gulong strut_size;
223 gulong strut_lower;
224 gulong strut_upper;
225
226 #if GTK_CHECK_VERSION(2, 20, 0)
227 if (!gtk_widget_get_mapped(GTK_WIDGET(panel)))
228 #else
229 if (!GTK_WIDGET_MAPPED(panel))
230 #endif
231 return;
232 /* most wm's tend to ignore struts of unmapped windows, and that's how
233 * lxpanel hides itself. so no reason to set it. */
234 if (p->autohide && p->height_when_hidden <= 0)
235 return;
236
237 /* Dispatch on edge to set up strut parameters. */
238 switch (p->edge)
239 {
240 case EDGE_LEFT:
241 index = 0;
242 strut_size = p->aw;
243 strut_lower = p->ay;
244 strut_upper = p->ay + p->ah;
245 break;
246 case EDGE_RIGHT:
247 index = 1;
248 strut_size = p->aw;
249 strut_lower = p->ay;
250 strut_upper = p->ay + p->ah;
251 break;
252 case EDGE_TOP:
253 index = 2;
254 strut_size = p->ah;
255 strut_lower = p->ax;
256 strut_upper = p->ax + p->aw;
257 break;
258 case EDGE_BOTTOM:
259 index = 3;
260 strut_size = p->ah;
261 strut_lower = p->ax;
262 strut_upper = p->ax + p->aw;
263 break;
264 default:
265 return;
266 }
267
268 /* Handle autohide case. EWMH recommends having the strut be the minimized size. */
269 if (p->autohide)
270 strut_size = p->height_when_hidden;
271
272 /* Set up strut value in property format. */
273 gulong desired_strut[12];
274 memset(desired_strut, 0, sizeof(desired_strut));
275 if (p->setstrut)
276 {
277 desired_strut[index] = strut_size;
278 desired_strut[4 + index * 2] = strut_lower;
279 desired_strut[5 + index * 2] = strut_upper;
280 }
281 else
282 {
283 strut_size = 0;
284 strut_lower = 0;
285 strut_upper = 0;
286 }
287
288 /* If strut value changed, set the property value on the panel window.
289 * This avoids property change traffic when the panel layout is recalculated but strut geometry hasn't changed. */
290 if ((p->strut_size != strut_size) || (p->strut_lower != strut_lower) || (p->strut_upper != strut_upper) || (p->strut_edge != p->edge))
291 {
292 p->strut_size = strut_size;
293 p->strut_lower = strut_lower;
294 p->strut_upper = strut_upper;
295 p->strut_edge = p->edge;
296
297 /* If window manager supports STRUT_PARTIAL, it will ignore STRUT.
298 * Set STRUT also for window managers that do not support STRUT_PARTIAL. */
299 if (strut_size != 0)
300 {
301 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STRUT_PARTIAL,
302 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desired_strut, 12);
303 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STRUT,
304 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desired_strut, 4);
305 }
306 else
307 {
308 XDeleteProperty(xdisplay, p->topxwin, a_NET_WM_STRUT);
309 XDeleteProperty(xdisplay, p->topxwin, a_NET_WM_STRUT_PARTIAL);
310 }
311 }
312 }
313
314 static void process_client_msg ( XClientMessageEvent* ev )
315 {
316 int cmd = ev->data.b[0];
317 switch( cmd )
318 {
319 #ifndef DISABLE_MENU
320 case LXPANEL_CMD_SYS_MENU:
321 {
322 GSList* l;
323 for( l = all_panels; l; l = l->next )
324 {
325 LXPanel* p = (LXPanel*)l->data;
326 GList *plugins, *pl;
327
328 plugins = gtk_container_get_children(GTK_CONTAINER(p->priv->box));
329 for (pl = plugins; pl; pl = pl->next)
330 {
331 const LXPanelPluginInit *init = PLUGIN_CLASS(pl->data);
332 if (init->show_system_menu)
333 /* queue to show system menu */
334 init->show_system_menu(pl->data);
335 }
336 g_list_free(plugins);
337 }
338 break;
339 }
340 #endif
341 case LXPANEL_CMD_RUN:
342 gtk_run();
343 break;
344 case LXPANEL_CMD_CONFIG:
345 {
346 LXPanel * p = ((all_panels != NULL) ? all_panels->data : NULL);
347 if (p != NULL)
348 panel_configure(p, 0);
349 }
350 break;
351 case LXPANEL_CMD_RESTART:
352 restart();
353 break;
354 case LXPANEL_CMD_EXIT:
355 gtk_main_quit();
356 break;
357 }
358 }
359
360 static GdkFilterReturn
361 panel_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer not_used)
362 {
363 Atom at;
364 Window win;
365 XEvent *ev = (XEvent *) xevent;
366
367 ENTER;
368 DBG("win = 0x%x\n", ev->xproperty.window);
369 if (ev->type != PropertyNotify )
370 {
371 /* private client message from lxpanelctl */
372 if( ev->type == ClientMessage && ev->xproperty.atom == a_LXPANEL_CMD )
373 {
374 process_client_msg( (XClientMessageEvent*)ev );
375 }
376 else if( ev->type == DestroyNotify )
377 {
378 fb_ev_emit_destroy( fbev, ((XDestroyWindowEvent*)ev)->window );
379 }
380 RET(GDK_FILTER_CONTINUE);
381 }
382
383 at = ev->xproperty.atom;
384 win = ev->xproperty.window;
385 if (win == GDK_ROOT_WINDOW())
386 {
387 if (at == a_NET_CLIENT_LIST)
388 {
389 fb_ev_emit(fbev, EV_CLIENT_LIST);
390 }
391 else if (at == a_NET_CURRENT_DESKTOP)
392 {
393 GSList* l;
394 for( l = all_panels; l; l = l->next )
395 ((LXPanel*)l->data)->priv->curdesk = get_net_current_desktop();
396 fb_ev_emit(fbev, EV_CURRENT_DESKTOP);
397 }
398 else if (at == a_NET_NUMBER_OF_DESKTOPS)
399 {
400 GSList* l;
401 for( l = all_panels; l; l = l->next )
402 ((LXPanel*)l->data)->priv->desknum = get_net_number_of_desktops();
403 fb_ev_emit(fbev, EV_NUMBER_OF_DESKTOPS);
404 }
405 else if (at == a_NET_DESKTOP_NAMES)
406 {
407 fb_ev_emit(fbev, EV_DESKTOP_NAMES);
408 }
409 else if (at == a_NET_ACTIVE_WINDOW)
410 {
411 fb_ev_emit(fbev, EV_ACTIVE_WINDOW );
412 }
413 else if (at == a_NET_CLIENT_LIST_STACKING)
414 {
415 fb_ev_emit(fbev, EV_CLIENT_LIST_STACKING);
416 }
417 else if (at == a_XROOTPMAP_ID)
418 {
419 GSList* l;
420 for( l = all_panels; l; l = l->next )
421 {
422 LXPanel* p = (LXPanel*)l->data;
423 if (p->priv->transparent) {
424 fb_bg_notify_changed_bg(p->priv->bg);
425 }
426 }
427 }
428 else if (at == a_NET_WORKAREA)
429 {
430 GSList* l;
431 for( l = all_panels; l; l = l->next )
432 {
433 LXPanel* p = (LXPanel*)l->data;
434 g_free( p->priv->workarea );
435 p->priv->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->priv->wa_len);
436 /* print_wmdata(p); */
437 }
438 }
439 else
440 return GDK_FILTER_CONTINUE;
441
442 return GDK_FILTER_REMOVE;
443 }
444 return GDK_FILTER_CONTINUE;
445 }
446
447 /****************************************************
448 * panel's handlers for GTK events *
449 ****************************************************/
450
451
452 static void
453 on_root_bg_changed(FbBg *bg, LXPanel* p)
454 {
455 _panel_update_background( p );
456 }
457
458 void panel_determine_background_pixmap(Panel * panel, GtkWidget * widget, GdkWindow * window)
459 {
460 _panel_determine_background_pixmap(panel->topgwin, widget);
461 }
462
463 void _panel_determine_background_pixmap(LXPanel * panel, GtkWidget * widget)
464 {
465 GdkPixmap * pixmap = NULL;
466 GdkWindow * window = gtk_widget_get_window(widget);
467 Panel * p = panel->priv;
468
469 /* Free p->bg if it is not going to be used. */
470 if (( ! p->transparent) && (p->bg != NULL))
471 {
472 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, panel);
473 g_object_unref(p->bg);
474 p->bg = NULL;
475 }
476
477 if (p->background)
478 {
479 /* User specified background pixmap. */
480 if (p->background_file != NULL)
481 pixmap = fb_bg_get_pix_from_file(widget, p->background_file);
482 }
483
484 else if (p->transparent)
485 {
486 /* Transparent. Determine the appropriate value from the root pixmap. */
487 if (p->bg == NULL)
488 {
489 p->bg = fb_bg_get_for_display();
490 g_signal_connect(G_OBJECT(p->bg), "changed", G_CALLBACK(on_root_bg_changed), panel);
491 }
492 pixmap = fb_bg_get_xroot_pix_for_win(p->bg, widget);
493 if ((pixmap != NULL) && (pixmap != GDK_NO_BG) && (p->alpha != 0))
494 fb_bg_composite(pixmap, &p->gtintcolor, p->alpha);
495 }
496
497 if (pixmap != NULL)
498 {
499 gtk_widget_set_app_paintable(widget, TRUE );
500 gdk_window_set_back_pixmap(window, pixmap, FALSE);
501 g_object_unref(pixmap);
502 }
503 else
504 gtk_widget_set_app_paintable(widget, FALSE);
505 }
506
507 /* Update the background of the entire panel.
508 * This function should only be called after the panel has been realized. */
509 void panel_update_background(Panel * p)
510 {
511 _panel_update_background(p->topgwin);
512 }
513
514 void _panel_update_background(LXPanel * p)
515 {
516 GtkWidget *w = GTK_WIDGET(p);
517 GList *plugins, *l;
518
519 /* Redraw the top level widget. */
520 _panel_determine_background_pixmap(p, w);
521 gdk_window_clear(gtk_widget_get_window(w));
522 gtk_widget_queue_draw(w);
523
524 /* Loop over all plugins redrawing each plugin. */
525 plugins = gtk_container_get_children(GTK_CONTAINER(p->priv->box));
526 for (l = plugins; l != NULL; l = l->next)
527 plugin_widget_set_background(l->data, p);
528 g_list_free(plugins);
529 }
530
531 static gboolean delay_update_background( GtkWidget* p )
532 {
533 /* Panel could be destroyed while background update scheduled */
534 #if GTK_CHECK_VERSION(2, 20, 0)
535 if (gtk_widget_get_realized(p)) {
536 #else
537 if (GTK_WIDGET_REALIZED(p)) {
538 #endif
539 gdk_display_sync( gtk_widget_get_display(p) );
540 _panel_update_background( LXPANEL(p) );
541 }
542
543 return FALSE;
544 }
545
546 static void lxpanel_realize(GtkWidget *widget)
547 {
548 GTK_WIDGET_CLASS(lxpanel_parent_class)->realize(widget);
549
550 g_idle_add_full( G_PRIORITY_LOW,
551 (GSourceFunc)delay_update_background, widget, NULL );
552 }
553
554 static void lxpanel_style_set(GtkWidget *widget, GtkStyle* prev)
555 {
556 GTK_WIDGET_CLASS(lxpanel_parent_class)->style_set(widget, prev);
557
558 /* FIXME: This dirty hack is used to fix the background of systray... */
559 #if GTK_CHECK_VERSION(2, 20, 0)
560 if (gtk_widget_get_realized(widget))
561 #else
562 if( GTK_WIDGET_REALIZED( widget ) )
563 #endif
564 g_idle_add_full( G_PRIORITY_LOW,
565 (GSourceFunc)delay_update_background, widget, NULL );
566 }
567
568 static void lxpanel_size_request(GtkWidget *widget, GtkRequisition *req)
569 {
570 Panel *p = LXPANEL(widget)->priv;
571
572 GTK_WIDGET_CLASS(lxpanel_parent_class)->size_request(widget, req);
573
574 if (!p->visible)
575 /* When the panel is in invisible state, the content box also got hidden, thus always
576 * report 0 size. Ask the content box instead for its size. */
577 gtk_widget_size_request(p->box, req);
578
579 /* FIXME: is this ever required? */
580 if (p->widthtype == WIDTH_REQUEST)
581 p->width = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? req->width : req->height;
582 if (p->heighttype == HEIGHT_REQUEST)
583 p->height = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? req->height : req->width;
584 calculate_position(p);
585
586 gtk_widget_set_size_request( widget, p->aw, p->ah );
587 }
588
589 static void lxpanel_size_allocate(GtkWidget *widget, GtkAllocation *a)
590 {
591 Panel *p = LXPANEL(widget)->priv;
592
593 GTK_WIDGET_CLASS(lxpanel_parent_class)->size_allocate(widget, a);
594
595 if (p->widthtype == WIDTH_REQUEST)
596 p->width = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? a->width : a->height;
597 if (p->heighttype == HEIGHT_REQUEST)
598 p->height = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? a->height : a->width;
599 calculate_position(p);
600
601 if (a->width != p->aw || a->height != p->ah || a->x != p->ax || a->y != p->ay)
602 {
603 gtk_window_move(GTK_WINDOW(widget), p->ax, p->ay);
604 _panel_set_wm_strut(LXPANEL(widget));
605 }
606 }
607
608 static gboolean lxpanel_configure_event (GtkWidget *widget, GdkEventConfigure *e)
609 {
610 Panel *p = LXPANEL(widget)->priv;
611
612 if (e->width == p->cw && e->height == p->ch && e->x == p->cx && e->y == p->cy)
613 goto ok;
614 p->cw = e->width;
615 p->ch = e->height;
616 p->cx = e->x;
617 p->cy = e->y;
618
619 if (p->transparent)
620 fb_bg_notify_changed_bg(p->bg);
621 ok:
622 return GTK_WIDGET_CLASS(lxpanel_parent_class)->configure_event(widget, e);
623 }
624
625 /****************************************************
626 * autohide : borrowed from fbpanel *
627 ****************************************************/
628
629 /* Autohide is behaviour when panel hides itself when mouse is "far enough"
630 * and pops up again when mouse comes "close enough".
631 * Formally, it's a state machine with 3 states that driven by mouse
632 * coordinates and timer:
633 * 1. VISIBLE - ensures that panel is visible. When/if mouse goes "far enough"
634 * switches to WAITING state
635 * 2. WAITING - starts timer. If mouse comes "close enough", stops timer and
636 * switches to VISIBLE. If timer expires, switches to HIDDEN
637 * 3. HIDDEN - hides panel. When mouse comes "close enough" switches to VISIBLE
638 *
639 * Note 1
640 * Mouse coordinates are queried every PERIOD milisec
641 *
642 * Note 2
643 * If mouse is less then GAP pixels to panel it's considered to be close,
644 * otherwise it's far
645 */
646
647 #define GAP 2
648 #define PERIOD 300
649
650 typedef enum
651 {
652 AH_STATE_VISIBLE,
653 AH_STATE_WAITING,
654 AH_STATE_HIDDEN
655 } PanelAHState;
656
657 static void ah_state_set(LXPanel *p, PanelAHState ah_state);
658
659 static gboolean
660 mouse_watch(LXPanel *panel)
661 {
662 Panel *p = panel->priv;
663 gint x, y;
664
665 if (g_source_is_destroyed(g_main_current_source()))
666 return FALSE;
667
668 ENTER;
669 gdk_display_get_pointer(gdk_display_get_default(), NULL, &x, &y, NULL);
670
671 /* Reduce sensitivity area
672 p->ah_far = ((x < p->cx - GAP) || (x > p->cx + p->cw + GAP)
673 || (y < p->cy - GAP) || (y > p->cy + p->ch + GAP));
674 */
675
676 gint cx, cy, cw, ch, gap;
677
678 cx = p->cx;
679 cy = p->cy;
680 cw = p->aw;
681 ch = p->ah;
682
683 /* reduce area which will raise panel so it does not interfere with apps */
684 if (p->ah_state == AH_STATE_HIDDEN) {
685 gap = MAX(p->height_when_hidden, GAP);
686 switch (p->edge) {
687 case EDGE_LEFT:
688 cw = gap;
689 break;
690 case EDGE_RIGHT:
691 cx = cx + cw - gap;
692 cw = gap;
693 break;
694 case EDGE_TOP:
695 ch = gap;
696 break;
697 case EDGE_BOTTOM:
698 cy = cy + ch - gap;
699 ch = gap;
700 break;
701 }
702 }
703 p->ah_far = ((x < cx) || (x > cx + cw) || (y < cy) || (y > cy + ch));
704
705 ah_state_set(panel, p->ah_state);
706 RET(TRUE);
707 }
708
709 static gboolean ah_state_hide_timeout(gpointer p)
710 {
711 if (!g_source_is_destroyed(g_main_current_source()))
712 {
713 ah_state_set(p, AH_STATE_HIDDEN);
714 ((LXPanel *)p)->priv->hide_timeout = 0;
715 }
716 return FALSE;
717 }
718
719 static void ah_state_set(LXPanel *panel, PanelAHState ah_state)
720 {
721 Panel *p = panel->priv;
722
723 ENTER;
724 if (p->ah_state != ah_state) {
725 p->ah_state = ah_state;
726 switch (ah_state) {
727 case AH_STATE_VISIBLE:
728 gtk_widget_show(GTK_WIDGET(panel));
729 gtk_widget_show(p->box);
730 gtk_window_stick(GTK_WINDOW(panel));
731 p->visible = TRUE;
732 break;
733 case AH_STATE_WAITING:
734 p->hide_timeout = g_timeout_add(2 * PERIOD, ah_state_hide_timeout, panel);
735 break;
736 case AH_STATE_HIDDEN:
737 if (p->height_when_hidden > 0)
738 gtk_widget_hide(p->box);
739 else
740 gtk_widget_hide(GTK_WIDGET(panel));
741 p->visible = FALSE;
742 }
743 } else if (p->autohide && p->ah_far) {
744 switch (ah_state) {
745 case AH_STATE_VISIBLE:
746 ah_state_set(panel, AH_STATE_WAITING);
747 break;
748 case AH_STATE_WAITING:
749 break;
750 case AH_STATE_HIDDEN:
751 /* configurator might change height_when_hidden value */
752 if (p->height_when_hidden > 0)
753 {
754 if (gtk_widget_get_visible(p->box))
755 {
756 gtk_widget_hide(p->box);
757 gtk_widget_show(GTK_WIDGET(panel));
758 }
759 }
760 else
761 if (gtk_widget_get_visible(GTK_WIDGET(panel)))
762 {
763 gtk_widget_hide(GTK_WIDGET(panel));
764 gtk_widget_show(p->box);
765 }
766 }
767 } else {
768 switch (ah_state) {
769 case AH_STATE_VISIBLE:
770 break;
771 case AH_STATE_WAITING:
772 if (p->hide_timeout)
773 g_source_remove(p->hide_timeout);
774 p->hide_timeout = 0;
775 /* continue with setting visible */
776 case AH_STATE_HIDDEN:
777 ah_state_set(panel, AH_STATE_VISIBLE);
778 }
779 }
780 RET();
781 }
782
783 /* starts autohide behaviour */
784 static void ah_start(LXPanel *p)
785 {
786 ENTER;
787 if (!p->priv->mouse_timeout)
788 p->priv->mouse_timeout = g_timeout_add(PERIOD, (GSourceFunc) mouse_watch, p);
789 RET();
790 }
791
792 /* stops autohide */
793 static void ah_stop(LXPanel *p)
794 {
795 ENTER;
796 if (p->priv->mouse_timeout) {
797 g_source_remove(p->priv->mouse_timeout);
798 p->priv->mouse_timeout = 0;
799 }
800 if (p->priv->hide_timeout) {
801 g_source_remove(p->priv->hide_timeout);
802 p->priv->hide_timeout = 0;
803 }
804 RET();
805 }
806
807 static gboolean lxpanel_map_event(GtkWidget *widget, GdkEventAny *event)
808 {
809 Panel *p = PLUGIN_PANEL(widget)->priv;
810
811 if (p->autohide)
812 ah_start(LXPANEL(widget));
813 return GTK_WIDGET_CLASS(lxpanel_parent_class)->map_event(widget, event);
814 }
815 /* end of the autohide code
816 * ------------------------------------------------------------- */
817
818 static gint
819 panel_popupmenu_configure(GtkWidget *widget, gpointer user_data)
820 {
821 panel_configure( (LXPanel*)user_data, 0 );
822 return TRUE;
823 }
824
825 /* Handler for "button_press_event" signal with Panel as parameter. */
826 static gboolean lxpanel_button_press(GtkWidget *widget, GdkEventButton *event)
827 {
828 if (event->button == 3) /* right button */
829 {
830 GtkMenu* popup = (GtkMenu*) lxpanel_get_plugin_menu(LXPANEL(widget), NULL, FALSE);
831 gtk_menu_popup(popup, NULL, NULL, NULL, NULL, event->button, event->time);
832 return TRUE;
833 }
834 return GTK_WIDGET_CLASS(lxpanel_parent_class)->button_press_event(widget, event);
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 ERR("Error adding panel: There is no room for another panel. All the edges are taken.\n");
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 guint32 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, 0xFFFFFFFF, 0, 0, 0, 0);
1288 /* and assign it ourself just for case when wm is not running */
1289 val = 0xFFFFFFFF;
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 if (p->icon_size < 20)
1349 font_desc = 9;
1350 else if (p->icon_size >= 20 && p->icon_size < 36)
1351 font_desc = 10;
1352 else
1353 font_desc = 12;
1354 }
1355 font_desc *= custom_size_factor;
1356
1357 /* Check the string for characters that need to be escaped.
1358 * If any are found, create the properly escaped string and use it instead. */
1359 const char * valid_markup = text;
1360 char * escaped_text = NULL;
1361 const char * q;
1362 for (q = text; *q != '\0'; q += 1)
1363 {
1364 if ((*q == '<') || (*q == '>') || (*q == '&'))
1365 {
1366 escaped_text = g_markup_escape_text(text, -1);
1367 valid_markup = escaped_text;
1368 break;
1369 }
1370 }
1371
1372 gchar * formatted_text;
1373 if ((custom_color) && (p->usefontcolor))
1374 {
1375 /* Color, optionally bold. */
1376 formatted_text = g_strdup_printf("<span font_desc=\"%d\" color=\"#%06x\">%s%s%s</span>",
1377 font_desc,
1378 gcolor2rgb24(&p->gfontcolor),
1379 ((bold) ? "<b>" : ""),
1380 valid_markup,
1381 ((bold) ? "</b>" : ""));
1382 }
1383 else
1384 {
1385 /* No color, optionally bold. */
1386 formatted_text = g_strdup_printf("<span font_desc=\"%d\">%s%s%s</span>",
1387 font_desc,
1388 ((bold) ? "<b>" : ""),
1389 valid_markup,
1390 ((bold) ? "</b>" : ""));
1391 }
1392
1393 gtk_label_set_markup(GTK_LABEL(label), formatted_text);
1394 g_free(formatted_text);
1395 g_free(escaped_text);
1396 }
1397
1398 void lxpanel_draw_label_text(LXPanel * p, GtkWidget * label, const char * text,
1399 gboolean bold, float custom_size_factor,
1400 gboolean custom_color)
1401 {
1402 panel_draw_label_text(p->priv, label, text, bold, custom_size_factor, custom_color);
1403 }
1404
1405 void panel_set_panel_configuration_changed(Panel *p)
1406 {
1407 _panel_set_panel_configuration_changed(p->topgwin);
1408 }
1409
1410 void _panel_set_panel_configuration_changed(LXPanel *panel)
1411 {
1412 Panel *p = panel->priv;
1413 GList *plugins, *l;
1414
1415 GtkOrientation previous_orientation = p->orientation;
1416 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
1417 ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
1418
1419 /* either first run or orientation was changed */
1420 if (!p->initialized || previous_orientation != p->orientation)
1421 {
1422 panel_adjust_geometry_terminology(p);
1423 if (p->initialized)
1424 p->height = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? PANEL_HEIGHT_DEFAULT : PANEL_WIDTH_DEFAULT);
1425 if (p->height_control != NULL)
1426 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->height_control), p->height);
1427 if ((p->widthtype == WIDTH_PIXEL) && (p->width_control != NULL))
1428 {
1429 int value = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? gdk_screen_width() : gdk_screen_height());
1430 gtk_spin_button_set_range(GTK_SPIN_BUTTON(p->width_control), 0, value);
1431 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->width_control), value);
1432 }
1433 }
1434
1435 /* FIXME: it's deprecated, kept for binary compatibility */
1436 if (p->orientation == GTK_ORIENTATION_HORIZONTAL) {
1437 p->my_box_new = gtk_hbox_new;
1438 p->my_separator_new = gtk_vseparator_new;
1439 } else {
1440 p->my_box_new = gtk_vbox_new;
1441 p->my_separator_new = gtk_hseparator_new;
1442 }
1443
1444 /* recreate the main layout box */
1445 if (p->box != NULL)
1446 {
1447 gtk_orientable_set_orientation(GTK_ORIENTABLE(p->box), p->orientation);
1448 }
1449
1450 /* NOTE: This loop won't be executed when panel started since
1451 plugins are not loaded at that time.
1452 This is used when the orientation of the panel is changed
1453 from the config dialog, and plugins should be re-layout.
1454 */
1455 plugins = p->box ? gtk_container_get_children(GTK_CONTAINER(p->box)) : NULL;
1456 for( l = plugins; l; l = l->next ) {
1457 GtkWidget *w = (GtkWidget*)l->data;
1458 const LXPanelPluginInit *init = PLUGIN_CLASS(w);
1459 if (init->reconfigure)
1460 init->reconfigure(panel, w);
1461 }
1462 g_list_free(plugins);
1463 /* panel geometry changed? update panel background then */
1464 g_idle_add_full( G_PRIORITY_LOW,
1465 (GSourceFunc)delay_update_background, panel, NULL );
1466 }
1467
1468 static int
1469 panel_parse_global(Panel *p, config_setting_t *cfg)
1470 {
1471 const char *str;
1472 gint i;
1473
1474 /* check Global config */
1475 if (!cfg || strcmp(config_setting_get_name(cfg), "Global") != 0)
1476 {
1477 ERR( "lxpanel: Global section not found\n");
1478 RET(0);
1479 }
1480 if (config_setting_lookup_string(cfg, "edge", &str))
1481 p->edge = str2num(edge_pair, str, EDGE_NONE);
1482 if (config_setting_lookup_string(cfg, "allign", &str))
1483 p->allign = str2num(allign_pair, str, ALLIGN_NONE);
1484 config_setting_lookup_int(cfg, "monitor", &p->monitor);
1485 config_setting_lookup_int(cfg, "margin", &p->margin);
1486 if (config_setting_lookup_string(cfg, "widthtype", &str))
1487 p->widthtype = str2num(width_pair, str, WIDTH_NONE);
1488 config_setting_lookup_int(cfg, "width", &p->width);
1489 if (config_setting_lookup_string(cfg, "heighttype", &str))
1490 p->heighttype = str2num(height_pair, str, HEIGHT_NONE);
1491 config_setting_lookup_int(cfg, "height", &p->height);
1492 if (config_setting_lookup_int(cfg, "spacing", &i) && i > 0)
1493 p->spacing = i;
1494 if (config_setting_lookup_int(cfg, "setdocktype", &i))
1495 p->setdocktype = i != 0;
1496 if (config_setting_lookup_int(cfg, "setpartialstrut", &i))
1497 p->setstrut = i != 0;
1498 if (config_setting_lookup_int(cfg, "RoundCorners", &i))
1499 p->round_corners = i != 0;
1500 if (config_setting_lookup_int(cfg, "transparent", &i))
1501 p->transparent = i != 0;
1502 if (config_setting_lookup_int(cfg, "alpha", &p->alpha))
1503 {
1504 if (p->alpha > 255)
1505 p->alpha = 255;
1506 }
1507 if (config_setting_lookup_int(cfg, "autohide", &i))
1508 p->autohide = i != 0;
1509 if (config_setting_lookup_int(cfg, "heightwhenhidden", &i))
1510 p->height_when_hidden = MAX(0, i);
1511 if (config_setting_lookup_string(cfg, "tintcolor", &str))
1512 {
1513 if (!gdk_color_parse (str, &p->gtintcolor))
1514 gdk_color_parse ("white", &p->gtintcolor);
1515 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
1516 DBG("tintcolor=%x\n", p->tintcolor);
1517 }
1518 if (config_setting_lookup_int(cfg, "usefontcolor", &i))
1519 p->usefontcolor = i != 0;
1520 if (config_setting_lookup_string(cfg, "fontcolor", &str))
1521 {
1522 if (!gdk_color_parse (str, &p->gfontcolor))
1523 gdk_color_parse ("black", &p->gfontcolor);
1524 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
1525 DBG("fontcolor=%x\n", p->fontcolor);
1526 }
1527 if (config_setting_lookup_int(cfg, "usefontsize", &i))
1528 p->usefontsize = i != 0;
1529 if (config_setting_lookup_int(cfg, "fontsize", &i) && i > 0)
1530 p->fontsize = i;
1531 if (config_setting_lookup_int(cfg, "background", &i))
1532 p->background = i != 0;
1533 if (config_setting_lookup_string(cfg, "backgroundfile", &str))
1534 p->background_file = g_strdup(str);
1535 config_setting_lookup_int(cfg, "iconsize", &p->icon_size);
1536 if (config_setting_lookup_int(cfg, "loglevel", &configured_log_level))
1537 {
1538 if (!log_level_set_on_commandline)
1539 log_level = configured_log_level;
1540 }
1541
1542 panel_normalize_configuration(p);
1543
1544 return 1;
1545 }
1546
1547 static int
1548 panel_parse_plugin(LXPanel *p, config_setting_t *cfg)
1549 {
1550 const char *type = NULL;
1551
1552 ENTER;
1553 config_setting_lookup_string(cfg, "type", &type);
1554 DBG("plug %s\n", type);
1555
1556 if (!type || lxpanel_add_plugin(p, type, cfg, -1) == NULL) {
1557 ERR( "lxpanel: can't load %s plugin\n", type);
1558 goto error;
1559 }
1560 RET(1);
1561
1562 error:
1563 RET(0);
1564 }
1565
1566 static int panel_start( LXPanel *p )
1567 {
1568 config_setting_t *list, *s;
1569 int i;
1570
1571 /* parse global section */
1572 ENTER;
1573
1574 list = config_setting_get_member(config_root_setting(p->priv->config), "");
1575 if (!list || !panel_parse_global(p->priv, config_setting_get_elem(list, 0)))
1576 RET(0);
1577
1578 panel_start_gui(p);
1579
1580 for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
1581 if (strcmp(config_setting_get_name(s), "Plugin") == 0 &&
1582 panel_parse_plugin(p, s)) /* success on plugin start */
1583 i++;
1584 else /* remove invalid data from config */
1585 config_setting_remove_elem(list, i);
1586
1587 /* update backgrond of panel and all plugins */
1588 _panel_update_background(p);
1589 return 1;
1590 }
1591
1592 void panel_destroy(Panel *p)
1593 {
1594 gtk_widget_destroy(GTK_WIDGET(p->topgwin));
1595 }
1596
1597 static LXPanel* panel_new( const char* config_file, const char* config_name )
1598 {
1599 LXPanel* panel = NULL;
1600
1601 if (G_LIKELY(config_file))
1602 {
1603 panel = panel_allocate();
1604 panel->priv->name = g_strdup(config_name);
1605 g_debug("starting panel from file %s",config_file);
1606 if (!config_read_file(panel->priv->config, config_file) ||
1607 !panel_start(panel))
1608 {
1609 ERR( "lxpanel: can't start panel\n");
1610 gtk_widget_destroy(GTK_WIDGET(panel));
1611 panel = NULL;
1612 }
1613 }
1614 return panel;
1615 }
1616
1617 static void
1618 usage()
1619 {
1620 g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
1621 g_print(_("Command line options:\n"));
1622 g_print(_(" --help -- print this help and exit\n"));
1623 g_print(_(" --version -- print version and exit\n"));
1624 g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
1625 // g_print(_(" --configure -- launch configuration utility\n"));
1626 g_print(_(" --profile name -- use specified profile\n"));
1627 g_print("\n");
1628 g_print(_(" -h -- same as --help\n"));
1629 g_print(_(" -p -- same as --profile\n"));
1630 g_print(_(" -v -- same as --version\n"));
1631 // g_print(_(" -C -- same as --configure\n"));
1632 g_print(_("\nVisit http://lxde.org/ for detail.\n\n"));
1633 }
1634
1635 /* Lightweight lock related functions - X clipboard hacks */
1636
1637 #define CLIPBOARD_NAME "LXPANEL_SELECTION"
1638
1639 /*
1640 * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
1641 */
1642 static void
1643 clipboard_get_func(
1644 GtkClipboard *clipboard G_GNUC_UNUSED,
1645 GtkSelectionData *selection_data G_GNUC_UNUSED,
1646 guint info G_GNUC_UNUSED,
1647 gpointer user_data_or_owner G_GNUC_UNUSED)
1648 {
1649 }
1650
1651 /*
1652 * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
1653 */
1654 static void clipboard_clear_func(
1655 GtkClipboard *clipboard G_GNUC_UNUSED,
1656 gpointer user_data_or_owner G_GNUC_UNUSED)
1657 {
1658 }
1659
1660 /*
1661 * Lightweight version for checking single instance.
1662 * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
1663 *
1664 * Returns TRUE if successfully retrieved and FALSE otherwise.
1665 */
1666 static gboolean check_main_lock()
1667 {
1668 static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
1669 gboolean retval = FALSE;
1670 GtkClipboard *clipboard;
1671 Atom atom;
1672 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1673
1674 atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
1675
1676 XGrabServer(xdisplay);
1677
1678 if (XGetSelectionOwner(xdisplay, atom) != None)
1679 goto out;
1680
1681 clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
1682
1683 if (gtk_clipboard_set_with_data(clipboard, targets,
1684 G_N_ELEMENTS (targets),
1685 clipboard_get_func,
1686 clipboard_clear_func, NULL))
1687 retval = TRUE;
1688
1689 out:
1690 XUngrabServer (xdisplay);
1691 gdk_flush ();
1692
1693 return retval;
1694 }
1695 #undef CLIPBOARD_NAME
1696
1697 static void _start_panels_from_dir(const char *panel_dir)
1698 {
1699 GDir* dir = g_dir_open( panel_dir, 0, NULL );
1700 const gchar* name;
1701
1702 if( ! dir )
1703 {
1704 return;
1705 }
1706
1707 while((name = g_dir_read_name(dir)) != NULL)
1708 {
1709 char* panel_config = g_build_filename( panel_dir, name, NULL );
1710 if (strchr(panel_config, '~') == NULL) /* Skip editor backup files in case user has hand edited in this directory */
1711 {
1712 LXPanel* panel = panel_new( panel_config, name );
1713 if( panel )
1714 all_panels = g_slist_prepend( all_panels, panel );
1715 }
1716 g_free( panel_config );
1717 }
1718 g_dir_close( dir );
1719 }
1720
1721 static gboolean start_all_panels( )
1722 {
1723 char *panel_dir;
1724
1725 /* try user panels */
1726 panel_dir = _user_config_file_name("panels", NULL);
1727 _start_panels_from_dir(panel_dir);
1728 g_free(panel_dir);
1729 if (all_panels != NULL)
1730 return TRUE;
1731 /* else try XDG fallback */
1732 panel_dir = _system_config_file_name("panels");
1733 _start_panels_from_dir(panel_dir);
1734 g_free(panel_dir);
1735 if (all_panels != NULL)
1736 return TRUE;
1737 /* last try at old fallback for compatibility reasons */
1738 panel_dir = _old_system_config_file_name("panels");
1739 _start_panels_from_dir(panel_dir);
1740 g_free(panel_dir);
1741 return all_panels != NULL;
1742 }
1743
1744 void load_global_config();
1745 void free_global_config();
1746
1747 static void _ensure_user_config_dirs(void)
1748 {
1749 char *dir = g_build_filename(g_get_user_config_dir(), "lxpanel", cprofile,
1750 "panels", NULL);
1751
1752 /* make sure the private profile and panels dir exists */
1753 g_mkdir_with_parents(dir, 0700);
1754 g_free(dir);
1755 }
1756
1757 int main(int argc, char *argv[], char *env[])
1758 {
1759 int i;
1760 const char* desktop_name;
1761 char *file;
1762
1763 setlocale(LC_CTYPE, "");
1764
1765 g_thread_init(NULL);
1766 /* gdk_threads_init();
1767 gdk_threads_enter(); */
1768
1769 /* Add a gtkrc file to be parsed too. */
1770 file = _user_config_file_name("gtkrc", NULL);
1771 gtk_rc_add_default_file(file);
1772 g_free(file);
1773
1774 gtk_init(&argc, &argv);
1775
1776 #ifdef ENABLE_NLS
1777 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
1778 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
1779 textdomain ( GETTEXT_PACKAGE );
1780 #endif
1781
1782 XSetLocaleModifiers("");
1783 XSetErrorHandler((XErrorHandler) panel_handle_x_error);
1784
1785 resolve_atoms();
1786
1787 desktop_name = g_getenv("XDG_CURRENT_DESKTOP");
1788 is_in_lxde = desktop_name && (0 == strcmp(desktop_name, "LXDE"));
1789
1790 for (i = 1; i < argc; i++) {
1791 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
1792 usage();
1793 exit(0);
1794 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
1795 printf("lxpanel %s\n", version);
1796 exit(0);
1797 } else if (!strcmp(argv[i], "--log")) {
1798 i++;
1799 if (i == argc) {
1800 ERR( "lxpanel: missing log level\n");
1801 usage();
1802 exit(1);
1803 } else {
1804 log_level = atoi(argv[i]);
1805 log_level_set_on_commandline = true;
1806 }
1807 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
1808 config = 1;
1809 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
1810 i++;
1811 if (i == argc) {
1812 ERR( "lxpanel: missing profile name\n");
1813 usage();
1814 exit(1);
1815 } else {
1816 cprofile = g_strdup(argv[i]);
1817 }
1818 } else {
1819 printf("lxpanel: unknown option - %s\n", argv[i]);
1820 usage();
1821 exit(1);
1822 }
1823 }
1824
1825 /* Check for duplicated lxpanel instances */
1826 if (!check_main_lock() && !config) {
1827 printf("There is already an instance of LXPanel. Now to exit\n");
1828 exit(1);
1829 }
1830
1831 _ensure_user_config_dirs();
1832
1833 /* Add our own icons to the search path of icon theme */
1834 gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(), PACKAGE_DATA_DIR "/images" );
1835
1836 fbev = fb_ev_new();
1837 win_grp = gtk_window_group_new();
1838
1839 restart:
1840 is_restarting = FALSE;
1841
1842 /* init LibFM */
1843 fm_gtk_init(NULL);
1844
1845 /* prepare modules data */
1846 _prepare_modules();
1847
1848 load_global_config();
1849
1850 /* NOTE: StructureNotifyMask is required by XRandR
1851 * See init_randr_support() in gdkscreen-x11.c of gtk+ for detail.
1852 */
1853 gdk_window_set_events(gdk_get_default_root_window(), GDK_STRUCTURE_MASK |
1854 GDK_SUBSTRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK);
1855 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1856
1857 if( G_UNLIKELY( ! start_all_panels() ) )
1858 g_warning( "Config files are not found.\n" );
1859 /*
1860 * FIXME: configure??
1861 if (config)
1862 configure();
1863 */
1864 gtk_main();
1865
1866 XSelectInput (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), GDK_ROOT_WINDOW(), NoEventMask);
1867 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1868
1869 /* destroy all panels */
1870 g_slist_foreach( all_panels, (GFunc) gtk_widget_destroy, NULL );
1871 g_slist_free( all_panels );
1872 all_panels = NULL;
1873 g_free( cfgfile );
1874
1875 free_global_config();
1876
1877 _unload_modules();
1878 fm_gtk_finalize();
1879
1880 if( is_restarting )
1881 goto restart;
1882
1883 /* gdk_threads_leave(); */
1884
1885 g_object_unref(win_grp);
1886 g_object_unref(fbev);
1887
1888 /* FIXME: do restart more correct way:
1889 if (!is_restarting)
1890 return 0;
1891 if (strchr(argv[0], G_PATH_SEPARATOR))
1892 execve(argv[0], argv, env);
1893 else
1894 execve(g_find_program_in_path(argv[0]), argv, env);
1895 return 1; */
1896
1897 return 0;
1898 }
1899
1900 GtkOrientation panel_get_orientation(LXPanel *panel)
1901 {
1902 return panel->priv->orientation;
1903 }
1904
1905 gint panel_get_icon_size(LXPanel *panel)
1906 {
1907 return panel->priv->icon_size;
1908 }
1909
1910 gint panel_get_height(LXPanel *panel)
1911 {
1912 return panel->priv->height;
1913 }
1914
1915 Window panel_get_xwindow(LXPanel *panel)
1916 {
1917 return panel->priv->topxwin;
1918 }
1919
1920 gint panel_get_monitor(LXPanel *panel)
1921 {
1922 return panel->priv->monitor;
1923 }
1924
1925 GtkStyle *panel_get_defstyle(LXPanel *panel)
1926 {
1927 return panel->priv->defstyle;
1928 }
1929
1930 GtkIconTheme *panel_get_icon_theme(LXPanel *panel)
1931 {
1932 return panel->priv->icon_theme;
1933 }
1934
1935 gboolean panel_is_at_bottom(LXPanel *panel)
1936 {
1937 return panel->priv->edge == EDGE_BOTTOM;
1938 }
1939
1940 gboolean panel_is_dynamic(LXPanel *panel)
1941 {
1942 return panel->priv->widthtype == WIDTH_REQUEST;
1943 }
1944
1945 GtkWidget *panel_box_new(LXPanel *panel, gboolean homogeneous, gint spacing)
1946 {
1947 if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1948 return gtk_hbox_new(homogeneous, spacing);
1949 return gtk_vbox_new(homogeneous, spacing);
1950 }
1951
1952 GtkWidget *panel_separator_new(LXPanel *panel)
1953 {
1954 if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1955 return gtk_vseparator_new();
1956 return gtk_hseparator_new();
1957 }
1958
1959 gboolean _class_is_present(const LXPanelPluginInit *init)
1960 {
1961 GSList *sl;
1962
1963 for (sl = all_panels; sl; sl = sl->next )
1964 {
1965 LXPanel *panel = (LXPanel*)sl->data;
1966 GList *plugins, *p;
1967
1968 plugins = gtk_container_get_children(GTK_CONTAINER(panel->priv->box));
1969 for (p = plugins; p; p = p->next)
1970 if (PLUGIN_CLASS(p->data) == init)
1971 {
1972 g_list_free(plugins);
1973 return TRUE;
1974 }
1975 g_list_free(plugins);
1976 }
1977 return FALSE;
1978 }