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