Commit from LXDE Pootle server by user armakolas.: 1248 of 1248 strings translated...
[lxde/lxpanel.git] / src / panel.c
CommitLineData
50928868 1/*
b840f7cc 2 * Copyright (c) 2006-2014 LxDE Developers, see the file AUTHORS for details.
e68b47dc
JH
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
a52c2257 19#ifdef HAVE_CONFIG_H
cf701cb7 20#include <config.h>
a52c2257
HJYP
21#endif
22
cf701cb7 23#include <glib/gi18n.h>
a52c2257 24#include <stdlib.h>
16fbda14 25#include <glib/gstdio.h>
a52c2257
HJYP
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <unistd.h>
29#include <errno.h>
30#include <locale.h>
31#include <string.h>
e68b47dc 32#include <gdk/gdkx.h>
4f5769fc 33#include <libfm/fm-gtk.h>
a52c2257 34
1f4bc3aa
AG
35#define __LXPANEL_INTERNALS__
36
b31cb1d2 37#include "private.h"
a52c2257
HJYP
38#include "misc.h"
39#include "bg.h"
a52c2257 40
77886b88 41#include "lxpanelctl.h"
cf701cb7 42#include "dbg.h"
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
R
330 if (p->monitor < 0)
331 p->monitor = 0;
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. */
64afc832
R
800 screen = gdk_screen_get_default();
801 g_assert(screen);
802 monitors = gdk_screen_get_n_monitors(screen);
803 for(m=0; m<monitors; ++m)
804 {
805 /* try each of the four edges */
806 for(e=1; e<5; ++e)
807 {
a7bd16a4
AG
808 if(panel_edge_available(p,e,m)) {
809 p->edge = e;
810 p->monitor = m;
64afc832
R
811 goto found_edge;
812 }
813 }
814 }
815
a7bd16a4 816 gtk_widget_destroy(GTK_WIDGET(new_panel));
06e29ce1 817 g_warning("Error adding panel: There is no room for another panel. All the edges are taken.");
bb4cf963 818 fm_show_error(NULL, NULL, _("There is no room for another panel. All the edges are taken."));
64afc832
R
819 return;
820
821found_edge:
a7bd16a4 822 p->name = gen_panel_name(p->edge, p->monitor);
9dd114c4 823
17fab6e5 824 /* create new config with first group "Global" */
59c0082e
AG
825 global = config_group_add_subgroup(config_root_setting(p->config), "Global");
826 config_group_set_string(global, "edge", num2str(edge_pair, p->edge, "none"));
827 config_group_set_int(global, "monitor", p->monitor);
9dd114c4 828 panel_configure(new_panel, 0);
a7bd16a4 829 panel_normalize_configuration(p);
9dd114c4 830 panel_start_gui(new_panel);
a7bd16a4 831 gtk_widget_show_all(GTK_WIDGET(new_panel));
9dd114c4 832
a7bd16a4 833 lxpanel_config_save(new_panel);
9dd114c4 834 all_panels = g_slist_prepend(all_panels, new_panel);
cf701cb7
HJYP
835}
836
a7bd16a4 837static void panel_popupmenu_delete_panel( GtkMenuItem* item, LXPanel* panel )
cf701cb7
HJYP
838{
839 GtkWidget* dlg;
840 gboolean ok;
a7bd16a4 841 dlg = gtk_message_dialog_new_with_markup( GTK_WINDOW(panel),
cf701cb7
HJYP
842 GTK_DIALOG_MODAL,
843 GTK_MESSAGE_QUESTION,
844 GTK_BUTTONS_OK_CANCEL,
845 _("Really delete this panel?\n<b>Warning: This can not be recovered.</b>") );
d1d43629 846 panel_apply_icon(GTK_WINDOW(dlg));
cf701cb7
HJYP
847 gtk_window_set_title( (GtkWindow*)dlg, _("Confirm") );
848 ok = ( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK );
849 gtk_widget_destroy( dlg );
850 if( ok )
851 {
1f4bc3aa 852 gchar *fname;
cf701cb7 853 all_panels = g_slist_remove( all_panels, panel );
4b93d81e
HJYP
854
855 /* delete the config file of this panel */
a7bd16a4 856 fname = _user_config_file_name("panels", panel->priv->name);
4b93d81e 857 g_unlink( fname );
1f4bc3aa 858 g_free(fname);
a7bd16a4
AG
859 panel->priv->config_changed = 0;
860 gtk_widget_destroy(GTK_WIDGET(panel));
cf701cb7
HJYP
861 }
862}
863
e7a42ecf 864static void panel_popupmenu_about( GtkMenuItem* item, Panel* panel )
865{
866 GtkWidget *about;
867 const gchar* authors[] = {
868 "Hong Jen Yee (PCMan) <pcman.tw@gmail.com>",
869 "Jim Huang <jserv.tw@gmail.com>",
870 "Greg McNew <gmcnew@gmail.com> (battery plugin)",
871 "Fred Chien <cfsghost@gmail.com>",
872 "Daniel Kesler <kesler.daniel@gmail.com>",
873 "Juergen Hoetzel <juergen@archlinux.org>",
2918994e 874 "Marty Jack <martyj19@comcast.net>",
815e1027 875 "Martin Bagge <brother@bsnet.se>",
bb4cf963
AG
876 "Andriy Grytsenko <andrej@rep.kiev.ua>",
877 "Giuseppe Penone <giuspen@gmail.com>",
878 "Piotr Sipika <piotr.sipika@gmail.com>",
e7a42ecf 879 NULL
880 };
881 /* TRANSLATORS: Replace this string with your names, one name per line. */
882 gchar *translators = _( "translator-credits" );
883
884 about = gtk_about_dialog_new();
885 panel_apply_icon(GTK_WINDOW(about));
886 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), VERSION);
09fa171b 887 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about), _("LXPanel"));
4c91be3e
JL
888
889 if(gtk_icon_theme_has_icon(panel->icon_theme, "video-display"))
890 {
891 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
892 gtk_icon_theme_load_icon(panel->icon_theme, "video-display", 48, 0, NULL));
893 }
894 else if (gtk_icon_theme_has_icon(panel->icon_theme, "start-here"))
895 {
896 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
897 gtk_icon_theme_load_icon(panel->icon_theme, "start-here", 48, 0, NULL));
898 }
0bcf9045 899 else
4c91be3e
JL
900 {
901 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
0b806437 902 gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL));
4c91be3e
JL
903 }
904
b840f7cc 905 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about), _("Copyright (C) 2008-2014"));
e7a42ecf 906 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), _( "Desktop panel for LXDE project"));
907 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.");
908 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://lxde.org/");
909 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about), authors);
910 gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about), translators);
911 gtk_dialog_run(GTK_DIALOG(about));
0bcf9045 912 gtk_widget_destroy(about);
e7a42ecf 913}
914
915void panel_apply_icon( GtkWindow *w )
916{
0bcf9045
AG
917 GdkPixbuf* window_icon;
918
919 if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "video-display"))
4c91be3e 920 {
0bcf9045
AG
921 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "video-display", 24, 0, NULL);
922 }
923 else if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "start-here"))
4c91be3e 924 {
0bcf9045
AG
925 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "start-here", 24, 0, NULL);
926 }
89496346 927 else
4c91be3e 928 {
0bcf9045
AG
929 window_icon = gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL);
930 }
21f91705 931 gtk_window_set_icon(w, window_icon);
e7a42ecf 932}
933
a7bd16a4 934GtkMenu* lxpanel_get_plugin_menu( LXPanel* panel, GtkWidget* plugin, gboolean use_sub_menu )
cf701cb7 935{
e3b89f43 936 GtkWidget *menu_item, *img;
937 GtkMenu *ret,*menu;
191694fb 938 const LXPanelPluginInit *init;
cf701cb7 939 char* tmp;
eb1762e5 940
e3b89f43 941 ret = menu = GTK_MENU(gtk_menu_new());
cf701cb7 942
eb1762e5
AG
943 if (plugin)
944 {
945 init = PLUGIN_CLASS(plugin);
946 /* create single item - plugin instance settings */
947 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
948 tmp = g_strdup_printf( _("\"%s\" Settings"), _(init->name) );
949 menu_item = gtk_image_menu_item_new_with_label( tmp );
950 g_free( tmp );
951 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
952 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
953 if( init->config )
954 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
955 else
956 gtk_widget_set_sensitive( menu_item, FALSE );
957 /* add custom items by plugin if requested */
958 if (init->update_context_menu != NULL)
959 use_sub_menu = init->update_context_menu(plugin, ret);
960 /* append a separator */
961 menu_item = gtk_separator_menu_item_new();
962 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
963 }
964 if (use_sub_menu)
965 menu = GTK_MENU(gtk_menu_new());
966
4b93d81e
HJYP
967 img = gtk_image_new_from_stock( GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU );
968 menu_item = gtk_image_menu_item_new_with_label(_("Add / Remove Panel Items"));
969 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
970 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
971 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
cf701cb7
HJYP
972
973 if( plugin )
974 {
975 img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
17fab6e5 976 tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(init->name) );
cf701cb7
HJYP
977 menu_item = gtk_image_menu_item_new_with_label( tmp );
978 g_free( tmp );
979 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
980 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
981 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_remove_item), plugin );
982 }
983
984 menu_item = gtk_separator_menu_item_new();
985 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
986
4b93d81e
HJYP
987 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
988 menu_item = gtk_image_menu_item_new_with_label(_("Panel Settings"));
989 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
990 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
991 g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_popupmenu_configure), panel );
992
cf701cb7
HJYP
993 img = gtk_image_new_from_stock( GTK_STOCK_NEW, GTK_ICON_SIZE_MENU );
994 menu_item = gtk_image_menu_item_new_with_label(_("Create New Panel"));
995 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
996 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
997 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_create_panel), panel );
998
999 img = gtk_image_new_from_stock( GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU );
1000 menu_item = gtk_image_menu_item_new_with_label(_("Delete This Panel"));
1001 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1002 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1003 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_delete_panel), panel );
1004 if( ! all_panels->next ) /* if this is the only panel */
1005 gtk_widget_set_sensitive( menu_item, FALSE );
1006
e7a42ecf 1007 menu_item = gtk_separator_menu_item_new();
1008 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1009
1010 img = gtk_image_new_from_stock( GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU );
1011 menu_item = gtk_image_menu_item_new_with_label(_("About"));
1012 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1013 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
a7bd16a4 1014 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_about), panel->priv );
e7a42ecf 1015
cf701cb7
HJYP
1016 if( use_sub_menu )
1017 {
cf701cb7
HJYP
1018 menu_item = gtk_image_menu_item_new_with_label(_("Panel"));
1019 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
e3b89f43 1020 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), GTK_WIDGET(menu) );
3e7b8eb7
HJYP
1021 }
1022
eb1762e5 1023 gtk_widget_show_all(GTK_WIDGET(ret));
3e7b8eb7 1024
cf701cb7
HJYP
1025 g_signal_connect( ret, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
1026 return ret;
1027}
1028
17fab6e5
AG
1029/* for old plugins compatibility */
1030GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
1031{
a7bd16a4 1032 return lxpanel_get_plugin_menu(panel->topgwin, plugin->pwid, use_sub_menu);
17fab6e5
AG
1033}
1034
a52c2257
HJYP
1035/****************************************************
1036 * panel creation *
1037 ****************************************************/
176fb687 1038
a52c2257 1039static void
22242ed4 1040make_round_corners(Panel *p)
a52c2257 1041{
a97d06a6 1042 /* FIXME: This should be re-written with shape extension of X11 */
4542c20d 1043 /* gdk_window_shape_combine_mask() can be used */
bee4c26e
HJYP
1044}
1045
22242ed4 1046void panel_set_dock_type(Panel *p)
bee4c26e 1047{
09fa171b
AG
1048 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1049
bee4c26e
HJYP
1050 if (p->setdocktype) {
1051 Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
09fa171b 1052 XChangeProperty(xdisplay, p->topxwin,
bee4c26e
HJYP
1053 a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
1054 PropModeReplace, (unsigned char *) &state, 1);
1055 }
1056 else {
09fa171b 1057 XDeleteProperty( xdisplay, p->topxwin, a_NET_WM_WINDOW_TYPE );
bee4c26e 1058 }
a52c2257
HJYP
1059}
1060
176fb687 1061void panel_establish_autohide(Panel *p)
1062{
a7bd16a4
AG
1063 _panel_establish_autohide(p->topgwin);
1064}
1065
1066void _panel_establish_autohide(LXPanel *p)
1067{
1068 if (p->priv->autohide)
9a2c13d0
AG
1069 ah_start(p);
1070 else
176fb687 1071 {
9a2c13d0
AG
1072 ah_stop(p);
1073 ah_state_set(p, AH_STATE_VISIBLE);
176fb687 1074 }
1075}
1076
8f9e6256 1077/* Set an image from a file with scaling to the panel icon size. */
fcb35553 1078void panel_image_set_from_file(Panel * p, GtkWidget * image, const char * file)
8f9e6256 1079{
1080 GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file_at_scale(file, p->icon_size, p->icon_size, TRUE, NULL);
1081 if (pixbuf != NULL)
1082 {
1083 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
1084 g_object_unref(pixbuf);
1085 }
1086}
1087
a7bd16a4
AG
1088void lxpanel_image_set_from_file(LXPanel * p, GtkWidget * image, const char * file)
1089{
1090 panel_image_set_from_file(p->priv, image, file);
1091}
1092
c14620f2
MJ
1093/* Set an image from a icon theme with scaling to the panel icon size. */
1094gboolean panel_image_set_icon_theme(Panel * p, GtkWidget * image, const gchar * icon)
1095{
1b532bce 1096 if (gtk_icon_theme_has_icon(p->icon_theme, icon))
c14620f2 1097 {
1b532bce 1098 GdkPixbuf * pixbuf = gtk_icon_theme_load_icon(p->icon_theme, icon, p->icon_size, 0, NULL);
c14620f2
MJ
1099 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
1100 g_object_unref(pixbuf);
1101 return TRUE;
1102 }
1103 return FALSE;
1104}
1105
a7bd16a4
AG
1106gboolean lxpanel_image_set_icon_theme(LXPanel * p, GtkWidget * image, const gchar * icon)
1107{
1108 return panel_image_set_icon_theme(p->priv, image, icon);
1109}
1110
0defe4b9 1111static void
a7bd16a4 1112panel_start_gui(LXPanel *panel)
a52c2257
HJYP
1113{
1114 Atom state[3];
1115 XWMHints wmhints;
0bfcc6c9 1116 gulong val;
09fa171b 1117 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
a7bd16a4
AG
1118 Panel *p = panel->priv;
1119 GtkWidget *w = GTK_WIDGET(panel);
6db11841 1120
a52c2257
HJYP
1121 ENTER;
1122
9dd114c4 1123 p->curdesk = get_net_current_desktop();
1124 p->desknum = get_net_number_of_desktops();
1125 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
1126
cb22c87c
HJYP
1127 /* main toplevel window */
1128 /* p->topgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); */
a7bd16a4 1129 gtk_widget_set_name(w, "PanelToplevel");
176fb687 1130 p->display = gdk_display_get_default();
a7bd16a4
AG
1131 gtk_container_set_border_width(GTK_CONTAINER(panel), 0);
1132 gtk_window_set_resizable(GTK_WINDOW(panel), FALSE);
1133 gtk_window_set_wmclass(GTK_WINDOW(panel), "panel", "lxpanel");
1134 gtk_window_set_title(GTK_WINDOW(panel), "panel");
1135 gtk_window_set_position(GTK_WINDOW(panel), GTK_WIN_POS_NONE);
1136 gtk_window_set_decorated(GTK_WINDOW(panel), FALSE);
77886b88 1137
a7bd16a4 1138 gtk_window_group_add_window( win_grp, (GtkWindow*)panel );
e2957bd2 1139
a7bd16a4 1140 gtk_widget_add_events( w, GDK_BUTTON_PRESS_MASK );
f2d54481 1141
a7bd16a4 1142 gtk_widget_realize(w);
175f73d1 1143 //gdk_window_set_decorations(gtk_widget_get_window(p->topgwin), 0);
2de71c90 1144
4542c20d 1145 // main layout manager as a single child of panel
a7bd16a4 1146 p->box = panel_box_new(panel, FALSE, 0);
a52c2257 1147 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
a7bd16a4 1148 gtk_container_add(GTK_CONTAINER(panel), p->box);
a52c2257 1149 gtk_widget_show(p->box);
a97d06a6
HJYP
1150 if (p->round_corners)
1151 make_round_corners(p);
6db11841 1152
a7bd16a4 1153 p->topxwin = GDK_WINDOW_XWINDOW(gtk_widget_get_window(w));
a52c2257
HJYP
1154 DBG("topxwin = %x\n", p->topxwin);
1155
1156 /* the settings that should be done before window is mapped */
1157 wmhints.flags = InputHint;
1158 wmhints.input = 0;
09fa171b 1159 XSetWMHints (xdisplay, p->topxwin, &wmhints);
24053345 1160#define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
a52c2257 1161 val = WIN_HINTS_SKIP_FOCUS;
09fa171b
AG
1162 XChangeProperty(xdisplay, p->topxwin,
1163 XInternAtom(xdisplay, "_WIN_HINTS", False), XA_CARDINAL, 32,
a52c2257
HJYP
1164 PropModeReplace, (unsigned char *) &val, 1);
1165
bee4c26e 1166 panel_set_dock_type(p);
a52c2257
HJYP
1167
1168 /* window mapping point */
a7bd16a4 1169 gtk_widget_show_all(w);
a52c2257
HJYP
1170
1171 /* the settings that should be done after window is mapped */
a7bd16a4 1172 _panel_establish_autohide(panel);
a52c2257
HJYP
1173
1174 /* send it to running wm */
0bfcc6c9 1175 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, G_MAXULONG, 0, 0, 0, 0);
a52c2257 1176 /* and assign it ourself just for case when wm is not running */
0bfcc6c9 1177 val = G_MAXULONG;
09fa171b 1178 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
a52c2257
HJYP
1179 PropModeReplace, (unsigned char *) &val, 1);
1180
1181 state[0] = a_NET_WM_STATE_SKIP_PAGER;
1182 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
1183 state[2] = a_NET_WM_STATE_STICKY;
09fa171b 1184 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STATE, XA_ATOM,
a52c2257
HJYP
1185 32, PropModeReplace, (unsigned char *) state, 3);
1186
a7bd16a4
AG
1187 _calculate_position(panel);
1188 gdk_window_move_resize(gtk_widget_get_window(w), p->ax, p->ay, p->aw, p->ah);
1189 _panel_set_wm_strut(panel);
5eaabb1b 1190 p->initialized = TRUE;
77886b88 1191
a52c2257
HJYP
1192 RET();
1193}
1194
2918994e 1195/* Exchange the "width" and "height" terminology for vertical and horizontal panels. */
1196void panel_adjust_geometry_terminology(Panel * p)
9dd114c4 1197{
8ed3b3d4 1198 if ((p->height_label != NULL) && (p->width_label != NULL)
1199 && (p->alignment_left_label != NULL) && (p->alignment_right_label != NULL))
9dd114c4 1200 {
1201 if ((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM))
1202 {
1203 gtk_label_set_text(GTK_LABEL(p->height_label), _("Height:"));
1204 gtk_label_set_text(GTK_LABEL(p->width_label), _("Width:"));
2918994e 1205 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Left"));
1206 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Right"));
9dd114c4 1207 }
1208 else
1209 {
1210 gtk_label_set_text(GTK_LABEL(p->height_label), _("Width:"));
1211 gtk_label_set_text(GTK_LABEL(p->width_label), _("Height:"));
2918994e 1212 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Top"));
1213 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Bottom"));
9dd114c4 1214 }
1215 }
1216}
1217
2918994e 1218/* Draw text into a label, with the user preference color and optionally bold. */
38ac664c
AG
1219void panel_draw_label_text(Panel * p, GtkWidget * label, const char * text,
1220 gboolean bold, float custom_size_factor,
1221 gboolean custom_color)
2918994e 1222{
2918994e 1223 if (text == NULL)
1224 {
1225 /* Null string. */
1226 gtk_label_set_text(GTK_LABEL(label), NULL);
83d410c1 1227 return;
2918994e 1228 }
1229
83d410c1
HG
1230 /* Compute an appropriate size so the font will scale with the panel's icon size. */
1231 int font_desc;
1232 if (p->usefontsize)
1233 font_desc = p->fontsize;
f669ce5e 1234 else
2918994e 1235 {
761e0dae
AG
1236 GtkStyle *style = gtk_widget_get_style(label);
1237 font_desc = pango_font_description_get_size(style->font_desc) / PANGO_SCALE;
83d410c1
HG
1238 }
1239 font_desc *= custom_size_factor;
1240
1241 /* Check the string for characters that need to be escaped.
1242 * If any are found, create the properly escaped string and use it instead. */
38ac664c 1243 const char * valid_markup = text;
83d410c1 1244 char * escaped_text = NULL;
38ac664c 1245 const char * q;
83d410c1
HG
1246 for (q = text; *q != '\0'; q += 1)
1247 {
1248 if ((*q == '<') || (*q == '>') || (*q == '&'))
2918994e 1249 {
83d410c1
HG
1250 escaped_text = g_markup_escape_text(text, -1);
1251 valid_markup = escaped_text;
1252 break;
2918994e 1253 }
83d410c1 1254 }
2918994e 1255
83d410c1
HG
1256 gchar * formatted_text;
1257 if ((custom_color) && (p->usefontcolor))
1258 {
1259 /* Color, optionally bold. */
1260 formatted_text = g_strdup_printf("<span font_desc=\"%d\" color=\"#%06x\">%s%s%s</span>",
f669ce5e 1261 font_desc,
2918994e 1262 gcolor2rgb24(&p->gfontcolor),
1263 ((bold) ? "<b>" : ""),
1264 valid_markup,
1265 ((bold) ? "</b>" : ""));
83d410c1
HG
1266 }
1267 else
1268 {
1269 /* No color, optionally bold. */
1270 formatted_text = g_strdup_printf("<span font_desc=\"%d\">%s%s%s</span>",
f669ce5e 1271 font_desc,
1272 ((bold) ? "<b>" : ""),
1273 valid_markup,
1274 ((bold) ? "</b>" : ""));
2918994e 1275 }
83d410c1
HG
1276
1277 gtk_label_set_markup(GTK_LABEL(label), formatted_text);
1278 g_free(formatted_text);
1279 g_free(escaped_text);
2918994e 1280}
1281
a7bd16a4
AG
1282void lxpanel_draw_label_text(LXPanel * p, GtkWidget * label, const char * text,
1283 gboolean bold, float custom_size_factor,
1284 gboolean custom_color)
1285{
1286 panel_draw_label_text(p->priv, label, text, bold, custom_size_factor, custom_color);
1287}
1288
2918994e 1289void panel_set_panel_configuration_changed(Panel *p)
a97d06a6 1290{
a7bd16a4
AG
1291 _panel_set_panel_configuration_changed(p->topgwin);
1292}
1293
1294void _panel_set_panel_configuration_changed(LXPanel *panel)
1295{
1296 Panel *p = panel->priv;
17fab6e5 1297 GList *plugins, *l;
9dd114c4 1298
cfde283a 1299 GtkOrientation previous_orientation = p->orientation;
a97d06a6 1300 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
cfde283a 1301 ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
9dd114c4 1302
cfde283a 1303 /* either first run or orientation was changed */
5eaabb1b 1304 if (!p->initialized || previous_orientation != p->orientation)
9dd114c4 1305 {
1306 panel_adjust_geometry_terminology(p);
5eaabb1b 1307 if (p->initialized)
f5c7784a 1308 p->height = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? PANEL_HEIGHT_DEFAULT : PANEL_WIDTH_DEFAULT);
9dd114c4 1309 if (p->height_control != NULL)
1310 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->height_control), p->height);
2918994e 1311 if ((p->widthtype == WIDTH_PIXEL) && (p->width_control != NULL))
1312 {
cfde283a 1313 int value = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? gdk_screen_width() : gdk_screen_height());
2918994e 1314 gtk_spin_button_set_range(GTK_SPIN_BUTTON(p->width_control), 0, value);
1315 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->width_control), value);
1316 }
9dd114c4 1317 }
1318
5eaabb1b 1319 /* FIXME: it's deprecated, kept for binary compatibility */
cfde283a 1320 if (p->orientation == GTK_ORIENTATION_HORIZONTAL) {
a97d06a6
HJYP
1321 p->my_box_new = gtk_hbox_new;
1322 p->my_separator_new = gtk_vseparator_new;
1323 } else {
1324 p->my_box_new = gtk_vbox_new;
1325 p->my_separator_new = gtk_hseparator_new;
1326 }
1327
1328 /* recreate the main layout box */
964b8b7e 1329 if (p->box != NULL)
1330 {
cfde283a 1331 gtk_orientable_set_orientation(GTK_ORIENTABLE(p->box), p->orientation);
a97d06a6 1332 }
9dd114c4 1333
a97d06a6
HJYP
1334 /* NOTE: This loop won't be executed when panel started since
1335 plugins are not loaded at that time.
1336 This is used when the orientation of the panel is changed
1337 from the config dialog, and plugins should be re-layout.
1338 */
17fab6e5
AG
1339 plugins = p->box ? gtk_container_get_children(GTK_CONTAINER(p->box)) : NULL;
1340 for( l = plugins; l; l = l->next ) {
1341 GtkWidget *w = (GtkWidget*)l->data;
191694fb 1342 const LXPanelPluginInit *init = PLUGIN_CLASS(w);
17fab6e5 1343 if (init->reconfigure)
a7bd16a4 1344 init->reconfigure(panel, w);
a97d06a6 1345 }
17fab6e5 1346 g_list_free(plugins);
3154b4ef 1347 /* panel geometry changed? update panel background then */
50928868 1348 _panel_queue_update_background(panel);
a97d06a6
HJYP
1349}
1350
a52c2257 1351static int
17fab6e5 1352panel_parse_global(Panel *p, config_setting_t *cfg)
a52c2257 1353{
4bca3e51
AG
1354 const char *str;
1355 gint i;
6db11841 1356
17fab6e5
AG
1357 /* check Global config */
1358 if (!cfg || strcmp(config_setting_get_name(cfg), "Global") != 0)
3e7b8eb7 1359 {
06e29ce1 1360 g_warning( "lxpanel: Global section not found");
17fab6e5
AG
1361 RET(0);
1362 }
4bca3e51
AG
1363 if (config_setting_lookup_string(cfg, "edge", &str))
1364 p->edge = str2num(edge_pair, str, EDGE_NONE);
1365 if (config_setting_lookup_string(cfg, "allign", &str))
1366 p->allign = str2num(allign_pair, str, ALLIGN_NONE);
1367 config_setting_lookup_int(cfg, "monitor", &p->monitor);
1368 config_setting_lookup_int(cfg, "margin", &p->margin);
1369 if (config_setting_lookup_string(cfg, "widthtype", &str))
1370 p->widthtype = str2num(width_pair, str, WIDTH_NONE);
1371 config_setting_lookup_int(cfg, "width", &p->width);
1372 if (config_setting_lookup_string(cfg, "heighttype", &str))
1373 p->heighttype = str2num(height_pair, str, HEIGHT_NONE);
1374 config_setting_lookup_int(cfg, "height", &p->height);
1375 if (config_setting_lookup_int(cfg, "spacing", &i) && i > 0)
1376 p->spacing = i;
1377 if (config_setting_lookup_int(cfg, "setdocktype", &i))
1378 p->setdocktype = i != 0;
1379 if (config_setting_lookup_int(cfg, "setpartialstrut", &i))
1380 p->setstrut = i != 0;
1381 if (config_setting_lookup_int(cfg, "RoundCorners", &i))
1382 p->round_corners = i != 0;
1383 if (config_setting_lookup_int(cfg, "transparent", &i))
1384 p->transparent = i != 0;
1385 if (config_setting_lookup_int(cfg, "alpha", &p->alpha))
17fab6e5 1386 {
17fab6e5
AG
1387 if (p->alpha > 255)
1388 p->alpha = 255;
1389 }
4bca3e51
AG
1390 if (config_setting_lookup_int(cfg, "autohide", &i))
1391 p->autohide = i != 0;
9a2c13d0
AG
1392 if (config_setting_lookup_int(cfg, "heightwhenhidden", &i))
1393 p->height_when_hidden = MAX(0, i);
4bca3e51 1394 if (config_setting_lookup_string(cfg, "tintcolor", &str))
17fab6e5 1395 {
4bca3e51 1396 if (!gdk_color_parse (str, &p->gtintcolor))
17fab6e5
AG
1397 gdk_color_parse ("white", &p->gtintcolor);
1398 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
1399 DBG("tintcolor=%x\n", p->tintcolor);
1400 }
4bca3e51
AG
1401 if (config_setting_lookup_int(cfg, "usefontcolor", &i))
1402 p->usefontcolor = i != 0;
1403 if (config_setting_lookup_string(cfg, "fontcolor", &str))
17fab6e5 1404 {
4bca3e51 1405 if (!gdk_color_parse (str, &p->gfontcolor))
17fab6e5
AG
1406 gdk_color_parse ("black", &p->gfontcolor);
1407 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
1408 DBG("fontcolor=%x\n", p->fontcolor);
1409 }
4bca3e51
AG
1410 if (config_setting_lookup_int(cfg, "usefontsize", &i))
1411 p->usefontsize = i != 0;
1412 if (config_setting_lookup_int(cfg, "fontsize", &i) && i > 0)
1413 p->fontsize = i;
1414 if (config_setting_lookup_int(cfg, "background", &i))
1415 p->background = i != 0;
1416 if (config_setting_lookup_string(cfg, "backgroundfile", &str))
1417 p->background_file = g_strdup(str);
1418 config_setting_lookup_int(cfg, "iconsize", &p->icon_size);
4542c20d 1419
9dd114c4 1420 panel_normalize_configuration(p);
239cb032 1421
9dd114c4 1422 return 1;
a52c2257
HJYP
1423}
1424
1425static int
a7bd16a4 1426panel_parse_plugin(LXPanel *p, config_setting_t *cfg)
a52c2257 1427{
4bca3e51 1428 const char *type = NULL;
db449f6e 1429
a52c2257 1430 ENTER;
4bca3e51 1431 config_setting_lookup_string(cfg, "type", &type);
17fab6e5 1432 DBG("plug %s\n", type);
db449f6e 1433
17fab6e5 1434 if (!type || lxpanel_add_plugin(p, type, cfg, -1) == NULL) {
06e29ce1 1435 g_warning( "lxpanel: can't load %s plugin", type);
a52c2257
HJYP
1436 goto error;
1437 }
a52c2257 1438 RET(1);
db449f6e 1439
17fab6e5 1440error:
a52c2257 1441 RET(0);
a52c2257
HJYP
1442}
1443
adf42c84 1444static int panel_start( LXPanel *p )
a52c2257 1445{
17fab6e5
AG
1446 config_setting_t *list, *s;
1447 int i;
db449f6e 1448
a52c2257
HJYP
1449 /* parse global section */
1450 ENTER;
8110399f 1451
a7bd16a4
AG
1452 list = config_setting_get_member(config_root_setting(p->priv->config), "");
1453 if (!list || !panel_parse_global(p->priv, config_setting_get_elem(list, 0)))
a52c2257
HJYP
1454 RET(0);
1455
9dd114c4 1456 panel_start_gui(p);
1457
17fab6e5
AG
1458 for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
1459 if (strcmp(config_setting_get_name(s), "Plugin") == 0 &&
1460 panel_parse_plugin(p, s)) /* success on plugin start */
1461 i++;
1462 else /* remove invalid data from config */
1463 config_setting_remove_elem(list, i);
4542c20d
HJYP
1464
1465 /* update backgrond of panel and all plugins */
a7bd16a4 1466 _panel_update_background(p);
9dd114c4 1467 return 1;
a52c2257
HJYP
1468}
1469
8110399f 1470void panel_destroy(Panel *p)
a52c2257 1471{
a7bd16a4 1472 gtk_widget_destroy(GTK_WIDGET(p->topgwin));
a52c2257
HJYP
1473}
1474
46c7d227 1475LXPanel* panel_new( const char* config_file, const char* config_name )
8110399f 1476{
a7bd16a4 1477 LXPanel* panel = NULL;
16fbda14 1478
17fab6e5 1479 if (G_LIKELY(config_file))
cf701cb7 1480 {
17fab6e5 1481 panel = panel_allocate();
a7bd16a4 1482 panel->priv->name = g_strdup(config_name);
17fab6e5 1483 g_debug("starting panel from file %s",config_file);
a7bd16a4 1484 if (!config_read_file(panel->priv->config, config_file) ||
17fab6e5 1485 !panel_start(panel))
3e7b8eb7 1486 {
06e29ce1 1487 g_warning( "lxpanel: can't start panel");
a7bd16a4 1488 gtk_widget_destroy(GTK_WIDGET(panel));
17fab6e5 1489 panel = NULL;
cf701cb7 1490 }
cf701cb7
HJYP
1491 }
1492 return panel;
8110399f 1493}
a52c2257 1494
9c338caf 1495
a7bd16a4 1496GtkOrientation panel_get_orientation(LXPanel *panel)
9c338caf 1497{
a7bd16a4 1498 return panel->priv->orientation;
9c338caf
AG
1499}
1500
a7bd16a4 1501gint panel_get_icon_size(LXPanel *panel)
9c338caf 1502{
a7bd16a4 1503 return panel->priv->icon_size;
9c338caf
AG
1504}
1505
a7bd16a4 1506gint panel_get_height(LXPanel *panel)
9c338caf 1507{
a7bd16a4 1508 return panel->priv->height;
9c338caf
AG
1509}
1510
a7bd16a4 1511Window panel_get_xwindow(LXPanel *panel)
4718ca02 1512{
a7bd16a4 1513 return panel->priv->topxwin;
4718ca02
AG
1514}
1515
a7bd16a4 1516gint panel_get_monitor(LXPanel *panel)
4718ca02 1517{
a7bd16a4 1518 return panel->priv->monitor;
4718ca02
AG
1519}
1520
a7bd16a4 1521GtkStyle *panel_get_defstyle(LXPanel *panel)
9c338caf 1522{
a7bd16a4 1523 return panel->priv->defstyle;
9c338caf
AG
1524}
1525
a7bd16a4 1526GtkIconTheme *panel_get_icon_theme(LXPanel *panel)
9c338caf 1527{
a7bd16a4 1528 return panel->priv->icon_theme;
9c338caf
AG
1529}
1530
a7bd16a4 1531gboolean panel_is_at_bottom(LXPanel *panel)
4718ca02 1532{
a7bd16a4 1533 return panel->priv->edge == EDGE_BOTTOM;
4718ca02
AG
1534}
1535
072944bf
AG
1536gboolean panel_is_dynamic(LXPanel *panel)
1537{
1538 return panel->priv->widthtype == WIDTH_REQUEST;
1539}
1540
a7bd16a4 1541GtkWidget *panel_box_new(LXPanel *panel, gboolean homogeneous, gint spacing)
9c338caf 1542{
a7bd16a4 1543 if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
5eaabb1b
AG
1544 return gtk_hbox_new(homogeneous, spacing);
1545 return gtk_vbox_new(homogeneous, spacing);
9c338caf
AG
1546}
1547
a7bd16a4 1548GtkWidget *panel_separator_new(LXPanel *panel)
9c338caf 1549{
a7bd16a4 1550 if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
5eaabb1b
AG
1551 return gtk_vseparator_new();
1552 return gtk_hseparator_new();
9c338caf 1553}
10d93053 1554
191694fb 1555gboolean _class_is_present(const LXPanelPluginInit *init)
10d93053
AG
1556{
1557 GSList *sl;
1558
1559 for (sl = all_panels; sl; sl = sl->next )
1560 {
a7bd16a4 1561 LXPanel *panel = (LXPanel*)sl->data;
10d93053
AG
1562 GList *plugins, *p;
1563
a7bd16a4 1564 plugins = gtk_container_get_children(GTK_CONTAINER(panel->priv->box));
10d93053
AG
1565 for (p = plugins; p; p = p->next)
1566 if (PLUGIN_CLASS(p->data) == init)
1567 {
1568 g_list_free(plugins);
1569 return TRUE;
1570 }
1571 g_list_free(plugins);
1572 }
1573 return FALSE;
1574}