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