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