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