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