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