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