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