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