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