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