25542c990a677fa6ecf0277a55a15dfc291dae4b
[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);
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);
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->allign = ALLIGN_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(Panel * panel, GtkWidget * widget, GdkWindow * window)
678 {
679 _panel_determine_background_pixmap(panel->topgwin, widget);
680 }
681
682 void _panel_determine_background_pixmap(LXPanel * panel, GtkWidget * widget)
683 {
684 #if GTK_CHECK_VERSION(3, 0, 0)
685 cairo_surface_t *surface;
686 cairo_pattern_t *pattern;
687 #else
688 GdkPixmap * pixmap = NULL;
689 #endif
690 GdkWindow * window = gtk_widget_get_window(widget);
691 Panel * p = panel->priv;
692 cairo_t *cr;
693 GtkAllocation alloc;
694 gint x = 0, y = 0;
695
696 if (!p->background && !p->transparent)
697 goto not_paintable;
698 else if (p->aw <= 1 || p->ah <= 1)
699 goto not_paintable;
700 #if GTK_CHECK_VERSION(3, 0, 0)
701 else if (GTK_WIDGET(panel) != widget)
702 {
703 /* reset background for the child, using background of panel */
704 gdk_window_set_background_pattern(window, NULL);
705 return;
706 }
707 #endif
708 else if (p->surface == NULL)
709 {
710 GdkPixbuf *pixbuf = NULL;
711
712 p->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, p->aw, p->ah);
713 cr = cairo_create(p->surface);
714 if (p->background)
715 {
716 /* User specified background pixmap. */
717 pixbuf = gdk_pixbuf_new_from_file(p->background_file, NULL);
718 }
719 if ((p->transparent && p->alpha != 255) || /* ignore it for opaque panel */
720 (pixbuf != NULL && gdk_pixbuf_get_has_alpha(pixbuf)))
721 {
722 /* Transparent. Determine the appropriate value from the root pixmap. */
723 paint_root_pixmap(panel, cr);
724 }
725 if (pixbuf != NULL)
726 {
727 gint w = gdk_pixbuf_get_width(pixbuf);
728 gint h = gdk_pixbuf_get_height(pixbuf);
729
730 /* Tile the image */
731 for (y = 0; y < p->ah; y += h)
732 for (x = 0; x < p->aw; x += w)
733 {
734 gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
735 cairo_paint(cr);
736 }
737 y = 0;
738 g_object_unref(pixbuf);
739 }
740 else
741 {
742 /* Either color is set or image is invalid, fill the background */
743 gdk_cairo_set_source_color(cr, &p->gtintcolor);
744 cairo_paint_with_alpha(cr, p->transparent ? (double)p->alpha/255 : 1.0);
745 }
746 cairo_destroy(cr);
747 }
748
749 if (p->surface != NULL)
750 {
751 gtk_widget_set_app_paintable(widget, TRUE);
752 gtk_widget_get_allocation(widget, &alloc);
753 #if GTK_CHECK_VERSION(3, 0, 0)
754 surface = gdk_window_create_similar_surface(window, CAIRO_CONTENT_COLOR_ALPHA,
755 alloc.width, alloc.height);
756 cr = cairo_create(surface);
757 #else
758 pixmap = gdk_pixmap_new(window, alloc.width, alloc.height, -1);
759 cr = gdk_cairo_create(pixmap);
760 #endif
761 gtk_widget_translate_coordinates(widget, GTK_WIDGET(panel), 0, 0, &x, &y);
762 cairo_set_source_surface(cr, p->surface, 0.0 - x, 0.0 - y);
763 cairo_paint(cr);
764 cairo_destroy(cr);
765 #if GTK_CHECK_VERSION(3, 0, 0)
766 pattern = cairo_pattern_create_for_surface(surface);
767 gdk_window_set_background_pattern(window, pattern);
768 cairo_pattern_destroy(pattern);
769 cairo_surface_destroy(surface);
770 #else
771 gdk_window_set_back_pixmap(window, pixmap, FALSE);
772 g_object_unref(pixmap);
773 #endif
774 }
775 else
776 {
777 not_paintable:
778 gtk_widget_set_app_paintable(widget, FALSE);
779 }
780 }
781
782 /* Update the background of the entire panel.
783 * This function should only be called after the panel has been realized. */
784 void panel_update_background(Panel * p)
785 {
786 _panel_update_background(p->topgwin);
787 }
788
789 static void _panel_update_background(LXPanel * p)
790 {
791 GtkWidget *w = GTK_WIDGET(p);
792 GList *plugins = NULL, *l;
793
794 /* reset background image */
795 if (p->priv->surface != NULL)
796 {
797 cairo_surface_destroy(p->priv->surface);
798 p->priv->surface = NULL;
799 }
800
801 /* Redraw the top level widget. */
802 _panel_determine_background_pixmap(p, w);
803 gdk_window_clear(gtk_widget_get_window(w));
804 gtk_widget_queue_draw(w);
805
806 /* Loop over all plugins redrawing each plugin. */
807 if (p->priv->box != NULL)
808 plugins = gtk_container_get_children(GTK_CONTAINER(p->priv->box));
809 for (l = plugins; l != NULL; l = l->next)
810 plugin_widget_set_background(l->data, p);
811 g_list_free(plugins);
812 }
813
814 /****************************************************
815 * autohide : borrowed from fbpanel *
816 ****************************************************/
817
818 /* Autohide is behaviour when panel hides itself when mouse is "far enough"
819 * and pops up again when mouse comes "close enough".
820 * Formally, it's a state machine with 3 states that driven by mouse
821 * coordinates and timer:
822 * 1. VISIBLE - ensures that panel is visible. When/if mouse goes "far enough"
823 * switches to WAITING state
824 * 2. WAITING - starts timer. If mouse comes "close enough", stops timer and
825 * switches to VISIBLE. If timer expires, switches to HIDDEN
826 * 3. HIDDEN - hides panel. When mouse comes "close enough" switches to VISIBLE
827 *
828 * Note 1
829 * Mouse coordinates are queried every PERIOD milisec
830 *
831 * Note 2
832 * If mouse is less then GAP pixels to panel it's considered to be close,
833 * otherwise it's far
834 */
835
836 #define GAP 2
837 #define PERIOD 300
838
839 typedef enum
840 {
841 AH_STATE_VISIBLE,
842 AH_STATE_WAITING,
843 AH_STATE_HIDDEN
844 } PanelAHState;
845
846 static void ah_state_set(LXPanel *p, PanelAHState ah_state);
847
848 static gboolean
849 mouse_watch(LXPanel *panel)
850 {
851 Panel *p = panel->priv;
852 gint x, y;
853
854 if (g_source_is_destroyed(g_main_current_source()))
855 return FALSE;
856
857 ENTER;
858 gdk_display_get_pointer(gdk_display_get_default(), NULL, &x, &y, NULL);
859
860 /* Reduce sensitivity area
861 p->ah_far = ((x < p->cx - GAP) || (x > p->cx + p->cw + GAP)
862 || (y < p->cy - GAP) || (y > p->cy + p->ch + GAP));
863 */
864
865 gint cx, cy, cw, ch, gap;
866
867 cx = p->ax;
868 cy = p->ay;
869 cw = p->cw;
870 ch = p->ch;
871
872 if (cw == 1) cw = 0;
873 if (ch == 1) ch = 0;
874 /* reduce area which will raise panel so it does not interfere with apps */
875 if (p->ah_state == AH_STATE_HIDDEN) {
876 gap = MAX(p->height_when_hidden, GAP);
877 switch (p->edge) {
878 case EDGE_LEFT:
879 cw = gap;
880 break;
881 case EDGE_RIGHT:
882 cx = cx + cw - gap;
883 cw = gap;
884 break;
885 case EDGE_TOP:
886 ch = gap;
887 break;
888 case EDGE_BOTTOM:
889 cy = cy + ch - gap;
890 ch = gap;
891 break;
892 }
893 }
894 p->ah_far = ((x < cx) || (x > cx + cw) || (y < cy) || (y > cy + ch));
895
896 ah_state_set(panel, p->ah_state);
897 RET(TRUE);
898 }
899
900 static gboolean ah_state_hide_timeout(gpointer p)
901 {
902 if (!g_source_is_destroyed(g_main_current_source()))
903 {
904 ah_state_set(p, AH_STATE_HIDDEN);
905 ((LXPanel *)p)->priv->hide_timeout = 0;
906 }
907 return FALSE;
908 }
909
910 static void ah_state_set(LXPanel *panel, PanelAHState ah_state)
911 {
912 Panel *p = panel->priv;
913 GdkRectangle rect;
914
915 ENTER;
916 if (p->ah_state != ah_state) {
917 p->ah_state = ah_state;
918 switch (ah_state) {
919 case AH_STATE_VISIBLE:
920 p->visible = TRUE;
921 _calculate_position(panel, &rect);
922 gtk_window_move(GTK_WINDOW(panel), rect.x, rect.y);
923 gtk_widget_show(GTK_WIDGET(panel));
924 gtk_widget_show(p->box);
925 gtk_widget_queue_resize(GTK_WIDGET(panel));
926 gtk_window_stick(GTK_WINDOW(panel));
927 break;
928 case AH_STATE_WAITING:
929 if (p->hide_timeout)
930 g_source_remove(p->hide_timeout);
931 p->hide_timeout = g_timeout_add(2 * PERIOD, ah_state_hide_timeout, panel);
932 break;
933 case AH_STATE_HIDDEN:
934 if (p->height_when_hidden > 0)
935 gtk_widget_hide(p->box);
936 else
937 gtk_widget_hide(GTK_WIDGET(panel));
938 p->visible = FALSE;
939 }
940 } else if (p->autohide && p->ah_far) {
941 switch (ah_state) {
942 case AH_STATE_VISIBLE:
943 ah_state_set(panel, AH_STATE_WAITING);
944 break;
945 case AH_STATE_WAITING:
946 break;
947 case AH_STATE_HIDDEN:
948 /* configurator might change height_when_hidden value */
949 if (p->height_when_hidden > 0)
950 {
951 if (gtk_widget_get_visible(p->box))
952 {
953 gtk_widget_hide(p->box);
954 gtk_widget_show(GTK_WIDGET(panel));
955 }
956 }
957 else
958 if (gtk_widget_get_visible(GTK_WIDGET(panel)))
959 {
960 gtk_widget_hide(GTK_WIDGET(panel));
961 gtk_widget_show(p->box);
962 }
963 }
964 } else {
965 switch (ah_state) {
966 case AH_STATE_VISIBLE:
967 break;
968 case AH_STATE_WAITING:
969 if (p->hide_timeout)
970 g_source_remove(p->hide_timeout);
971 p->hide_timeout = 0;
972 /* continue with setting visible */
973 case AH_STATE_HIDDEN:
974 ah_state_set(panel, AH_STATE_VISIBLE);
975 }
976 }
977 RET();
978 }
979
980 /* starts autohide behaviour */
981 static void ah_start(LXPanel *p)
982 {
983 ENTER;
984 if (!p->priv->mouse_timeout)
985 p->priv->mouse_timeout = g_timeout_add(PERIOD, (GSourceFunc) mouse_watch, p);
986 RET();
987 }
988
989 /* stops autohide */
990 static void ah_stop(LXPanel *p)
991 {
992 ENTER;
993 if (p->priv->mouse_timeout) {
994 g_source_remove(p->priv->mouse_timeout);
995 p->priv->mouse_timeout = 0;
996 }
997 if (p->priv->hide_timeout) {
998 g_source_remove(p->priv->hide_timeout);
999 p->priv->hide_timeout = 0;
1000 }
1001 RET();
1002 }
1003 /* end of the autohide code
1004 * ------------------------------------------------------------- */
1005
1006 static gint
1007 panel_popupmenu_configure(GtkWidget *widget, gpointer user_data)
1008 {
1009 panel_configure( (LXPanel*)user_data, 0 );
1010 return TRUE;
1011 }
1012
1013 static void panel_popupmenu_config_plugin( GtkMenuItem* item, GtkWidget* plugin )
1014 {
1015 Panel *panel = PLUGIN_PANEL(plugin)->priv;
1016
1017 lxpanel_plugin_show_config_dialog(plugin);
1018
1019 /* FIXME: this should be more elegant */
1020 panel->config_changed = TRUE;
1021 }
1022
1023 static void panel_popupmenu_add_item( GtkMenuItem* item, LXPanel* panel )
1024 {
1025 /* panel_add_plugin( panel, panel->topgwin ); */
1026 panel_configure( panel, 2 );
1027 }
1028
1029 static void panel_popupmenu_remove_item( GtkMenuItem* item, GtkWidget* plugin )
1030 {
1031 Panel* panel = PLUGIN_PANEL(plugin)->priv;
1032
1033 /* If the configuration dialog is open, there will certainly be a crash if the
1034 * user manipulates the Configured Plugins list, after we remove this entry.
1035 * Close the configuration dialog if it is open. */
1036 if (panel->pref_dialog != NULL)
1037 {
1038 gtk_widget_destroy(panel->pref_dialog);
1039 panel->pref_dialog = NULL;
1040 }
1041 config_setting_destroy(g_object_get_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf));
1042 /* reset conf pointer because the widget still may be referenced by configurator */
1043 g_object_set_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf, NULL);
1044
1045 lxpanel_config_save(PLUGIN_PANEL(plugin));
1046 gtk_widget_destroy(plugin);
1047 }
1048
1049 /* FIXME: Potentially we can support multiple panels at the same edge,
1050 * but currently this cannot be done due to some positioning problems. */
1051 static char* gen_panel_name( int edge, gint monitor )
1052 {
1053 const char* edge_str = num2str( edge_pair, edge, "" );
1054 char* name = NULL;
1055 char* dir = _user_config_file_name("panels", NULL);
1056 int i;
1057 for( i = 0; i < G_MAXINT; ++i )
1058 {
1059 char* f;
1060 if(monitor != 0)
1061 name = g_strdup_printf( "%s-m%d-%d", edge_str, monitor, i );
1062 else if( G_LIKELY( i > 0 ) )
1063 name = g_strdup_printf( "%s%d", edge_str, i );
1064 else
1065 name = g_strdup( edge_str );
1066
1067 f = g_build_filename( dir, name, NULL );
1068 if( ! g_file_test( f, G_FILE_TEST_EXISTS ) )
1069 {
1070 g_free( f );
1071 break;
1072 }
1073 g_free( name );
1074 g_free( f );
1075 }
1076 g_free( dir );
1077 return name;
1078 }
1079
1080 /* FIXME: Potentially we can support multiple panels at the same edge,
1081 * but currently this cannot be done due to some positioning problems. */
1082 static void panel_popupmenu_create_panel( GtkMenuItem* item, LXPanel* panel )
1083 {
1084 gint m, e, monitors;
1085 GdkScreen *screen;
1086 LXPanel *new_panel = panel_allocate();
1087 Panel *p = new_panel->priv;
1088 config_setting_t *global;
1089
1090 /* Allocate the edge. */
1091 screen = gtk_widget_get_screen(GTK_WIDGET(panel));
1092 g_assert(screen);
1093 monitors = gdk_screen_get_n_monitors(screen);
1094 /* try to allocate edge on current monitor first */
1095 m = panel->priv->monitor;
1096 if (m < 0)
1097 {
1098 /* panel is spanned over the screen, guess from pointer now */
1099 gint x, y;
1100 gdk_display_get_pointer(gdk_display_get_default(), NULL, &x, &y, NULL);
1101 m = gdk_screen_get_monitor_at_point(screen, x, y);
1102 }
1103 for (e = 1; e < 5; ++e)
1104 {
1105 if (panel_edge_available(p, e, m))
1106 {
1107 p->edge = e;
1108 p->monitor = m;
1109 goto found_edge;
1110 }
1111 }
1112 /* try all monitors */
1113 for(m=0; m<monitors; ++m)
1114 {
1115 /* try each of the four edges */
1116 for(e=1; e<5; ++e)
1117 {
1118 if(panel_edge_available(p,e,m)) {
1119 p->edge = e;
1120 p->monitor = m;
1121 goto found_edge;
1122 }
1123 }
1124 }
1125
1126 gtk_widget_destroy(GTK_WIDGET(new_panel));
1127 g_warning("Error adding panel: There is no room for another panel. All the edges are taken.");
1128 fm_show_error(NULL, NULL, _("There is no room for another panel. All the edges are taken."));
1129 return;
1130
1131 found_edge:
1132 p->name = gen_panel_name(p->edge, p->monitor);
1133
1134 /* create new config with first group "Global" */
1135 global = config_group_add_subgroup(config_root_setting(p->config), "Global");
1136 config_group_set_string(global, "edge", num2str(edge_pair, p->edge, "none"));
1137 config_group_set_int(global, "monitor", p->monitor);
1138 panel_configure(new_panel, 0);
1139 panel_normalize_configuration(p);
1140 panel_start_gui(new_panel, NULL);
1141
1142 lxpanel_config_save(new_panel);
1143 all_panels = g_slist_prepend(all_panels, new_panel);
1144 }
1145
1146 static void panel_popupmenu_delete_panel( GtkMenuItem* item, LXPanel* panel )
1147 {
1148 GtkWidget* dlg;
1149 gboolean ok;
1150 dlg = gtk_message_dialog_new_with_markup( GTK_WINDOW(panel),
1151 GTK_DIALOG_MODAL,
1152 GTK_MESSAGE_QUESTION,
1153 GTK_BUTTONS_OK_CANCEL,
1154 _("Really delete this panel?\n<b>Warning: This can not be recovered.</b>") );
1155 panel_apply_icon(GTK_WINDOW(dlg));
1156 gtk_window_set_title( (GtkWindow*)dlg, _("Confirm") );
1157 ok = ( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK );
1158 gtk_widget_destroy( dlg );
1159 if( ok )
1160 {
1161 gchar *fname;
1162 all_panels = g_slist_remove( all_panels, panel );
1163
1164 /* delete the config file of this panel */
1165 fname = _user_config_file_name("panels", panel->priv->name);
1166 g_unlink( fname );
1167 g_free(fname);
1168 panel->priv->config_changed = 0;
1169 gtk_widget_destroy(GTK_WIDGET(panel));
1170 }
1171 }
1172
1173 static void panel_popupmenu_about( GtkMenuItem* item, Panel* panel )
1174 {
1175 GtkWidget *about;
1176 const gchar* authors[] = {
1177 "Hong Jen Yee (PCMan) <pcman.tw@gmail.com>",
1178 "Jim Huang <jserv.tw@gmail.com>",
1179 "Greg McNew <gmcnew@gmail.com> (battery plugin)",
1180 "Fred Chien <cfsghost@gmail.com>",
1181 "Daniel Kesler <kesler.daniel@gmail.com>",
1182 "Juergen Hoetzel <juergen@archlinux.org>",
1183 "Marty Jack <martyj19@comcast.net>",
1184 "Martin Bagge <brother@bsnet.se>",
1185 "Andriy Grytsenko <andrej@rep.kiev.ua>",
1186 "Giuseppe Penone <giuspen@gmail.com>",
1187 "Piotr Sipika <piotr.sipika@gmail.com>",
1188 NULL
1189 };
1190 /* TRANSLATORS: Replace this string with your names, one name per line. */
1191 gchar *translators = _( "translator-credits" );
1192
1193 about = gtk_about_dialog_new();
1194 panel_apply_icon(GTK_WINDOW(about));
1195 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), VERSION);
1196 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about), _("LXPanel"));
1197
1198 if(gtk_icon_theme_has_icon(panel->icon_theme, "video-display"))
1199 {
1200 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
1201 gtk_icon_theme_load_icon(panel->icon_theme, "video-display", 48, 0, NULL));
1202 }
1203 else if (gtk_icon_theme_has_icon(panel->icon_theme, "start-here"))
1204 {
1205 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
1206 gtk_icon_theme_load_icon(panel->icon_theme, "start-here", 48, 0, NULL));
1207 }
1208 else
1209 {
1210 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
1211 gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL));
1212 }
1213
1214 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about), _("Copyright (C) 2008-2014"));
1215 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), _( "Desktop panel for LXDE project"));
1216 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.");
1217 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://lxde.org/");
1218 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about), authors);
1219 gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about), translators);
1220 gtk_dialog_run(GTK_DIALOG(about));
1221 gtk_widget_destroy(about);
1222 }
1223
1224 void panel_apply_icon( GtkWindow *w )
1225 {
1226 GdkPixbuf* window_icon;
1227
1228 if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "video-display"))
1229 {
1230 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "video-display", 24, 0, NULL);
1231 }
1232 else if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "start-here"))
1233 {
1234 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "start-here", 24, 0, NULL);
1235 }
1236 else
1237 {
1238 window_icon = gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL);
1239 }
1240 gtk_window_set_icon(w, window_icon);
1241 }
1242
1243 GtkMenu* lxpanel_get_plugin_menu( LXPanel* panel, GtkWidget* plugin, gboolean use_sub_menu )
1244 {
1245 GtkWidget *menu_item, *img;
1246 GtkMenu *ret,*menu;
1247 const LXPanelPluginInit *init;
1248 char* tmp;
1249
1250 ret = menu = GTK_MENU(gtk_menu_new());
1251
1252 if (plugin)
1253 {
1254 init = PLUGIN_CLASS(plugin);
1255 /* create single item - plugin instance settings */
1256 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
1257 tmp = g_strdup_printf( _("\"%s\" Settings"), _(init->name) );
1258 menu_item = gtk_image_menu_item_new_with_label( tmp );
1259 g_free( tmp );
1260 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1261 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
1262 if( init->config )
1263 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
1264 else
1265 gtk_widget_set_sensitive( menu_item, FALSE );
1266 /* add custom items by plugin if requested */
1267 if (init->update_context_menu != NULL)
1268 use_sub_menu = init->update_context_menu(plugin, ret);
1269 /* append a separator */
1270 menu_item = gtk_separator_menu_item_new();
1271 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
1272 }
1273 if (use_sub_menu)
1274 menu = GTK_MENU(gtk_menu_new());
1275
1276 img = gtk_image_new_from_stock( GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU );
1277 menu_item = gtk_image_menu_item_new_with_label(_("Add / Remove Panel Items"));
1278 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1279 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1280 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
1281
1282 if( plugin )
1283 {
1284 img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
1285 tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(init->name) );
1286 menu_item = gtk_image_menu_item_new_with_label( tmp );
1287 g_free( tmp );
1288 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1289 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1290 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_remove_item), plugin );
1291 }
1292
1293 menu_item = gtk_separator_menu_item_new();
1294 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1295
1296 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
1297 menu_item = gtk_image_menu_item_new_with_label(_("Panel Settings"));
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(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_popupmenu_configure), panel );
1301
1302 img = gtk_image_new_from_stock( GTK_STOCK_NEW, GTK_ICON_SIZE_MENU );
1303 menu_item = gtk_image_menu_item_new_with_label(_("Create New 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_create_panel), panel );
1307
1308 img = gtk_image_new_from_stock( GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU );
1309 menu_item = gtk_image_menu_item_new_with_label(_("Delete This Panel"));
1310 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1311 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1312 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_delete_panel), panel );
1313 if( ! all_panels->next ) /* if this is the only panel */
1314 gtk_widget_set_sensitive( menu_item, FALSE );
1315
1316 menu_item = gtk_separator_menu_item_new();
1317 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1318
1319 img = gtk_image_new_from_stock( GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU );
1320 menu_item = gtk_image_menu_item_new_with_label(_("About"));
1321 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1322 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1323 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_about), panel->priv );
1324
1325 if( use_sub_menu )
1326 {
1327 menu_item = gtk_image_menu_item_new_with_label(_("Panel"));
1328 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
1329 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), GTK_WIDGET(menu) );
1330 }
1331
1332 gtk_widget_show_all(GTK_WIDGET(ret));
1333
1334 g_signal_connect( ret, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
1335 return ret;
1336 }
1337
1338 /* for old plugins compatibility */
1339 GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
1340 {
1341 return lxpanel_get_plugin_menu(panel->topgwin, plugin->pwid, use_sub_menu);
1342 }
1343
1344 /****************************************************
1345 * panel creation *
1346 ****************************************************/
1347
1348 static void
1349 make_round_corners(Panel *p)
1350 {
1351 /* FIXME: This should be re-written with shape extension of X11 */
1352 /* gdk_window_shape_combine_mask() can be used */
1353 }
1354
1355 void panel_set_dock_type(Panel *p)
1356 {
1357 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1358
1359 if (p->setdocktype) {
1360 Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
1361 XChangeProperty(xdisplay, p->topxwin,
1362 a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
1363 PropModeReplace, (unsigned char *) &state, 1);
1364 }
1365 else {
1366 XDeleteProperty( xdisplay, p->topxwin, a_NET_WM_WINDOW_TYPE );
1367 }
1368 }
1369
1370 void panel_establish_autohide(Panel *p)
1371 {
1372 _panel_establish_autohide(p->topgwin);
1373 }
1374
1375 void _panel_establish_autohide(LXPanel *p)
1376 {
1377 if (p->priv->autohide)
1378 ah_start(p);
1379 else
1380 {
1381 ah_stop(p);
1382 ah_state_set(p, AH_STATE_VISIBLE);
1383 }
1384 }
1385
1386 /* Set an image from a file with scaling to the panel icon size. */
1387 void panel_image_set_from_file(Panel * p, GtkWidget * image, const char * file)
1388 {
1389 GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file_at_scale(file, p->icon_size, p->icon_size, TRUE, NULL);
1390 if (pixbuf != NULL)
1391 {
1392 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
1393 g_object_unref(pixbuf);
1394 }
1395 }
1396
1397 void lxpanel_image_set_from_file(LXPanel * p, GtkWidget * image, const char * file)
1398 {
1399 panel_image_set_from_file(p->priv, image, file);
1400 }
1401
1402 /* Set an image from a icon theme with scaling to the panel icon size. */
1403 gboolean panel_image_set_icon_theme(Panel * p, GtkWidget * image, const gchar * icon)
1404 {
1405 if (gtk_icon_theme_has_icon(p->icon_theme, icon))
1406 {
1407 GdkPixbuf * pixbuf = gtk_icon_theme_load_icon(p->icon_theme, icon, p->icon_size, 0, NULL);
1408 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
1409 g_object_unref(pixbuf);
1410 return TRUE;
1411 }
1412 return FALSE;
1413 }
1414
1415 gboolean lxpanel_image_set_icon_theme(LXPanel * p, GtkWidget * image, const gchar * icon)
1416 {
1417 return panel_image_set_icon_theme(p->priv, image, icon);
1418 }
1419
1420 static int
1421 panel_parse_plugin(LXPanel *p, config_setting_t *cfg)
1422 {
1423 const char *type = NULL;
1424
1425 ENTER;
1426 config_setting_lookup_string(cfg, "type", &type);
1427 DBG("plug %s\n", type);
1428
1429 if (!type || lxpanel_add_plugin(p, type, cfg, -1) == NULL) {
1430 g_warning( "lxpanel: can't load %s plugin", type);
1431 goto error;
1432 }
1433 RET(1);
1434
1435 error:
1436 RET(0);
1437 }
1438
1439 static void
1440 panel_start_gui(LXPanel *panel, config_setting_t *list)
1441 {
1442 Atom state[3];
1443 XWMHints wmhints;
1444 gulong val;
1445 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1446 Panel *p = panel->priv;
1447 GtkWidget *w = GTK_WIDGET(panel);
1448 config_setting_t *s;
1449 GdkRectangle rect;
1450 int i;
1451
1452 ENTER;
1453
1454 g_debug("panel_start_gui on '%s'", p->name);
1455 p->curdesk = get_net_current_desktop();
1456 p->desknum = get_net_number_of_desktops();
1457 //p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
1458 p->ax = p->ay = p->aw = p->ah = 0;
1459
1460 p->display = gdk_display_get_default();
1461 gtk_window_set_wmclass(GTK_WINDOW(panel), "panel", "lxpanel");
1462
1463 if (G_UNLIKELY(win_grp == NULL))
1464 {
1465 win_grp = gtk_window_group_new();
1466 g_object_add_weak_pointer(G_OBJECT(win_grp), (gpointer *)&win_grp);
1467 gtk_window_group_add_window(win_grp, (GtkWindow*)panel);
1468 g_object_unref(win_grp);
1469 }
1470 else
1471 gtk_window_group_add_window(win_grp, (GtkWindow*)panel);
1472
1473 gtk_widget_add_events( w, GDK_BUTTON_PRESS_MASK );
1474
1475 gtk_widget_realize(w);
1476 //gdk_window_set_decorations(gtk_widget_get_window(p->topgwin), 0);
1477
1478 // main layout manager as a single child of panel
1479 p->box = panel_box_new(panel, FALSE, 0);
1480 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
1481 gtk_container_add(GTK_CONTAINER(panel), p->box);
1482 gtk_widget_show(p->box);
1483 if (p->round_corners)
1484 make_round_corners(p);
1485
1486 p->topxwin = GDK_WINDOW_XID(gtk_widget_get_window(w));
1487 DBG("topxwin = %x\n", p->topxwin);
1488
1489 /* the settings that should be done before window is mapped */
1490 wmhints.flags = InputHint;
1491 wmhints.input = 0;
1492 XSetWMHints (xdisplay, p->topxwin, &wmhints);
1493 #define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
1494 val = WIN_HINTS_SKIP_FOCUS;
1495 XChangeProperty(xdisplay, p->topxwin,
1496 XInternAtom(xdisplay, "_WIN_HINTS", False), XA_CARDINAL, 32,
1497 PropModeReplace, (unsigned char *) &val, 1);
1498
1499 panel_set_dock_type(p);
1500
1501 /* window mapping point */
1502 p->visible = TRUE;
1503 _calculate_position(panel, &rect);
1504 gtk_window_move(GTK_WINDOW(panel), rect.x, rect.y);
1505 gtk_window_present(GTK_WINDOW(panel));
1506
1507 /* the settings that should be done after window is mapped */
1508
1509 /* send it to running wm */
1510 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, G_MAXULONG, 0, 0, 0, 0);
1511 /* and assign it ourself just for case when wm is not running */
1512 val = G_MAXULONG;
1513 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
1514 PropModeReplace, (unsigned char *) &val, 1);
1515
1516 state[0] = a_NET_WM_STATE_SKIP_PAGER;
1517 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
1518 state[2] = a_NET_WM_STATE_STICKY;
1519 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STATE, XA_ATOM,
1520 32, PropModeReplace, (unsigned char *) state, 3);
1521
1522 p->initialized = TRUE;
1523
1524 if (list) for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
1525 if (strcmp(config_setting_get_name(s), "Plugin") == 0 &&
1526 panel_parse_plugin(panel, s)) /* success on plugin start */
1527 i++;
1528 else /* remove invalid data from config */
1529 config_setting_remove_elem(list, i);
1530
1531 RET();
1532 }
1533
1534 /* Exchange the "width" and "height" terminology for vertical and horizontal panels. */
1535 void panel_adjust_geometry_terminology(Panel * p)
1536 {
1537 if ((p->height_label != NULL) && (p->width_label != NULL)
1538 && (p->alignment_left_label != NULL) && (p->alignment_right_label != NULL))
1539 {
1540 if ((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM))
1541 {
1542 gtk_label_set_text(GTK_LABEL(p->height_label), _("Height:"));
1543 gtk_label_set_text(GTK_LABEL(p->width_label), _("Width:"));
1544 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Left"));
1545 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Right"));
1546 }
1547 else
1548 {
1549 gtk_label_set_text(GTK_LABEL(p->height_label), _("Width:"));
1550 gtk_label_set_text(GTK_LABEL(p->width_label), _("Height:"));
1551 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Top"));
1552 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Bottom"));
1553 }
1554 }
1555 }
1556
1557 /* Draw text into a label, with the user preference color and optionally bold. */
1558 void panel_draw_label_text(Panel * p, GtkWidget * label, const char * text,
1559 gboolean bold, float custom_size_factor,
1560 gboolean custom_color)
1561 {
1562 if (text == NULL)
1563 {
1564 /* Null string. */
1565 gtk_label_set_text(GTK_LABEL(label), NULL);
1566 return;
1567 }
1568
1569 /* Compute an appropriate size so the font will scale with the panel's icon size. */
1570 int font_desc;
1571 if (p->usefontsize)
1572 font_desc = p->fontsize;
1573 else
1574 {
1575 GtkStyle *style = gtk_widget_get_style(label);
1576 font_desc = pango_font_description_get_size(style->font_desc) / PANGO_SCALE;
1577 }
1578 font_desc *= custom_size_factor;
1579
1580 /* Check the string for characters that need to be escaped.
1581 * If any are found, create the properly escaped string and use it instead. */
1582 const char * valid_markup = text;
1583 char * escaped_text = NULL;
1584 const char * q;
1585 for (q = text; *q != '\0'; q += 1)
1586 {
1587 if ((*q == '<') || (*q == '>') || (*q == '&'))
1588 {
1589 escaped_text = g_markup_escape_text(text, -1);
1590 valid_markup = escaped_text;
1591 break;
1592 }
1593 }
1594
1595 gchar * formatted_text;
1596 if ((custom_color) && (p->usefontcolor))
1597 {
1598 /* Color, optionally bold. */
1599 formatted_text = g_strdup_printf("<span font_desc=\"%d\" color=\"#%06x\">%s%s%s</span>",
1600 font_desc,
1601 gcolor2rgb24(&p->gfontcolor),
1602 ((bold) ? "<b>" : ""),
1603 valid_markup,
1604 ((bold) ? "</b>" : ""));
1605 }
1606 else
1607 {
1608 /* No color, optionally bold. */
1609 formatted_text = g_strdup_printf("<span font_desc=\"%d\">%s%s%s</span>",
1610 font_desc,
1611 ((bold) ? "<b>" : ""),
1612 valid_markup,
1613 ((bold) ? "</b>" : ""));
1614 }
1615
1616 gtk_label_set_markup(GTK_LABEL(label), formatted_text);
1617 g_free(formatted_text);
1618 g_free(escaped_text);
1619 }
1620
1621 void lxpanel_draw_label_text(LXPanel * p, GtkWidget * label, const char * text,
1622 gboolean bold, float custom_size_factor,
1623 gboolean custom_color)
1624 {
1625 panel_draw_label_text(p->priv, label, text, bold, custom_size_factor, custom_color);
1626 }
1627
1628 void panel_set_panel_configuration_changed(Panel *p)
1629 {
1630 _panel_set_panel_configuration_changed(p->topgwin);
1631 }
1632
1633 void _panel_set_panel_configuration_changed(LXPanel *panel)
1634 {
1635 Panel *p = panel->priv;
1636 GList *plugins, *l;
1637
1638 GtkOrientation previous_orientation = p->orientation;
1639 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
1640 ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
1641
1642 /* either first run or orientation was changed */
1643 if (!p->initialized || previous_orientation != p->orientation)
1644 {
1645 panel_adjust_geometry_terminology(p);
1646 if (p->initialized)
1647 p->height = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? PANEL_HEIGHT_DEFAULT : PANEL_WIDTH_DEFAULT);
1648 if (p->height_control != NULL)
1649 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->height_control), p->height);
1650 if ((p->widthtype == WIDTH_PIXEL) && (p->width_control != NULL))
1651 {
1652 int value = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? gdk_screen_width() : gdk_screen_height());
1653 gtk_spin_button_set_range(GTK_SPIN_BUTTON(p->width_control), 0, value);
1654 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->width_control), value);
1655 }
1656 }
1657
1658 /* FIXME: it's deprecated, kept for binary compatibility */
1659 if (p->orientation == GTK_ORIENTATION_HORIZONTAL) {
1660 p->my_box_new = gtk_hbox_new;
1661 p->my_separator_new = gtk_vseparator_new;
1662 } else {
1663 p->my_box_new = gtk_vbox_new;
1664 p->my_separator_new = gtk_hseparator_new;
1665 }
1666
1667 /* recreate the main layout box */
1668 if (p->box != NULL)
1669 {
1670 gtk_orientable_set_orientation(GTK_ORIENTABLE(p->box), p->orientation);
1671 }
1672
1673 /* NOTE: This loop won't be executed when panel started since
1674 plugins are not loaded at that time.
1675 This is used when the orientation of the panel is changed
1676 from the config dialog, and plugins should be re-layout.
1677 */
1678 plugins = p->box ? gtk_container_get_children(GTK_CONTAINER(p->box)) : NULL;
1679 for( l = plugins; l; l = l->next ) {
1680 GtkWidget *w = (GtkWidget*)l->data;
1681 const LXPanelPluginInit *init = PLUGIN_CLASS(w);
1682 if (init->reconfigure)
1683 init->reconfigure(panel, w);
1684 }
1685 g_list_free(plugins);
1686 /* panel geometry changed? update panel background then */
1687 _panel_queue_update_background(panel);
1688 }
1689
1690 static int
1691 panel_parse_global(Panel *p, config_setting_t *cfg)
1692 {
1693 const char *str;
1694 gint i;
1695
1696 /* check Global config */
1697 if (!cfg || strcmp(config_setting_get_name(cfg), "Global") != 0)
1698 {
1699 g_warning( "lxpanel: Global section not found");
1700 RET(0);
1701 }
1702 if (config_setting_lookup_string(cfg, "edge", &str))
1703 p->edge = str2num(edge_pair, str, EDGE_NONE);
1704 if (config_setting_lookup_string(cfg, "allign", &str))
1705 p->allign = str2num(allign_pair, str, ALLIGN_NONE);
1706 config_setting_lookup_int(cfg, "monitor", &p->monitor);
1707 config_setting_lookup_int(cfg, "margin", &p->margin);
1708 if (config_setting_lookup_string(cfg, "widthtype", &str))
1709 p->widthtype = str2num(width_pair, str, WIDTH_NONE);
1710 config_setting_lookup_int(cfg, "width", &p->width);
1711 if (config_setting_lookup_string(cfg, "heighttype", &str))
1712 p->heighttype = str2num(height_pair, str, HEIGHT_NONE);
1713 config_setting_lookup_int(cfg, "height", &p->height);
1714 if (config_setting_lookup_int(cfg, "spacing", &i) && i > 0)
1715 p->spacing = i;
1716 if (config_setting_lookup_int(cfg, "setdocktype", &i))
1717 p->setdocktype = i != 0;
1718 if (config_setting_lookup_int(cfg, "setpartialstrut", &i))
1719 p->setstrut = i != 0;
1720 if (config_setting_lookup_int(cfg, "RoundCorners", &i))
1721 p->round_corners = i != 0;
1722 if (config_setting_lookup_int(cfg, "transparent", &i))
1723 p->transparent = i != 0;
1724 if (config_setting_lookup_int(cfg, "alpha", &p->alpha))
1725 {
1726 if (p->alpha > 255)
1727 p->alpha = 255;
1728 }
1729 if (config_setting_lookup_int(cfg, "autohide", &i))
1730 p->autohide = i != 0;
1731 if (config_setting_lookup_int(cfg, "heightwhenhidden", &i))
1732 p->height_when_hidden = MAX(0, i);
1733 if (config_setting_lookup_string(cfg, "tintcolor", &str))
1734 {
1735 if (!gdk_color_parse (str, &p->gtintcolor))
1736 gdk_color_parse ("white", &p->gtintcolor);
1737 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
1738 DBG("tintcolor=%x\n", p->tintcolor);
1739 }
1740 if (config_setting_lookup_int(cfg, "usefontcolor", &i))
1741 p->usefontcolor = i != 0;
1742 if (config_setting_lookup_string(cfg, "fontcolor", &str))
1743 {
1744 if (!gdk_color_parse (str, &p->gfontcolor))
1745 gdk_color_parse ("black", &p->gfontcolor);
1746 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
1747 DBG("fontcolor=%x\n", p->fontcolor);
1748 }
1749 if (config_setting_lookup_int(cfg, "usefontsize", &i))
1750 p->usefontsize = i != 0;
1751 if (config_setting_lookup_int(cfg, "fontsize", &i) && i > 0)
1752 p->fontsize = i;
1753 if (config_setting_lookup_int(cfg, "background", &i))
1754 p->background = i != 0;
1755 if (config_setting_lookup_string(cfg, "backgroundfile", &str))
1756 p->background_file = g_strdup(str);
1757 config_setting_lookup_int(cfg, "iconsize", &p->icon_size);
1758
1759 panel_normalize_configuration(p);
1760
1761 return 1;
1762 }
1763
1764 static void on_monitors_changed(GdkScreen* screen, gpointer unused)
1765 {
1766 GSList *pl;
1767 int monitors = gdk_screen_get_n_monitors(screen);
1768
1769 for (pl = all_panels; pl; pl = pl->next)
1770 {
1771 LXPanel *p = pl->data;
1772
1773 /* handle connecting and disconnecting monitors now */
1774 if (p->priv->monitor < monitors && !p->priv->initialized)
1775 panel_start_gui(p, config_setting_get_member(config_root_setting(p->priv->config), ""));
1776 else if (p->priv->monitor >= monitors && p->priv->initialized)
1777 panel_stop_gui(p);
1778 /* resize panel if appropriate monitor changed its size or position */
1779 else
1780 {
1781 /* SF bug #666: after screen resize panel cannot establish
1782 right size since cannot be moved while is hidden */
1783 ah_state_set(p, AH_STATE_VISIBLE);
1784 gtk_widget_queue_resize(GTK_WIDGET(p));
1785 }
1786 }
1787 }
1788
1789 static int panel_start(LXPanel *p)
1790 {
1791 config_setting_t *list;
1792 GdkScreen *screen = gdk_screen_get_default();
1793
1794 /* parse global section */
1795 ENTER;
1796
1797 list = config_setting_get_member(config_root_setting(p->priv->config), "");
1798 if (!list || !panel_parse_global(p->priv, config_setting_get_elem(list, 0)))
1799 RET(0);
1800
1801 if (p->priv->monitor < gdk_screen_get_n_monitors(screen))
1802 panel_start_gui(p, list);
1803 if (monitors_handler == 0)
1804 monitors_handler = g_signal_connect(screen, "monitors-changed",
1805 G_CALLBACK(on_monitors_changed), NULL);
1806 return 1;
1807 }
1808
1809 void panel_destroy(Panel *p)
1810 {
1811 gtk_widget_destroy(GTK_WIDGET(p->topgwin));
1812 }
1813
1814 LXPanel* panel_new( const char* config_file, const char* config_name )
1815 {
1816 LXPanel* panel = NULL;
1817
1818 if (G_LIKELY(config_file))
1819 {
1820 panel = panel_allocate();
1821 panel->priv->name = g_strdup(config_name);
1822 g_debug("starting panel from file %s",config_file);
1823 if (!config_read_file(panel->priv->config, config_file) ||
1824 !panel_start(panel))
1825 {
1826 g_warning( "lxpanel: can't start panel");
1827 gtk_widget_destroy(GTK_WIDGET(panel));
1828 panel = NULL;
1829 }
1830 }
1831 return panel;
1832 }
1833
1834
1835 GtkOrientation panel_get_orientation(LXPanel *panel)
1836 {
1837 return panel->priv->orientation;
1838 }
1839
1840 gint panel_get_icon_size(LXPanel *panel)
1841 {
1842 return panel->priv->icon_size;
1843 }
1844
1845 gint panel_get_height(LXPanel *panel)
1846 {
1847 return panel->priv->height;
1848 }
1849
1850 Window panel_get_xwindow(LXPanel *panel)
1851 {
1852 return panel->priv->topxwin;
1853 }
1854
1855 gint panel_get_monitor(LXPanel *panel)
1856 {
1857 return panel->priv->monitor;
1858 }
1859
1860 GtkStyle *panel_get_defstyle(LXPanel *panel)
1861 {
1862 return panel->priv->defstyle;
1863 }
1864
1865 GtkIconTheme *panel_get_icon_theme(LXPanel *panel)
1866 {
1867 return panel->priv->icon_theme;
1868 }
1869
1870 gboolean panel_is_at_bottom(LXPanel *panel)
1871 {
1872 return panel->priv->edge == EDGE_BOTTOM;
1873 }
1874
1875 gboolean panel_is_dynamic(LXPanel *panel)
1876 {
1877 return panel->priv->widthtype == WIDTH_REQUEST;
1878 }
1879
1880 GtkWidget *panel_box_new(LXPanel *panel, gboolean homogeneous, gint spacing)
1881 {
1882 if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1883 return gtk_hbox_new(homogeneous, spacing);
1884 return gtk_vbox_new(homogeneous, spacing);
1885 }
1886
1887 GtkWidget *panel_separator_new(LXPanel *panel)
1888 {
1889 if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1890 return gtk_vseparator_new();
1891 return gtk_hseparator_new();
1892 }
1893
1894 gboolean _class_is_present(const LXPanelPluginInit *init)
1895 {
1896 GSList *sl;
1897
1898 for (sl = all_panels; sl; sl = sl->next )
1899 {
1900 LXPanel *panel = (LXPanel*)sl->data;
1901 GList *plugins, *p;
1902
1903 if (panel->priv->box == NULL)
1904 continue;
1905 plugins = gtk_container_get_children(GTK_CONTAINER(panel->priv->box));
1906 for (p = plugins; p; p = p->next)
1907 if (PLUGIN_CLASS(p->data) == init)
1908 {
1909 g_list_free(plugins);
1910 return TRUE;
1911 }
1912 g_list_free(plugins);
1913 }
1914 return FALSE;
1915 }