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