Commit from LXDE Pootle server by user armakolas.: 1309 of 1422 strings translated...
[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
AG
783 Panel *p = panel->priv;
784
9a2c13d0
AG
785 ENTER;
786 if (p->ah_state != ah_state) {
787 p->ah_state = ah_state;
788 switch (ah_state) {
789 case AH_STATE_VISIBLE:
a7bd16a4 790 gtk_widget_show(GTK_WIDGET(panel));
9a2c13d0 791 gtk_widget_show(p->box);
9a762e63 792 gtk_widget_queue_resize(GTK_WIDGET(panel));
a7bd16a4 793 gtk_window_stick(GTK_WINDOW(panel));
9a2c13d0
AG
794 p->visible = TRUE;
795 break;
796 case AH_STATE_WAITING:
9a762e63
AG
797 if (p->hide_timeout)
798 g_source_remove(p->hide_timeout);
a7bd16a4 799 p->hide_timeout = g_timeout_add(2 * PERIOD, ah_state_hide_timeout, panel);
9a2c13d0
AG
800 break;
801 case AH_STATE_HIDDEN:
802 if (p->height_when_hidden > 0)
803 gtk_widget_hide(p->box);
804 else
a7bd16a4 805 gtk_widget_hide(GTK_WIDGET(panel));
9a2c13d0
AG
806 p->visible = FALSE;
807 }
808 } else if (p->autohide && p->ah_far) {
e1fd11ee
AG
809 switch (ah_state) {
810 case AH_STATE_VISIBLE:
a7bd16a4 811 ah_state_set(panel, AH_STATE_WAITING);
e1fd11ee
AG
812 break;
813 case AH_STATE_WAITING:
814 break;
815 case AH_STATE_HIDDEN:
816 /* configurator might change height_when_hidden value */
817 if (p->height_when_hidden > 0)
818 {
819 if (gtk_widget_get_visible(p->box))
820 {
821 gtk_widget_hide(p->box);
a7bd16a4 822 gtk_widget_show(GTK_WIDGET(panel));
e1fd11ee
AG
823 }
824 }
825 else
a7bd16a4 826 if (gtk_widget_get_visible(GTK_WIDGET(panel)))
e1fd11ee 827 {
a7bd16a4 828 gtk_widget_hide(GTK_WIDGET(panel));
e1fd11ee
AG
829 gtk_widget_show(p->box);
830 }
831 }
9a2c13d0
AG
832 } else {
833 switch (ah_state) {
834 case AH_STATE_VISIBLE:
835 break;
836 case AH_STATE_WAITING:
837 if (p->hide_timeout)
838 g_source_remove(p->hide_timeout);
839 p->hide_timeout = 0;
840 /* continue with setting visible */
841 case AH_STATE_HIDDEN:
a7bd16a4 842 ah_state_set(panel, AH_STATE_VISIBLE);
9a2c13d0
AG
843 }
844 }
845 RET();
846}
847
848/* starts autohide behaviour */
a7bd16a4 849static void ah_start(LXPanel *p)
9a2c13d0
AG
850{
851 ENTER;
a7bd16a4
AG
852 if (!p->priv->mouse_timeout)
853 p->priv->mouse_timeout = g_timeout_add(PERIOD, (GSourceFunc) mouse_watch, p);
9a2c13d0
AG
854 RET();
855}
856
857/* stops autohide */
a7bd16a4 858static void ah_stop(LXPanel *p)
9a2c13d0
AG
859{
860 ENTER;
a7bd16a4
AG
861 if (p->priv->mouse_timeout) {
862 g_source_remove(p->priv->mouse_timeout);
863 p->priv->mouse_timeout = 0;
9a2c13d0 864 }
a7bd16a4
AG
865 if (p->priv->hide_timeout) {
866 g_source_remove(p->priv->hide_timeout);
867 p->priv->hide_timeout = 0;
9a2c13d0
AG
868 }
869 RET();
870}
9a2c13d0
AG
871/* end of the autohide code
872 * ------------------------------------------------------------- */
873
fddae119
FC
874static gint
875panel_popupmenu_configure(GtkWidget *widget, gpointer user_data)
876{
a7bd16a4 877 panel_configure( (LXPanel*)user_data, 0 );
4b93d81e 878 return TRUE;
fddae119
FC
879}
880
17fab6e5 881static void panel_popupmenu_config_plugin( GtkMenuItem* item, GtkWidget* plugin )
cf701cb7 882{
a7bd16a4 883 Panel *panel = PLUGIN_PANEL(plugin)->priv;
17fab6e5 884
2f1173de 885 lxpanel_plugin_show_config_dialog(plugin);
930af9fd
HJYP
886
887 /* FIXME: this should be more elegant */
17fab6e5 888 panel->config_changed = TRUE;
cf701cb7
HJYP
889}
890
a7bd16a4 891static void panel_popupmenu_add_item( GtkMenuItem* item, LXPanel* panel )
4b93d81e
HJYP
892{
893 /* panel_add_plugin( panel, panel->topgwin ); */
8d8b66da 894 panel_configure( panel, 2 );
cf701cb7
HJYP
895}
896
17fab6e5 897static void panel_popupmenu_remove_item( GtkMenuItem* item, GtkWidget* plugin )
cf701cb7 898{
a7bd16a4 899 Panel* panel = PLUGIN_PANEL(plugin)->priv;
b7e8ad02
MJ
900
901 /* If the configuration dialog is open, there will certainly be a crash if the
902 * user manipulates the Configured Plugins list, after we remove this entry.
903 * Close the configuration dialog if it is open. */
904 if (panel->pref_dialog != NULL)
905 {
906 gtk_widget_destroy(panel->pref_dialog);
907 panel->pref_dialog = NULL;
908 }
17fab6e5
AG
909 config_setting_destroy(g_object_get_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf));
910 /* reset conf pointer because the widget still may be referenced by configurator */
911 g_object_set_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf, NULL);
b7e8ad02 912
a7bd16a4 913 lxpanel_config_save(PLUGIN_PANEL(plugin));
17fab6e5 914 gtk_widget_destroy(plugin);
cf701cb7
HJYP
915}
916
3e7b8eb7
HJYP
917/* FIXME: Potentially we can support multiple panels at the same edge,
918 * but currently this cannot be done due to some positioning problems. */
64afc832 919static char* gen_panel_name( int edge, gint monitor )
3e7b8eb7
HJYP
920{
921 const char* edge_str = num2str( edge_pair, edge, "" );
922 char* name = NULL;
1f4bc3aa 923 char* dir = _user_config_file_name("panels", NULL);
3e7b8eb7
HJYP
924 int i;
925 for( i = 0; i < G_MAXINT; ++i )
926 {
927 char* f;
64afc832
R
928 if(monitor != 0)
929 name = g_strdup_printf( "%s-m%d-%d", edge_str, monitor, i );
930 else if( G_LIKELY( i > 0 ) )
3e7b8eb7
HJYP
931 name = g_strdup_printf( "%s%d", edge_str, i );
932 else
933 name = g_strdup( edge_str );
64afc832 934
3e7b8eb7
HJYP
935 f = g_build_filename( dir, name, NULL );
936 if( ! g_file_test( f, G_FILE_TEST_EXISTS ) )
937 {
938 g_free( f );
939 break;
940 }
941 g_free( name );
942 g_free( f );
943 }
944 g_free( dir );
945 return name;
946}
947
948/* FIXME: Potentially we can support multiple panels at the same edge,
949 * but currently this cannot be done due to some positioning problems. */
a7bd16a4 950static void panel_popupmenu_create_panel( GtkMenuItem* item, LXPanel* panel )
cf701cb7 951{
64afc832
R
952 gint m, e, monitors;
953 GdkScreen *screen;
a7bd16a4
AG
954 LXPanel *new_panel = panel_allocate();
955 Panel *p = new_panel->priv;
59c0082e 956 config_setting_t *global;
9dd114c4 957
958 /* Allocate the edge. */
ca4eee75 959 screen = gtk_widget_get_screen(GTK_WIDGET(panel));
64afc832
R
960 g_assert(screen);
961 monitors = gdk_screen_get_n_monitors(screen);
2a23649a
AG
962 /* try to allocate edge on current monitor first */
963 m = panel->priv->monitor;
964 if (m < 0)
965 {
966 /* panel is spanned over the screen, guess from pointer now */
967 gint x, y;
968 gdk_display_get_pointer(gdk_display_get_default(), NULL, &x, &y, NULL);
969 m = gdk_screen_get_monitor_at_point(screen, x, y);
970 }
971 for (e = 1; e < 5; ++e)
972 {
973 if (panel_edge_available(p, e, m))
974 {
975 p->edge = e;
976 p->monitor = m;
977 goto found_edge;
978 }
979 }
980 /* try all monitors */
64afc832
R
981 for(m=0; m<monitors; ++m)
982 {
983 /* try each of the four edges */
984 for(e=1; e<5; ++e)
985 {
a7bd16a4
AG
986 if(panel_edge_available(p,e,m)) {
987 p->edge = e;
988 p->monitor = m;
64afc832
R
989 goto found_edge;
990 }
991 }
992 }
993
a7bd16a4 994 gtk_widget_destroy(GTK_WIDGET(new_panel));
06e29ce1 995 g_warning("Error adding panel: There is no room for another panel. All the edges are taken.");
bb4cf963 996 fm_show_error(NULL, NULL, _("There is no room for another panel. All the edges are taken."));
64afc832
R
997 return;
998
999found_edge:
a7bd16a4 1000 p->name = gen_panel_name(p->edge, p->monitor);
9dd114c4 1001
17fab6e5 1002 /* create new config with first group "Global" */
59c0082e
AG
1003 global = config_group_add_subgroup(config_root_setting(p->config), "Global");
1004 config_group_set_string(global, "edge", num2str(edge_pair, p->edge, "none"));
1005 config_group_set_int(global, "monitor", p->monitor);
9dd114c4 1006 panel_configure(new_panel, 0);
a7bd16a4 1007 panel_normalize_configuration(p);
51abba48 1008 panel_start_gui(new_panel, NULL);
9dd114c4 1009
a7bd16a4 1010 lxpanel_config_save(new_panel);
9dd114c4 1011 all_panels = g_slist_prepend(all_panels, new_panel);
cf701cb7
HJYP
1012}
1013
a7bd16a4 1014static void panel_popupmenu_delete_panel( GtkMenuItem* item, LXPanel* panel )
cf701cb7
HJYP
1015{
1016 GtkWidget* dlg;
1017 gboolean ok;
a7bd16a4 1018 dlg = gtk_message_dialog_new_with_markup( GTK_WINDOW(panel),
cf701cb7
HJYP
1019 GTK_DIALOG_MODAL,
1020 GTK_MESSAGE_QUESTION,
1021 GTK_BUTTONS_OK_CANCEL,
1022 _("Really delete this panel?\n<b>Warning: This can not be recovered.</b>") );
d1d43629 1023 panel_apply_icon(GTK_WINDOW(dlg));
cf701cb7
HJYP
1024 gtk_window_set_title( (GtkWindow*)dlg, _("Confirm") );
1025 ok = ( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK );
1026 gtk_widget_destroy( dlg );
1027 if( ok )
1028 {
1f4bc3aa 1029 gchar *fname;
cf701cb7 1030 all_panels = g_slist_remove( all_panels, panel );
4b93d81e
HJYP
1031
1032 /* delete the config file of this panel */
a7bd16a4 1033 fname = _user_config_file_name("panels", panel->priv->name);
4b93d81e 1034 g_unlink( fname );
1f4bc3aa 1035 g_free(fname);
a7bd16a4
AG
1036 panel->priv->config_changed = 0;
1037 gtk_widget_destroy(GTK_WIDGET(panel));
cf701cb7
HJYP
1038 }
1039}
1040
e7a42ecf 1041static void panel_popupmenu_about( GtkMenuItem* item, Panel* panel )
1042{
1043 GtkWidget *about;
1044 const gchar* authors[] = {
1045 "Hong Jen Yee (PCMan) <pcman.tw@gmail.com>",
1046 "Jim Huang <jserv.tw@gmail.com>",
1047 "Greg McNew <gmcnew@gmail.com> (battery plugin)",
1048 "Fred Chien <cfsghost@gmail.com>",
1049 "Daniel Kesler <kesler.daniel@gmail.com>",
1050 "Juergen Hoetzel <juergen@archlinux.org>",
2918994e 1051 "Marty Jack <martyj19@comcast.net>",
815e1027 1052 "Martin Bagge <brother@bsnet.se>",
bb4cf963
AG
1053 "Andriy Grytsenko <andrej@rep.kiev.ua>",
1054 "Giuseppe Penone <giuspen@gmail.com>",
1055 "Piotr Sipika <piotr.sipika@gmail.com>",
e7a42ecf 1056 NULL
1057 };
1058 /* TRANSLATORS: Replace this string with your names, one name per line. */
1059 gchar *translators = _( "translator-credits" );
1060
1061 about = gtk_about_dialog_new();
1062 panel_apply_icon(GTK_WINDOW(about));
1063 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), VERSION);
09fa171b 1064 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about), _("LXPanel"));
4c91be3e
JL
1065
1066 if(gtk_icon_theme_has_icon(panel->icon_theme, "video-display"))
1067 {
1068 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
1069 gtk_icon_theme_load_icon(panel->icon_theme, "video-display", 48, 0, NULL));
1070 }
1071 else if (gtk_icon_theme_has_icon(panel->icon_theme, "start-here"))
1072 {
1073 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
1074 gtk_icon_theme_load_icon(panel->icon_theme, "start-here", 48, 0, NULL));
1075 }
0bcf9045 1076 else
4c91be3e
JL
1077 {
1078 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
0b806437 1079 gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL));
4c91be3e
JL
1080 }
1081
b840f7cc 1082 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about), _("Copyright (C) 2008-2014"));
e7a42ecf 1083 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), _( "Desktop panel for LXDE project"));
1084 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.");
1085 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://lxde.org/");
1086 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about), authors);
1087 gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about), translators);
1088 gtk_dialog_run(GTK_DIALOG(about));
0bcf9045 1089 gtk_widget_destroy(about);
e7a42ecf 1090}
1091
1092void panel_apply_icon( GtkWindow *w )
1093{
0bcf9045
AG
1094 GdkPixbuf* window_icon;
1095
1096 if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "video-display"))
4c91be3e 1097 {
0bcf9045
AG
1098 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "video-display", 24, 0, NULL);
1099 }
1100 else if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "start-here"))
4c91be3e 1101 {
0bcf9045
AG
1102 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "start-here", 24, 0, NULL);
1103 }
89496346 1104 else
4c91be3e 1105 {
0bcf9045
AG
1106 window_icon = gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL);
1107 }
21f91705 1108 gtk_window_set_icon(w, window_icon);
e7a42ecf 1109}
1110
a7bd16a4 1111GtkMenu* lxpanel_get_plugin_menu( LXPanel* panel, GtkWidget* plugin, gboolean use_sub_menu )
cf701cb7 1112{
e3b89f43 1113 GtkWidget *menu_item, *img;
1114 GtkMenu *ret,*menu;
191694fb 1115 const LXPanelPluginInit *init;
cf701cb7 1116 char* tmp;
eb1762e5 1117
e3b89f43 1118 ret = menu = GTK_MENU(gtk_menu_new());
cf701cb7 1119
eb1762e5
AG
1120 if (plugin)
1121 {
1122 init = PLUGIN_CLASS(plugin);
1123 /* create single item - plugin instance settings */
1124 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
1125 tmp = g_strdup_printf( _("\"%s\" Settings"), _(init->name) );
1126 menu_item = gtk_image_menu_item_new_with_label( tmp );
1127 g_free( tmp );
1128 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1129 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
1130 if( init->config )
1131 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
1132 else
1133 gtk_widget_set_sensitive( menu_item, FALSE );
1134 /* add custom items by plugin if requested */
1135 if (init->update_context_menu != NULL)
1136 use_sub_menu = init->update_context_menu(plugin, ret);
1137 /* append a separator */
1138 menu_item = gtk_separator_menu_item_new();
1139 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
1140 }
1141 if (use_sub_menu)
1142 menu = GTK_MENU(gtk_menu_new());
1143
4b93d81e
HJYP
1144 img = gtk_image_new_from_stock( GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU );
1145 menu_item = gtk_image_menu_item_new_with_label(_("Add / Remove Panel Items"));
1146 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1147 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1148 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
cf701cb7
HJYP
1149
1150 if( plugin )
1151 {
1152 img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
17fab6e5 1153 tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(init->name) );
cf701cb7
HJYP
1154 menu_item = gtk_image_menu_item_new_with_label( tmp );
1155 g_free( tmp );
1156 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1157 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1158 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_remove_item), plugin );
1159 }
1160
1161 menu_item = gtk_separator_menu_item_new();
1162 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1163
4b93d81e
HJYP
1164 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
1165 menu_item = gtk_image_menu_item_new_with_label(_("Panel Settings"));
1166 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1167 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1168 g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_popupmenu_configure), panel );
1169
cf701cb7
HJYP
1170 img = gtk_image_new_from_stock( GTK_STOCK_NEW, GTK_ICON_SIZE_MENU );
1171 menu_item = gtk_image_menu_item_new_with_label(_("Create New Panel"));
1172 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1173 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1174 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_create_panel), panel );
1175
1176 img = gtk_image_new_from_stock( GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU );
1177 menu_item = gtk_image_menu_item_new_with_label(_("Delete This Panel"));
1178 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1179 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1180 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_delete_panel), panel );
1181 if( ! all_panels->next ) /* if this is the only panel */
1182 gtk_widget_set_sensitive( menu_item, FALSE );
1183
e7a42ecf 1184 menu_item = gtk_separator_menu_item_new();
1185 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1186
1187 img = gtk_image_new_from_stock( GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU );
1188 menu_item = gtk_image_menu_item_new_with_label(_("About"));
1189 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1190 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
a7bd16a4 1191 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_about), panel->priv );
e7a42ecf 1192
cf701cb7
HJYP
1193 if( use_sub_menu )
1194 {
cf701cb7
HJYP
1195 menu_item = gtk_image_menu_item_new_with_label(_("Panel"));
1196 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
e3b89f43 1197 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), GTK_WIDGET(menu) );
3e7b8eb7
HJYP
1198 }
1199
eb1762e5 1200 gtk_widget_show_all(GTK_WIDGET(ret));
3e7b8eb7 1201
cf701cb7
HJYP
1202 g_signal_connect( ret, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
1203 return ret;
1204}
1205
17fab6e5
AG
1206/* for old plugins compatibility */
1207GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
1208{
a7bd16a4 1209 return lxpanel_get_plugin_menu(panel->topgwin, plugin->pwid, use_sub_menu);
17fab6e5
AG
1210}
1211
a52c2257
HJYP
1212/****************************************************
1213 * panel creation *
1214 ****************************************************/
176fb687 1215
a52c2257 1216static void
22242ed4 1217make_round_corners(Panel *p)
a52c2257 1218{
a97d06a6 1219 /* FIXME: This should be re-written with shape extension of X11 */
4542c20d 1220 /* gdk_window_shape_combine_mask() can be used */
bee4c26e
HJYP
1221}
1222
22242ed4 1223void panel_set_dock_type(Panel *p)
bee4c26e 1224{
09fa171b
AG
1225 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1226
bee4c26e
HJYP
1227 if (p->setdocktype) {
1228 Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
09fa171b 1229 XChangeProperty(xdisplay, p->topxwin,
bee4c26e
HJYP
1230 a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
1231 PropModeReplace, (unsigned char *) &state, 1);
1232 }
1233 else {
09fa171b 1234 XDeleteProperty( xdisplay, p->topxwin, a_NET_WM_WINDOW_TYPE );
bee4c26e 1235 }
a52c2257
HJYP
1236}
1237
176fb687 1238void panel_establish_autohide(Panel *p)
1239{
a7bd16a4
AG
1240 _panel_establish_autohide(p->topgwin);
1241}
1242
1243void _panel_establish_autohide(LXPanel *p)
1244{
1245 if (p->priv->autohide)
9a2c13d0
AG
1246 ah_start(p);
1247 else
176fb687 1248 {
9a2c13d0
AG
1249 ah_stop(p);
1250 ah_state_set(p, AH_STATE_VISIBLE);
176fb687 1251 }
1252}
1253
8f9e6256 1254/* Set an image from a file with scaling to the panel icon size. */
fcb35553 1255void panel_image_set_from_file(Panel * p, GtkWidget * image, const char * file)
8f9e6256 1256{
1257 GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file_at_scale(file, p->icon_size, p->icon_size, TRUE, NULL);
1258 if (pixbuf != NULL)
1259 {
1260 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
1261 g_object_unref(pixbuf);
1262 }
1263}
1264
a7bd16a4
AG
1265void lxpanel_image_set_from_file(LXPanel * p, GtkWidget * image, const char * file)
1266{
1267 panel_image_set_from_file(p->priv, image, file);
1268}
1269
c14620f2
MJ
1270/* Set an image from a icon theme with scaling to the panel icon size. */
1271gboolean panel_image_set_icon_theme(Panel * p, GtkWidget * image, const gchar * icon)
1272{
1b532bce 1273 if (gtk_icon_theme_has_icon(p->icon_theme, icon))
c14620f2 1274 {
1b532bce 1275 GdkPixbuf * pixbuf = gtk_icon_theme_load_icon(p->icon_theme, icon, p->icon_size, 0, NULL);
c14620f2
MJ
1276 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
1277 g_object_unref(pixbuf);
1278 return TRUE;
1279 }
1280 return FALSE;
1281}
1282
a7bd16a4
AG
1283gboolean lxpanel_image_set_icon_theme(LXPanel * p, GtkWidget * image, const gchar * icon)
1284{
1285 return panel_image_set_icon_theme(p->priv, image, icon);
1286}
1287
51abba48
AG
1288static int
1289panel_parse_plugin(LXPanel *p, config_setting_t *cfg)
1290{
1291 const char *type = NULL;
1292
1293 ENTER;
1294 config_setting_lookup_string(cfg, "type", &type);
1295 DBG("plug %s\n", type);
1296
1297 if (!type || lxpanel_add_plugin(p, type, cfg, -1) == NULL) {
1298 g_warning( "lxpanel: can't load %s plugin", type);
1299 goto error;
1300 }
1301 RET(1);
1302
1303error:
1304 RET(0);
1305}
1306
0defe4b9 1307static void
51abba48 1308panel_start_gui(LXPanel *panel, config_setting_t *list)
a52c2257
HJYP
1309{
1310 Atom state[3];
1311 XWMHints wmhints;
0bfcc6c9 1312 gulong val;
09fa171b 1313 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
a7bd16a4
AG
1314 Panel *p = panel->priv;
1315 GtkWidget *w = GTK_WIDGET(panel);
51abba48
AG
1316 config_setting_t *s;
1317 int i;
6db11841 1318
a52c2257
HJYP
1319 ENTER;
1320
51abba48 1321 g_debug("panel_start_gui on '%s'", p->name);
9dd114c4 1322 p->curdesk = get_net_current_desktop();
1323 p->desknum = get_net_number_of_desktops();
1324 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
b2700758 1325 p->ax = p->ay = p->aw = p->ah = 0;
9dd114c4 1326
176fb687 1327 p->display = gdk_display_get_default();
a7bd16a4 1328 gtk_window_set_wmclass(GTK_WINDOW(panel), "panel", "lxpanel");
77886b88 1329
29657982
AG
1330 if (G_UNLIKELY(win_grp == NULL))
1331 {
1332 win_grp = gtk_window_group_new();
1333 g_object_add_weak_pointer(G_OBJECT(win_grp), (gpointer *)&win_grp);
1334 gtk_window_group_add_window(win_grp, (GtkWindow*)panel);
1335 g_object_unref(win_grp);
1336 }
1337 else
1338 gtk_window_group_add_window(win_grp, (GtkWindow*)panel);
e2957bd2 1339
a7bd16a4 1340 gtk_widget_add_events( w, GDK_BUTTON_PRESS_MASK );
f2d54481 1341
a7bd16a4 1342 gtk_widget_realize(w);
175f73d1 1343 //gdk_window_set_decorations(gtk_widget_get_window(p->topgwin), 0);
2de71c90 1344
4542c20d 1345 // main layout manager as a single child of panel
a7bd16a4 1346 p->box = panel_box_new(panel, FALSE, 0);
a52c2257 1347 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
a7bd16a4 1348 gtk_container_add(GTK_CONTAINER(panel), p->box);
a52c2257 1349 gtk_widget_show(p->box);
a97d06a6
HJYP
1350 if (p->round_corners)
1351 make_round_corners(p);
6db11841 1352
a7bd16a4 1353 p->topxwin = GDK_WINDOW_XWINDOW(gtk_widget_get_window(w));
a52c2257
HJYP
1354 DBG("topxwin = %x\n", p->topxwin);
1355
1356 /* the settings that should be done before window is mapped */
1357 wmhints.flags = InputHint;
1358 wmhints.input = 0;
09fa171b 1359 XSetWMHints (xdisplay, p->topxwin, &wmhints);
24053345 1360#define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
a52c2257 1361 val = WIN_HINTS_SKIP_FOCUS;
09fa171b
AG
1362 XChangeProperty(xdisplay, p->topxwin,
1363 XInternAtom(xdisplay, "_WIN_HINTS", False), XA_CARDINAL, 32,
a52c2257
HJYP
1364 PropModeReplace, (unsigned char *) &val, 1);
1365
bee4c26e 1366 panel_set_dock_type(p);
a52c2257
HJYP
1367
1368 /* window mapping point */
4d86ff00 1369 gtk_window_present(GTK_WINDOW(panel));
a52c2257
HJYP
1370
1371 /* the settings that should be done after window is mapped */
1372
1373 /* send it to running wm */
0bfcc6c9 1374 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, G_MAXULONG, 0, 0, 0, 0);
a52c2257 1375 /* and assign it ourself just for case when wm is not running */
0bfcc6c9 1376 val = G_MAXULONG;
09fa171b 1377 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
a52c2257
HJYP
1378 PropModeReplace, (unsigned char *) &val, 1);
1379
1380 state[0] = a_NET_WM_STATE_SKIP_PAGER;
1381 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
1382 state[2] = a_NET_WM_STATE_STICKY;
09fa171b 1383 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STATE, XA_ATOM,
a52c2257
HJYP
1384 32, PropModeReplace, (unsigned char *) state, 3);
1385
5eaabb1b 1386 p->initialized = TRUE;
77886b88 1387
51abba48
AG
1388 if (list) for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
1389 if (strcmp(config_setting_get_name(s), "Plugin") == 0 &&
1390 panel_parse_plugin(panel, s)) /* success on plugin start */
1391 i++;
1392 else /* remove invalid data from config */
1393 config_setting_remove_elem(list, i);
1394
a52c2257
HJYP
1395 RET();
1396}
1397
2918994e 1398/* Exchange the "width" and "height" terminology for vertical and horizontal panels. */
1399void panel_adjust_geometry_terminology(Panel * p)
9dd114c4 1400{
8ed3b3d4 1401 if ((p->height_label != NULL) && (p->width_label != NULL)
1402 && (p->alignment_left_label != NULL) && (p->alignment_right_label != NULL))
9dd114c4 1403 {
1404 if ((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM))
1405 {
1406 gtk_label_set_text(GTK_LABEL(p->height_label), _("Height:"));
1407 gtk_label_set_text(GTK_LABEL(p->width_label), _("Width:"));
2918994e 1408 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Left"));
1409 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Right"));
9dd114c4 1410 }
1411 else
1412 {
1413 gtk_label_set_text(GTK_LABEL(p->height_label), _("Width:"));
1414 gtk_label_set_text(GTK_LABEL(p->width_label), _("Height:"));
2918994e 1415 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Top"));
1416 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Bottom"));
9dd114c4 1417 }
1418 }
1419}
1420
2918994e 1421/* Draw text into a label, with the user preference color and optionally bold. */
38ac664c
AG
1422void panel_draw_label_text(Panel * p, GtkWidget * label, const char * text,
1423 gboolean bold, float custom_size_factor,
1424 gboolean custom_color)
2918994e 1425{
2918994e 1426 if (text == NULL)
1427 {
1428 /* Null string. */
1429 gtk_label_set_text(GTK_LABEL(label), NULL);
83d410c1 1430 return;
2918994e 1431 }
1432
83d410c1
HG
1433 /* Compute an appropriate size so the font will scale with the panel's icon size. */
1434 int font_desc;
1435 if (p->usefontsize)
1436 font_desc = p->fontsize;
f669ce5e 1437 else
2918994e 1438 {
761e0dae
AG
1439 GtkStyle *style = gtk_widget_get_style(label);
1440 font_desc = pango_font_description_get_size(style->font_desc) / PANGO_SCALE;
83d410c1
HG
1441 }
1442 font_desc *= custom_size_factor;
1443
1444 /* Check the string for characters that need to be escaped.
1445 * If any are found, create the properly escaped string and use it instead. */
38ac664c 1446 const char * valid_markup = text;
83d410c1 1447 char * escaped_text = NULL;
38ac664c 1448 const char * q;
83d410c1
HG
1449 for (q = text; *q != '\0'; q += 1)
1450 {
1451 if ((*q == '<') || (*q == '>') || (*q == '&'))
2918994e 1452 {
83d410c1
HG
1453 escaped_text = g_markup_escape_text(text, -1);
1454 valid_markup = escaped_text;
1455 break;
2918994e 1456 }
83d410c1 1457 }
2918994e 1458
83d410c1
HG
1459 gchar * formatted_text;
1460 if ((custom_color) && (p->usefontcolor))
1461 {
1462 /* Color, optionally bold. */
1463 formatted_text = g_strdup_printf("<span font_desc=\"%d\" color=\"#%06x\">%s%s%s</span>",
f669ce5e 1464 font_desc,
2918994e 1465 gcolor2rgb24(&p->gfontcolor),
1466 ((bold) ? "<b>" : ""),
1467 valid_markup,
1468 ((bold) ? "</b>" : ""));
83d410c1
HG
1469 }
1470 else
1471 {
1472 /* No color, optionally bold. */
1473 formatted_text = g_strdup_printf("<span font_desc=\"%d\">%s%s%s</span>",
f669ce5e 1474 font_desc,
1475 ((bold) ? "<b>" : ""),
1476 valid_markup,
1477 ((bold) ? "</b>" : ""));
2918994e 1478 }
83d410c1
HG
1479
1480 gtk_label_set_markup(GTK_LABEL(label), formatted_text);
1481 g_free(formatted_text);
1482 g_free(escaped_text);
2918994e 1483}
1484
a7bd16a4
AG
1485void lxpanel_draw_label_text(LXPanel * p, GtkWidget * label, const char * text,
1486 gboolean bold, float custom_size_factor,
1487 gboolean custom_color)
1488{
1489 panel_draw_label_text(p->priv, label, text, bold, custom_size_factor, custom_color);
1490}
1491
2918994e 1492void panel_set_panel_configuration_changed(Panel *p)
a97d06a6 1493{
a7bd16a4
AG
1494 _panel_set_panel_configuration_changed(p->topgwin);
1495}
1496
1497void _panel_set_panel_configuration_changed(LXPanel *panel)
1498{
1499 Panel *p = panel->priv;
17fab6e5 1500 GList *plugins, *l;
9dd114c4 1501
cfde283a 1502 GtkOrientation previous_orientation = p->orientation;
a97d06a6 1503 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
cfde283a 1504 ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
9dd114c4 1505
cfde283a 1506 /* either first run or orientation was changed */
5eaabb1b 1507 if (!p->initialized || previous_orientation != p->orientation)
9dd114c4 1508 {
1509 panel_adjust_geometry_terminology(p);
5eaabb1b 1510 if (p->initialized)
f5c7784a 1511 p->height = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? PANEL_HEIGHT_DEFAULT : PANEL_WIDTH_DEFAULT);
9dd114c4 1512 if (p->height_control != NULL)
1513 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->height_control), p->height);
2918994e 1514 if ((p->widthtype == WIDTH_PIXEL) && (p->width_control != NULL))
1515 {
cfde283a 1516 int value = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? gdk_screen_width() : gdk_screen_height());
2918994e 1517 gtk_spin_button_set_range(GTK_SPIN_BUTTON(p->width_control), 0, value);
1518 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->width_control), value);
1519 }
9dd114c4 1520 }
1521
5eaabb1b 1522 /* FIXME: it's deprecated, kept for binary compatibility */
cfde283a 1523 if (p->orientation == GTK_ORIENTATION_HORIZONTAL) {
a97d06a6
HJYP
1524 p->my_box_new = gtk_hbox_new;
1525 p->my_separator_new = gtk_vseparator_new;
1526 } else {
1527 p->my_box_new = gtk_vbox_new;
1528 p->my_separator_new = gtk_hseparator_new;
1529 }
1530
1531 /* recreate the main layout box */
964b8b7e 1532 if (p->box != NULL)
1533 {
cfde283a 1534 gtk_orientable_set_orientation(GTK_ORIENTABLE(p->box), p->orientation);
a97d06a6 1535 }
9dd114c4 1536
a97d06a6
HJYP
1537 /* NOTE: This loop won't be executed when panel started since
1538 plugins are not loaded at that time.
1539 This is used when the orientation of the panel is changed
1540 from the config dialog, and plugins should be re-layout.
1541 */
17fab6e5
AG
1542 plugins = p->box ? gtk_container_get_children(GTK_CONTAINER(p->box)) : NULL;
1543 for( l = plugins; l; l = l->next ) {
1544 GtkWidget *w = (GtkWidget*)l->data;
191694fb 1545 const LXPanelPluginInit *init = PLUGIN_CLASS(w);
17fab6e5 1546 if (init->reconfigure)
a7bd16a4 1547 init->reconfigure(panel, w);
a97d06a6 1548 }
17fab6e5 1549 g_list_free(plugins);
3154b4ef 1550 /* panel geometry changed? update panel background then */
50928868 1551 _panel_queue_update_background(panel);
a97d06a6
HJYP
1552}
1553
a52c2257 1554static int
17fab6e5 1555panel_parse_global(Panel *p, config_setting_t *cfg)
a52c2257 1556{
4bca3e51
AG
1557 const char *str;
1558 gint i;
6db11841 1559
17fab6e5
AG
1560 /* check Global config */
1561 if (!cfg || strcmp(config_setting_get_name(cfg), "Global") != 0)
3e7b8eb7 1562 {
06e29ce1 1563 g_warning( "lxpanel: Global section not found");
17fab6e5
AG
1564 RET(0);
1565 }
4bca3e51
AG
1566 if (config_setting_lookup_string(cfg, "edge", &str))
1567 p->edge = str2num(edge_pair, str, EDGE_NONE);
1568 if (config_setting_lookup_string(cfg, "allign", &str))
1569 p->allign = str2num(allign_pair, str, ALLIGN_NONE);
1570 config_setting_lookup_int(cfg, "monitor", &p->monitor);
1571 config_setting_lookup_int(cfg, "margin", &p->margin);
1572 if (config_setting_lookup_string(cfg, "widthtype", &str))
1573 p->widthtype = str2num(width_pair, str, WIDTH_NONE);
1574 config_setting_lookup_int(cfg, "width", &p->width);
1575 if (config_setting_lookup_string(cfg, "heighttype", &str))
1576 p->heighttype = str2num(height_pair, str, HEIGHT_NONE);
1577 config_setting_lookup_int(cfg, "height", &p->height);
1578 if (config_setting_lookup_int(cfg, "spacing", &i) && i > 0)
1579 p->spacing = i;
1580 if (config_setting_lookup_int(cfg, "setdocktype", &i))
1581 p->setdocktype = i != 0;
1582 if (config_setting_lookup_int(cfg, "setpartialstrut", &i))
1583 p->setstrut = i != 0;
1584 if (config_setting_lookup_int(cfg, "RoundCorners", &i))
1585 p->round_corners = i != 0;
1586 if (config_setting_lookup_int(cfg, "transparent", &i))
1587 p->transparent = i != 0;
1588 if (config_setting_lookup_int(cfg, "alpha", &p->alpha))
17fab6e5 1589 {
17fab6e5
AG
1590 if (p->alpha > 255)
1591 p->alpha = 255;
1592 }
4bca3e51
AG
1593 if (config_setting_lookup_int(cfg, "autohide", &i))
1594 p->autohide = i != 0;
9a2c13d0
AG
1595 if (config_setting_lookup_int(cfg, "heightwhenhidden", &i))
1596 p->height_when_hidden = MAX(0, i);
4bca3e51 1597 if (config_setting_lookup_string(cfg, "tintcolor", &str))
17fab6e5 1598 {
4bca3e51 1599 if (!gdk_color_parse (str, &p->gtintcolor))
17fab6e5
AG
1600 gdk_color_parse ("white", &p->gtintcolor);
1601 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
1602 DBG("tintcolor=%x\n", p->tintcolor);
1603 }
4bca3e51
AG
1604 if (config_setting_lookup_int(cfg, "usefontcolor", &i))
1605 p->usefontcolor = i != 0;
1606 if (config_setting_lookup_string(cfg, "fontcolor", &str))
17fab6e5 1607 {
4bca3e51 1608 if (!gdk_color_parse (str, &p->gfontcolor))
17fab6e5
AG
1609 gdk_color_parse ("black", &p->gfontcolor);
1610 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
1611 DBG("fontcolor=%x\n", p->fontcolor);
1612 }
4bca3e51
AG
1613 if (config_setting_lookup_int(cfg, "usefontsize", &i))
1614 p->usefontsize = i != 0;
1615 if (config_setting_lookup_int(cfg, "fontsize", &i) && i > 0)
1616 p->fontsize = i;
1617 if (config_setting_lookup_int(cfg, "background", &i))
1618 p->background = i != 0;
1619 if (config_setting_lookup_string(cfg, "backgroundfile", &str))
1620 p->background_file = g_strdup(str);
1621 config_setting_lookup_int(cfg, "iconsize", &p->icon_size);
4542c20d 1622
9dd114c4 1623 panel_normalize_configuration(p);
239cb032 1624
9dd114c4 1625 return 1;
a52c2257
HJYP
1626}
1627
51abba48 1628static void on_monitors_changed(GdkScreen* screen, gpointer unused)
a52c2257 1629{
51abba48
AG
1630 GSList *pl;
1631 int monitors = gdk_screen_get_n_monitors(screen);
db449f6e 1632
51abba48
AG
1633 for (pl = all_panels; pl; pl = pl->next)
1634 {
1635 LXPanel *p = pl->data;
db449f6e 1636
51abba48
AG
1637 /* handle connecting and disconnecting monitors now */
1638 if (p->priv->monitor < monitors && !p->priv->initialized)
1639 panel_start_gui(p, config_setting_get_member(config_root_setting(p->priv->config), ""));
1640 else if (p->priv->monitor >= monitors && p->priv->initialized)
1641 panel_stop_gui(p);
1d7155da
AG
1642 /* resize panel if appropriate monitor changed its size or position */
1643 else
12ddb4f8
AG
1644 {
1645 /* SF bug #666: after screen resize panel cannot establish
1646 right size since cannot be moved while is hidden */
1647 ah_state_set(p, AH_STATE_VISIBLE);
1d7155da 1648 gtk_widget_queue_resize(GTK_WIDGET(p));
12ddb4f8 1649 }
a52c2257 1650 }
a52c2257
HJYP
1651}
1652
51abba48 1653static int panel_start(LXPanel *p)
a52c2257 1654{
51abba48
AG
1655 config_setting_t *list;
1656 GdkScreen *screen = gdk_screen_get_default();
db449f6e 1657
a52c2257
HJYP
1658 /* parse global section */
1659 ENTER;
8110399f 1660
a7bd16a4
AG
1661 list = config_setting_get_member(config_root_setting(p->priv->config), "");
1662 if (!list || !panel_parse_global(p->priv, config_setting_get_elem(list, 0)))
a52c2257
HJYP
1663 RET(0);
1664
51abba48
AG
1665 if (p->priv->monitor < gdk_screen_get_n_monitors(screen))
1666 panel_start_gui(p, list);
1667 if (monitors_handler == 0)
1668 monitors_handler = g_signal_connect(screen, "monitors-changed",
1669 G_CALLBACK(on_monitors_changed), NULL);
9dd114c4 1670 return 1;
a52c2257
HJYP
1671}
1672
8110399f 1673void panel_destroy(Panel *p)
a52c2257 1674{
a7bd16a4 1675 gtk_widget_destroy(GTK_WIDGET(p->topgwin));
a52c2257
HJYP
1676}
1677
46c7d227 1678LXPanel* panel_new( const char* config_file, const char* config_name )
8110399f 1679{
a7bd16a4 1680 LXPanel* panel = NULL;
16fbda14 1681
17fab6e5 1682 if (G_LIKELY(config_file))
cf701cb7 1683 {
17fab6e5 1684 panel = panel_allocate();
a7bd16a4 1685 panel->priv->name = g_strdup(config_name);
17fab6e5 1686 g_debug("starting panel from file %s",config_file);
a7bd16a4 1687 if (!config_read_file(panel->priv->config, config_file) ||
17fab6e5 1688 !panel_start(panel))
3e7b8eb7 1689 {
06e29ce1 1690 g_warning( "lxpanel: can't start panel");
a7bd16a4 1691 gtk_widget_destroy(GTK_WIDGET(panel));
17fab6e5 1692 panel = NULL;
cf701cb7 1693 }
cf701cb7
HJYP
1694 }
1695 return panel;
8110399f 1696}
a52c2257 1697
9c338caf 1698
a7bd16a4 1699GtkOrientation panel_get_orientation(LXPanel *panel)
9c338caf 1700{
a7bd16a4 1701 return panel->priv->orientation;
9c338caf
AG
1702}
1703
a7bd16a4 1704gint panel_get_icon_size(LXPanel *panel)
9c338caf 1705{
a7bd16a4 1706 return panel->priv->icon_size;
9c338caf
AG
1707}
1708
a7bd16a4 1709gint panel_get_height(LXPanel *panel)
9c338caf 1710{
a7bd16a4 1711 return panel->priv->height;
9c338caf
AG
1712}
1713
a7bd16a4 1714Window panel_get_xwindow(LXPanel *panel)
4718ca02 1715{
a7bd16a4 1716 return panel->priv->topxwin;
4718ca02
AG
1717}
1718
a7bd16a4 1719gint panel_get_monitor(LXPanel *panel)
4718ca02 1720{
a7bd16a4 1721 return panel->priv->monitor;
4718ca02
AG
1722}
1723
a7bd16a4 1724GtkStyle *panel_get_defstyle(LXPanel *panel)
9c338caf 1725{
a7bd16a4 1726 return panel->priv->defstyle;
9c338caf
AG
1727}
1728
a7bd16a4 1729GtkIconTheme *panel_get_icon_theme(LXPanel *panel)
9c338caf 1730{
a7bd16a4 1731 return panel->priv->icon_theme;
9c338caf
AG
1732}
1733
a7bd16a4 1734gboolean panel_is_at_bottom(LXPanel *panel)
4718ca02 1735{
a7bd16a4 1736 return panel->priv->edge == EDGE_BOTTOM;
4718ca02
AG
1737}
1738
072944bf
AG
1739gboolean panel_is_dynamic(LXPanel *panel)
1740{
1741 return panel->priv->widthtype == WIDTH_REQUEST;
1742}
1743
a7bd16a4 1744GtkWidget *panel_box_new(LXPanel *panel, gboolean homogeneous, gint spacing)
9c338caf 1745{
a7bd16a4 1746 if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
5eaabb1b
AG
1747 return gtk_hbox_new(homogeneous, spacing);
1748 return gtk_vbox_new(homogeneous, spacing);
9c338caf
AG
1749}
1750
a7bd16a4 1751GtkWidget *panel_separator_new(LXPanel *panel)
9c338caf 1752{
a7bd16a4 1753 if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
5eaabb1b
AG
1754 return gtk_vseparator_new();
1755 return gtk_hseparator_new();
9c338caf 1756}
10d93053 1757
191694fb 1758gboolean _class_is_present(const LXPanelPluginInit *init)
10d93053
AG
1759{
1760 GSList *sl;
1761
1762 for (sl = all_panels; sl; sl = sl->next )
1763 {
a7bd16a4 1764 LXPanel *panel = (LXPanel*)sl->data;
10d93053
AG
1765 GList *plugins, *p;
1766
51abba48
AG
1767 if (panel->priv->box == NULL)
1768 continue;
a7bd16a4 1769 plugins = gtk_container_get_children(GTK_CONTAINER(panel->priv->box));
10d93053
AG
1770 for (p = plugins; p; p = p->next)
1771 if (PLUGIN_CLASS(p->data) == init)
1772 {
1773 g_list_free(plugins);
1774 return TRUE;
1775 }
1776 g_list_free(plugins);
1777 }
1778 return FALSE;
1779}