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