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