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