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