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