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