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