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