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