debian: add libxml2-dev into build-deps (weather plugin require it)
[lxde/lxpanel.git] / src / panel.c
CommitLineData
16fb8c2e 1/**
e68b47dc
JH
2 * Copyright (c) 2006 LxDE Developers, see the file AUTHORS for details.
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
b31cb1d2 35#include "private.h"
a52c2257
HJYP
36#include "misc.h"
37#include "bg.h"
a52c2257 38
77886b88 39#include "lxpanelctl.h"
cf701cb7 40#include "dbg.h"
77886b88 41
a52c2257
HJYP
42static gchar *cfgfile = NULL;
43static gchar version[] = VERSION;
44gchar *cprofile = "default";
45
e2957bd2
HJYP
46static GtkWindowGroup* win_grp; /* window group used to limit the scope of model dialog. */
47
e68b47dc 48static int config = 0;
22242ed4 49FbEv *fbev = NULL;
a52c2257 50
cf701cb7 51GSList* all_panels = NULL; /* a single-linked list storing all panels */
a52c2257 52
f7cb330e
HJYP
53gboolean is_restarting = FALSE;
54
17fab6e5 55static int panel_start(Panel *p);
9dd114c4 56static void panel_start_gui(Panel *p);
4b93d81e 57
95095259
HJYP
58gboolean is_in_lxde = FALSE;
59
cb22c87c
HJYP
60/* A hack used to be compatible with Gnome panel for gtk+ themes.
61 * Some gtk+ themes define special styles for desktop panels.
62 * http://live.gnome.org/GnomeArt/Tutorials/GtkThemes/GnomePanel
63 * So we make a derived class from GtkWindow named PanelToplevel
64 * and create the panels with it to be compatible with Gnome themes.
65 */
66#define PANEL_TOPLEVEL_TYPE (panel_toplevel_get_type())
67
68typedef struct _PanelToplevel PanelToplevel;
69typedef struct _PanelToplevelClass PanelToplevelClass;
70struct _PanelToplevel
71{
72 GtkWindow parent;
73};
74struct _PanelToplevelClass
75{
76 GtkWindowClass parent_class;
77};
78G_DEFINE_TYPE(PanelToplevel, panel_toplevel, GTK_TYPE_WINDOW);
79static void panel_toplevel_class_init(PanelToplevelClass *klass)
80{
81}
82static void panel_toplevel_init(PanelToplevel *self)
83{
84}
85
9dd114c4 86/* Allocate and initialize new Panel structure. */
87static Panel* panel_allocate(void)
88{
2918994e 89 Panel* p = g_new0(Panel, 1);
9dd114c4 90 p->allign = ALLIGN_CENTER;
91 p->edge = EDGE_NONE;
92 p->widthtype = WIDTH_PERCENT;
93 p->width = 100;
94 p->heighttype = HEIGHT_PIXEL;
95 p->height = PANEL_HEIGHT_DEFAULT;
64afc832 96 p->monitor = 0;
9dd114c4 97 p->setdocktype = 1;
98 p->setstrut = 1;
99 p->round_corners = 0;
100 p->autohide = 0;
101 p->visible = TRUE;
102 p->height_when_hidden = 2;
103 p->transparent = 0;
bf2140f8
MJ
104 p->alpha = 255;
105 gdk_color_parse("white", &p->gtintcolor);
106 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
9dd114c4 107 p->usefontcolor = 0;
108 p->fontcolor = 0x00000000;
1869ef90
LK
109 p->usefontsize = 0;
110 p->fontsize = 10;
9dd114c4 111 p->spacing = 0;
8f9e6256 112 p->icon_size = PANEL_ICON_SIZE;
21f91705 113 p->icon_theme = gtk_icon_theme_get_default();
17fab6e5 114 p->config = config_new();
9dd114c4 115 return p;
116}
117
118/* Normalize panel configuration after load from file or reconfiguration. */
119static void panel_normalize_configuration(Panel* p)
120{
2918994e 121 panel_set_panel_configuration_changed( p );
9dd114c4 122 if (p->width < 0)
123 p->width = 100;
124 if (p->widthtype == WIDTH_PERCENT && p->width > 100)
125 p->width = 100;
126 p->heighttype = HEIGHT_PIXEL;
127 if (p->heighttype == HEIGHT_PIXEL) {
128 if (p->height < PANEL_HEIGHT_MIN)
129 p->height = PANEL_HEIGHT_MIN;
130 else if (p->height > PANEL_HEIGHT_MAX)
131 p->height = PANEL_HEIGHT_MAX;
132 }
64afc832
R
133 if (p->monitor < 0)
134 p->monitor = 0;
9dd114c4 135 if (p->background)
136 p->transparent = 0;
137}
138
a52c2257
HJYP
139/****************************************************
140 * panel's handlers for WM events *
141 ****************************************************/
a52c2257 142
22242ed4 143void panel_set_wm_strut(Panel *p)
a52c2257 144{
d1d43629 145 int index;
146 gulong strut_size;
147 gulong strut_lower;
148 gulong strut_upper;
a52c2257 149
d1d43629 150 /* Dispatch on edge to set up strut parameters. */
151 switch (p->edge)
bee4c26e 152 {
d1d43629 153 case EDGE_LEFT:
154 index = 0;
155 strut_size = p->aw;
156 strut_lower = p->ay;
157 strut_upper = p->ay + p->ah;
158 break;
159 case EDGE_RIGHT:
160 index = 1;
161 strut_size = p->aw;
162 strut_lower = p->ay;
163 strut_upper = p->ay + p->ah;
164 break;
165 case EDGE_TOP:
166 index = 2;
167 strut_size = p->ah;
168 strut_lower = p->ax;
169 strut_upper = p->ax + p->aw;
170 break;
171 case EDGE_BOTTOM:
172 index = 3;
173 strut_size = p->ah;
174 strut_lower = p->ax;
175 strut_upper = p->ax + p->aw;
176 break;
177 default:
178 return;
bee4c26e
HJYP
179 }
180
176fb687 181 /* Handle autohide case. EWMH recommends having the strut be the minimized size. */
92955ae5 182 if (p->autohide)
176fb687 183 strut_size = p->height_when_hidden;
184
d1d43629 185 /* Set up strut value in property format. */
186 gulong desired_strut[12];
187 memset(desired_strut, 0, sizeof(desired_strut));
188 if (p->setstrut)
189 {
190 desired_strut[index] = strut_size;
191 desired_strut[4 + index * 2] = strut_lower;
192 desired_strut[5 + index * 2] = strut_upper;
193 }
194 else
195 {
196 strut_size = 0;
197 strut_lower = 0;
198 strut_upper = 0;
bee4c26e 199 }
bee4c26e 200
d1d43629 201 /* If strut value changed, set the property value on the panel window.
202 * This avoids property change traffic when the panel layout is recalculated but strut geometry hasn't changed. */
203 if ((GTK_WIDGET_MAPPED(p->topgwin))
547ece89 204 && ((p->strut_size != strut_size) || (p->strut_lower != strut_lower) || (p->strut_upper != strut_upper) || (p->strut_edge != p->edge)))
d1d43629 205 {
206 p->strut_size = strut_size;
207 p->strut_lower = strut_lower;
208 p->strut_upper = strut_upper;
547ece89 209 p->strut_edge = p->edge;
a52c2257 210
d1d43629 211 /* If window manager supports STRUT_PARTIAL, it will ignore STRUT.
212 * Set STRUT also for window managers that do not support STRUT_PARTIAL. */
213 if (strut_size != 0)
214 {
215 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL,
216 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desired_strut, 12);
217 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT,
218 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desired_strut, 4);
219 }
220 else
221 {
222 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT);
223 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL);
224 }
225 }
a52c2257
HJYP
226}
227
3e7b8eb7
HJYP
228/* defined in configurator.c */
229void panel_configure(Panel* p, int sel_page );
64afc832 230gboolean panel_edge_available(Panel* p, int edge, gint monitor);
3e7b8eb7 231
e996608e 232/* built-in commands, defined in configurator.c */
77886b88
HJYP
233void restart(void);
234void gtk_run(void);
e3b89f43 235void panel_destroy(Panel *p);
77886b88 236
d18c9409 237static void process_client_msg ( XClientMessageEvent* ev )
77886b88 238{
8c44345a 239 int cmd = ev->data.b[0];
77886b88
HJYP
240 switch( cmd )
241 {
ace2a572 242#ifndef DISABLE_MENU
77886b88 243 case LXPANEL_CMD_SYS_MENU:
d18c9409
HJYP
244 {
245 GSList* l;
246 for( l = all_panels; l; l = l->next )
8c44345a 247 {
d18c9409 248 Panel* p = (Panel*)l->data;
dd731fde
AG
249 GList *plugins, *pl;
250
251 plugins = gtk_container_get_children(GTK_CONTAINER(p->box));
252 for (pl = plugins; pl; pl = pl->next)
d18c9409 253 {
dd731fde
AG
254 LXPanelPluginInit *init = PLUGIN_CLASS(pl->data);
255 if (init->show_system_menu)
256 /* queue to show system menu */
257 init->show_system_menu(pl->data);
d18c9409 258 }
dd731fde 259 g_list_free(plugins);
8c44345a 260 }
77886b88 261 break;
d18c9409 262 }
ace2a572
JH
263#endif
264#ifndef DISABLE_MENU
77886b88
HJYP
265 case LXPANEL_CMD_RUN:
266 gtk_run();
267 break;
ace2a572 268#endif
77886b88 269 case LXPANEL_CMD_CONFIG:
0c5f948f
MJ
270 {
271 Panel * p = ((all_panels != NULL) ? all_panels->data : NULL);
272 if (p != NULL)
273 panel_configure(p, 0);
274 }
77886b88
HJYP
275 break;
276 case LXPANEL_CMD_RESTART:
277 restart();
278 break;
279 case LXPANEL_CMD_EXIT:
280 gtk_main_quit();
281 break;
282 }
283}
284
a52c2257 285static GdkFilterReturn
cf701cb7 286panel_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer not_used)
a52c2257
HJYP
287{
288 Atom at;
289 Window win;
290 XEvent *ev = (XEvent *) xevent;
291
292 ENTER;
293 DBG("win = 0x%x\n", ev->xproperty.window);
53b37ef2
HJYP
294 if (ev->type != PropertyNotify )
295 {
77886b88
HJYP
296 /* private client message from lxpanelctl */
297 if( ev->type == ClientMessage && ev->xproperty.atom == a_LXPANEL_CMD )
298 {
d18c9409 299 process_client_msg( (XClientMessageEvent*)ev );
77886b88 300 }
22242ed4
HJYP
301 else if( ev->type == DestroyNotify )
302 {
cf701cb7 303 fb_ev_emit_destroy( fbev, ((XDestroyWindowEvent*)ev)->window );
22242ed4 304 }
a52c2257 305 RET(GDK_FILTER_CONTINUE);
24053345 306 }
77886b88 307
a52c2257
HJYP
308 at = ev->xproperty.atom;
309 win = ev->xproperty.window;
53b37ef2
HJYP
310 if (win == GDK_ROOT_WINDOW())
311 {
312 if (at == a_NET_CLIENT_LIST)
313 {
314 fb_ev_emit(fbev, EV_CLIENT_LIST);
315 }
316 else if (at == a_NET_CURRENT_DESKTOP)
317 {
cf701cb7
HJYP
318 GSList* l;
319 for( l = all_panels; l; l = l->next )
320 ((Panel*)l->data)->curdesk = get_net_current_desktop();
22242ed4 321 fb_ev_emit(fbev, EV_CURRENT_DESKTOP);
53b37ef2
HJYP
322 }
323 else if (at == a_NET_NUMBER_OF_DESKTOPS)
324 {
cf701cb7
HJYP
325 GSList* l;
326 for( l = all_panels; l; l = l->next )
327 ((Panel*)l->data)->desknum = get_net_number_of_desktops();
22242ed4 328 fb_ev_emit(fbev, EV_NUMBER_OF_DESKTOPS);
53b37ef2
HJYP
329 }
330 else if (at == a_NET_DESKTOP_NAMES)
331 {
22242ed4 332 fb_ev_emit(fbev, EV_DESKTOP_NAMES);
53b37ef2
HJYP
333 }
334 else if (at == a_NET_ACTIVE_WINDOW)
335 {
22242ed4 336 fb_ev_emit(fbev, EV_ACTIVE_WINDOW );
53b37ef2
HJYP
337 }
338 else if (at == a_NET_CLIENT_LIST_STACKING)
339 {
22242ed4 340 fb_ev_emit(fbev, EV_CLIENT_LIST_STACKING);
53b37ef2
HJYP
341 }
342 else if (at == a_XROOTPMAP_ID)
343 {
cf701cb7
HJYP
344 GSList* l;
345 for( l = all_panels; l; l = l->next )
346 {
347 Panel* p = (Panel*)l->data;
348 if (p->transparent) {
349 fb_bg_notify_changed_bg(p->bg);
350 }
351 }
53b37ef2
HJYP
352 }
353 else if (at == a_NET_WORKAREA)
354 {
cf701cb7
HJYP
355 GSList* l;
356 for( l = all_panels; l; l = l->next )
357 {
358 Panel* p = (Panel*)l->data;
359 g_free( p->workarea );
360 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
1d9dc649 361 /* print_wmdata(p); */
a52c2257 362 }
53b37ef2
HJYP
363 }
364 else
cf701cb7
HJYP
365 return GDK_FILTER_CONTINUE;
366
367 return GDK_FILTER_REMOVE;
a52c2257 368 }
cf701cb7 369 return GDK_FILTER_CONTINUE;
a52c2257
HJYP
370}
371
372/****************************************************
373 * panel's handlers for GTK events *
374 ****************************************************/
375
bee4c26e 376
a52c2257
HJYP
377static gint
378panel_delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
379{
380 ENTER;
381 RET(FALSE);
382}
383
384static gint
385panel_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer data)
386{
22242ed4 387 //Panel *p = (Panel *) data;
a52c2257
HJYP
388 //if (!p->self_destroy)
389 gtk_main_quit();
390 RET(FALSE);
391}
392
4542c20d 393static void
22242ed4 394on_root_bg_changed(FbBg *bg, Panel* p)
4542c20d
HJYP
395{
396 panel_update_background( p );
397}
398
2918994e 399void panel_determine_background_pixmap(Panel * p, GtkWidget * widget, GdkWindow * window)
4542c20d 400{
2918994e 401 GdkPixmap * pixmap = NULL;
4542c20d 402
2918994e 403 /* Free p->bg if it is not going to be used. */
404 if (( ! p->transparent) && (p->bg != NULL))
405 {
406 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, p);
407 g_object_unref(p->bg);
408 p->bg = NULL;
409 }
4542c20d 410
2918994e 411 if (p->background)
412 {
413 /* User specified background pixmap. */
414 if (p->background_file != NULL)
415 pixmap = fb_bg_get_pix_from_file(widget, p->background_file);
4542c20d 416 }
2918994e 417
418 else if (p->transparent)
4542c20d 419 {
2918994e 420 /* Transparent. Determine the appropriate value from the root pixmap. */
421 if (p->bg == NULL)
4542c20d 422 {
2918994e 423 p->bg = fb_bg_get_for_display();
424 g_signal_connect(G_OBJECT(p->bg), "changed", G_CALLBACK(on_root_bg_changed), p);
4542c20d 425 }
2918994e 426 pixmap = fb_bg_get_xroot_pix_for_win(p->bg, widget);
427 if ((pixmap != NULL) && (pixmap != GDK_NO_BG) && (p->alpha != 0))
938806f9 428 fb_bg_composite(pixmap, &p->gtintcolor, p->alpha);
4542c20d
HJYP
429 }
430
2918994e 431 if (pixmap != NULL)
4542c20d 432 {
2918994e 433 gtk_widget_set_app_paintable(widget, TRUE );
434 gdk_window_set_back_pixmap(window, pixmap, FALSE);
435 g_object_unref(pixmap);
4542c20d
HJYP
436 }
437 else
2918994e 438 gtk_widget_set_app_paintable(widget, FALSE);
439}
4542c20d 440
2918994e 441/* Update the background of the entire panel.
442 * This function should only be called after the panel has been realized. */
443void panel_update_background(Panel * p)
444{
17fab6e5
AG
445 GList *plugins, *l;
446
2918994e 447 /* Redraw the top level widget. */
448 panel_determine_background_pixmap(p, p->topgwin, p->topgwin->window);
449 gdk_window_clear(p->topgwin->window);
450 gtk_widget_queue_draw(p->topgwin);
2918994e 451
452 /* Loop over all plugins redrawing each plugin. */
17fab6e5
AG
453 plugins = gtk_container_get_children(GTK_CONTAINER(p->box));
454 for (l = plugins; l != NULL; l = l->next)
455 plugin_widget_set_background(l->data, p);
456 g_list_free(plugins);
4542c20d 457}
a52c2257 458
84fc1d55
HJYP
459static gboolean delay_update_background( Panel* p )
460{
6589616e
JH
461 /* Panel could be destroyed while background update scheduled */
462 if ( p->topgwin && GTK_WIDGET_REALIZED ( p->topgwin ) ) {
463 gdk_display_sync( gtk_widget_get_display(p->topgwin) );
464 panel_update_background( p );
465 }
466
cf701cb7 467 return FALSE;
84fc1d55
HJYP
468}
469
470static void
f2d54481
HJYP
471panel_realize(GtkWidget *widget, Panel *p)
472{
e3b89f43 473 g_idle_add_full( G_PRIORITY_LOW,
474 (GSourceFunc)delay_update_background, p, NULL );
f2d54481
HJYP
475}
476
477static void
84fc1d55
HJYP
478panel_style_set(GtkWidget *widget, GtkStyle* prev, Panel *p)
479{
0987f648 480 /* FIXME: This dirty hack is used to fix the background of systray... */
cf701cb7 481 if( GTK_WIDGET_REALIZED( widget ) )
e3b89f43 482 g_idle_add_full( G_PRIORITY_LOW,
483 (GSourceFunc)delay_update_background, p, NULL );
84fc1d55 484}
4542c20d 485
a52c2257 486static gint
22242ed4 487panel_size_req(GtkWidget *widget, GtkRequisition *req, Panel *p)
a52c2257
HJYP
488{
489 ENTER;
4542c20d 490
b957082c
JC
491 if (p->autohide && !p->visible)
492 /* When the panel is in invisible state, the content box also got hidden, thus always
493 * report 0 size. Ask the content box instead for its size. */
494 gtk_widget_size_request(p->box, req);
495
a52c2257 496 if (p->widthtype == WIDTH_REQUEST)
cfde283a 497 p->width = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? req->width : req->height;
a52c2257 498 if (p->heighttype == HEIGHT_REQUEST)
cfde283a 499 p->height = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? req->height : req->width;
b957082c 500
a52c2257 501 calculate_position(p);
b957082c
JC
502
503 gtk_widget_set_size_request( widget, p->aw, p->ah );
4542c20d 504
a52c2257
HJYP
505 RET( TRUE );
506}
507
508static gint
22242ed4 509panel_size_alloc(GtkWidget *widget, GtkAllocation *a, Panel *p)
a52c2257
HJYP
510{
511 ENTER;
a52c2257 512 if (p->widthtype == WIDTH_REQUEST)
cfde283a 513 p->width = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? a->width : a->height;
a52c2257 514 if (p->heighttype == HEIGHT_REQUEST)
cfde283a 515 p->height = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? a->height : a->width;
a52c2257 516 calculate_position(p);
4542c20d 517
a52c2257 518 if (a->width == p->aw && a->height == p->ah && a->x == p->ax && a->y == p ->ay) {
a52c2257
HJYP
519 RET(TRUE);
520 }
521
522 gtk_window_move(GTK_WINDOW(p->topgwin), p->ax, p->ay);
bee4c26e 523 panel_set_wm_strut(p);
a52c2257
HJYP
524 RET(TRUE);
525}
526
a52c2257 527static gboolean
22242ed4 528panel_configure_event (GtkWidget *widget, GdkEventConfigure *e, Panel *p)
a52c2257
HJYP
529{
530 ENTER;
531 if (e->width == p->cw && e->height == p->ch && e->x == p->cx && e->y == p->cy)
532 RET(TRUE);
533 p->cw = e->width;
534 p->ch = e->height;
535 p->cx = e->x;
536 p->cy = e->y;
4542c20d 537
a52c2257
HJYP
538 if (p->transparent)
539 fb_bg_notify_changed_bg(p->bg);
bee4c26e 540
4542c20d 541 RET(FALSE);
a52c2257
HJYP
542}
543
fddae119
FC
544static gint
545panel_popupmenu_configure(GtkWidget *widget, gpointer user_data)
546{
4b93d81e
HJYP
547 panel_configure( (Panel*)user_data, 0 );
548 return TRUE;
fddae119
FC
549}
550
9dd114c4 551/* Handler for "button_press_event" signal with Panel as parameter. */
552static gboolean panel_button_press_event_with_panel(GtkWidget *widget, GdkEventButton *event, Panel *panel)
fddae119 553{
9dd114c4 554 if (event->button == 3) /* right button */
555 {
17fab6e5 556 GtkMenu* popup = (GtkMenu*) lxpanel_get_plugin_menu(panel, NULL, FALSE);
9dd114c4 557 gtk_menu_popup(popup, NULL, NULL, NULL, NULL, event->button, event->time);
558 return TRUE;
559 }
fddae119
FC
560 return FALSE;
561}
562
17fab6e5 563static void panel_popupmenu_config_plugin( GtkMenuItem* item, GtkWidget* plugin )
cf701cb7 564{
17fab6e5
AG
565 LXPanelPluginInit *init = PLUGIN_CLASS(plugin);
566 Panel *panel = PLUGIN_PANEL(plugin);
567
568 init->config(panel, plugin, GTK_WINDOW(panel->topgwin));
930af9fd
HJYP
569
570 /* FIXME: this should be more elegant */
17fab6e5 571 panel->config_changed = TRUE;
cf701cb7
HJYP
572}
573
4b93d81e
HJYP
574static void panel_popupmenu_add_item( GtkMenuItem* item, Panel* panel )
575{
576 /* panel_add_plugin( panel, panel->topgwin ); */
8d8b66da 577 panel_configure( panel, 2 );
cf701cb7
HJYP
578}
579
17fab6e5 580static void panel_popupmenu_remove_item( GtkMenuItem* item, GtkWidget* plugin )
cf701cb7 581{
17fab6e5 582 Panel* panel = PLUGIN_PANEL(plugin);
b7e8ad02
MJ
583
584 /* If the configuration dialog is open, there will certainly be a crash if the
585 * user manipulates the Configured Plugins list, after we remove this entry.
586 * Close the configuration dialog if it is open. */
587 if (panel->pref_dialog != NULL)
588 {
589 gtk_widget_destroy(panel->pref_dialog);
590 panel->pref_dialog = NULL;
591 }
17fab6e5
AG
592 config_setting_destroy(g_object_get_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf));
593 /* reset conf pointer because the widget still may be referenced by configurator */
594 g_object_set_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf, NULL);
b7e8ad02 595
17fab6e5
AG
596 panel_config_save(panel);
597 gtk_widget_destroy(plugin);
cf701cb7
HJYP
598}
599
3e7b8eb7
HJYP
600/* FIXME: Potentially we can support multiple panels at the same edge,
601 * but currently this cannot be done due to some positioning problems. */
64afc832 602static char* gen_panel_name( int edge, gint monitor )
3e7b8eb7
HJYP
603{
604 const char* edge_str = num2str( edge_pair, edge, "" );
605 char* name = NULL;
606 char* dir = get_config_file( cprofile, "panels", FALSE );
607 int i;
608 for( i = 0; i < G_MAXINT; ++i )
609 {
610 char* f;
64afc832
R
611 if(monitor != 0)
612 name = g_strdup_printf( "%s-m%d-%d", edge_str, monitor, i );
613 else if( G_LIKELY( i > 0 ) )
3e7b8eb7
HJYP
614 name = g_strdup_printf( "%s%d", edge_str, i );
615 else
616 name = g_strdup( edge_str );
64afc832 617
3e7b8eb7
HJYP
618 f = g_build_filename( dir, name, NULL );
619 if( ! g_file_test( f, G_FILE_TEST_EXISTS ) )
620 {
621 g_free( f );
622 break;
623 }
624 g_free( name );
625 g_free( f );
626 }
627 g_free( dir );
628 return name;
629}
630
631/* FIXME: Potentially we can support multiple panels at the same edge,
632 * but currently this cannot be done due to some positioning problems. */
cf701cb7
HJYP
633static void panel_popupmenu_create_panel( GtkMenuItem* item, Panel* panel )
634{
64afc832
R
635 gint m, e, monitors;
636 GdkScreen *screen;
637 GtkWidget *err;
9dd114c4 638 Panel* new_panel = panel_allocate();
639
640 /* Allocate the edge. */
64afc832
R
641 screen = gdk_screen_get_default();
642 g_assert(screen);
643 monitors = gdk_screen_get_n_monitors(screen);
644 for(m=0; m<monitors; ++m)
645 {
646 /* try each of the four edges */
647 for(e=1; e<5; ++e)
648 {
649 if(panel_edge_available(new_panel,e,m)) {
650 new_panel->edge = e;
651 new_panel->monitor = m;
652 goto found_edge;
653 }
654 }
655 }
656
17fab6e5 657 panel_destroy(new_panel);
64afc832
R
658 ERR("Error adding panel: There is no room for another panel. All the edges are taken.\n");
659 err = gtk_message_dialog_new(NULL,0,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("There is no room for another panel. All the edges are taken."));
660 gtk_dialog_run(GTK_DIALOG(err));
661 gtk_widget_destroy(err);
662 return;
663
664found_edge:
665 new_panel->name = gen_panel_name(new_panel->edge,new_panel->monitor);
9dd114c4 666
17fab6e5
AG
667 /* create new config with first group "Global" */
668 config_setting_add(config_setting_add(config_root_setting(new_panel->config),
669 "", PANEL_CONF_TYPE_LIST),
670 "Global", PANEL_CONF_TYPE_GROUP);
9dd114c4 671 panel_configure(new_panel, 0);
672 panel_normalize_configuration(new_panel);
673 panel_start_gui(new_panel);
674 gtk_widget_show_all(new_panel->topgwin);
675
676 panel_config_save(new_panel);
677 all_panels = g_slist_prepend(all_panels, new_panel);
cf701cb7
HJYP
678}
679
680static void panel_popupmenu_delete_panel( GtkMenuItem* item, Panel* panel )
681{
682 GtkWidget* dlg;
683 gboolean ok;
e3b89f43 684 dlg = gtk_message_dialog_new_with_markup( GTK_WINDOW(panel->topgwin),
cf701cb7
HJYP
685 GTK_DIALOG_MODAL,
686 GTK_MESSAGE_QUESTION,
687 GTK_BUTTONS_OK_CANCEL,
688 _("Really delete this panel?\n<b>Warning: This can not be recovered.</b>") );
d1d43629 689 panel_apply_icon(GTK_WINDOW(dlg));
cf701cb7
HJYP
690 gtk_window_set_title( (GtkWindow*)dlg, _("Confirm") );
691 ok = ( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK );
692 gtk_widget_destroy( dlg );
693 if( ok )
694 {
4b93d81e 695 gchar *fname, *dir;
cf701cb7 696 all_panels = g_slist_remove( all_panels, panel );
4b93d81e
HJYP
697
698 /* delete the config file of this panel */
699 dir = get_config_file( cprofile, "panels", FALSE );
700 fname = g_build_filename( dir, panel->name, NULL );
701 g_free( dir );
702 g_unlink( fname );
930af9fd 703 panel->config_changed = 0;
cf701cb7
HJYP
704 panel_destroy( panel );
705 }
706}
707
e7a42ecf 708static void panel_popupmenu_about( GtkMenuItem* item, Panel* panel )
709{
710 GtkWidget *about;
711 const gchar* authors[] = {
712 "Hong Jen Yee (PCMan) <pcman.tw@gmail.com>",
713 "Jim Huang <jserv.tw@gmail.com>",
714 "Greg McNew <gmcnew@gmail.com> (battery plugin)",
715 "Fred Chien <cfsghost@gmail.com>",
716 "Daniel Kesler <kesler.daniel@gmail.com>",
717 "Juergen Hoetzel <juergen@archlinux.org>",
2918994e 718 "Marty Jack <martyj19@comcast.net>",
815e1027 719 "Martin Bagge <brother@bsnet.se>",
e7a42ecf 720 NULL
721 };
722 /* TRANSLATORS: Replace this string with your names, one name per line. */
723 gchar *translators = _( "translator-credits" );
724
725 about = gtk_about_dialog_new();
726 panel_apply_icon(GTK_WINDOW(about));
727 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), VERSION);
728 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), _("LXPanel"));
4c91be3e
JL
729
730 if(gtk_icon_theme_has_icon(panel->icon_theme, "video-display"))
731 {
732 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
733 gtk_icon_theme_load_icon(panel->icon_theme, "video-display", 48, 0, NULL));
734 }
735 else if (gtk_icon_theme_has_icon(panel->icon_theme, "start-here"))
736 {
737 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
738 gtk_icon_theme_load_icon(panel->icon_theme, "start-here", 48, 0, NULL));
739 }
740 else
741 {
742 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
743 gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/lxpanel/images/my-computer.png", NULL));
744 }
745
d111d2b8 746 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about), _("Copyright (C) 2008-2013"));
e7a42ecf 747 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), _( "Desktop panel for LXDE project"));
748 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.");
749 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://lxde.org/");
750 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about), authors);
751 gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about), translators);
752 gtk_dialog_run(GTK_DIALOG(about));
753 gtk_widget_destroy(about);
754}
755
756void panel_apply_icon( GtkWindow *w )
757{
d60c9372
MR
758 GdkPixbuf* window_icon;
759
4c91be3e
JL
760 if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "video-display"))
761 {
3ad38785 762 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "video-display", 24, 0, NULL);
d60c9372 763 }
4c91be3e
JL
764 else if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "start-here"))
765 {
766 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "start-here", 24, 0, NULL);
89496346
JL
767 }
768 else
4c91be3e 769 {
d60c9372
MR
770 window_icon = gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/lxpanel/images/my-computer.png", NULL);
771 }
21f91705 772 gtk_window_set_icon(w, window_icon);
e7a42ecf 773}
774
17fab6e5 775GtkMenu* lxpanel_get_plugin_menu( Panel* panel, GtkWidget* plugin, gboolean use_sub_menu )
cf701cb7 776{
e3b89f43 777 GtkWidget *menu_item, *img;
778 GtkMenu *ret,*menu;
e56f2fdd 779 LXPanelPluginInit *init;
cf701cb7 780 char* tmp;
e3b89f43 781 ret = menu = GTK_MENU(gtk_menu_new());
cf701cb7 782
4b93d81e
HJYP
783 img = gtk_image_new_from_stock( GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU );
784 menu_item = gtk_image_menu_item_new_with_label(_("Add / Remove Panel Items"));
785 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
786 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
787 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
cf701cb7
HJYP
788
789 if( plugin )
790 {
e56f2fdd 791 init = PLUGIN_CLASS(plugin);
cf701cb7 792 img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
17fab6e5 793 tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(init->name) );
cf701cb7
HJYP
794 menu_item = gtk_image_menu_item_new_with_label( tmp );
795 g_free( tmp );
796 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
797 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
798 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_remove_item), plugin );
799 }
800
801 menu_item = gtk_separator_menu_item_new();
802 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
803
4b93d81e
HJYP
804 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
805 menu_item = gtk_image_menu_item_new_with_label(_("Panel Settings"));
806 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
807 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
808 g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_popupmenu_configure), panel );
809
cf701cb7
HJYP
810 img = gtk_image_new_from_stock( GTK_STOCK_NEW, GTK_ICON_SIZE_MENU );
811 menu_item = gtk_image_menu_item_new_with_label(_("Create New Panel"));
812 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
813 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
814 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_create_panel), panel );
815
816 img = gtk_image_new_from_stock( GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU );
817 menu_item = gtk_image_menu_item_new_with_label(_("Delete This Panel"));
818 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
819 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
820 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_delete_panel), panel );
821 if( ! all_panels->next ) /* if this is the only panel */
822 gtk_widget_set_sensitive( menu_item, FALSE );
823
e7a42ecf 824 menu_item = gtk_separator_menu_item_new();
825 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
826
827 img = gtk_image_new_from_stock( GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU );
828 menu_item = gtk_image_menu_item_new_with_label(_("About"));
829 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
830 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
831 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_about), panel );
832
cf701cb7
HJYP
833 if( use_sub_menu )
834 {
e3b89f43 835 ret = GTK_MENU(gtk_menu_new());
cf701cb7
HJYP
836 menu_item = gtk_image_menu_item_new_with_label(_("Panel"));
837 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
e3b89f43 838 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), GTK_WIDGET(menu) );
cf701cb7 839
e3b89f43 840 gtk_widget_show_all(GTK_WIDGET(ret));
cf701cb7
HJYP
841 }
842
3e7b8eb7
HJYP
843 if( plugin )
844 {
845 menu_item = gtk_separator_menu_item_new();
846 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
847
848 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
17fab6e5 849 tmp = g_strdup_printf( _("\"%s\" Settings"), _(init->name) );
3e7b8eb7
HJYP
850 menu_item = gtk_image_menu_item_new_with_label( tmp );
851 g_free( tmp );
852 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
853 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
17fab6e5 854 if( init->config )
3e7b8eb7
HJYP
855 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
856 else
857 gtk_widget_set_sensitive( menu_item, FALSE );
858 }
859
e3b89f43 860 gtk_widget_show_all(GTK_WIDGET(menu));
3e7b8eb7 861
cf701cb7
HJYP
862 g_signal_connect( ret, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
863 return ret;
864}
865
17fab6e5
AG
866/* for old plugins compatibility */
867GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
868{
869 return lxpanel_get_plugin_menu(panel, plugin->pwid, use_sub_menu);
870}
871
a52c2257
HJYP
872/****************************************************
873 * panel creation *
874 ****************************************************/
176fb687 875
a52c2257 876static void
22242ed4 877make_round_corners(Panel *p)
a52c2257 878{
a97d06a6 879 /* FIXME: This should be re-written with shape extension of X11 */
4542c20d 880 /* gdk_window_shape_combine_mask() can be used */
bee4c26e
HJYP
881}
882
22242ed4 883void panel_set_dock_type(Panel *p)
bee4c26e
HJYP
884{
885 if (p->setdocktype) {
886 Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
887 XChangeProperty(GDK_DISPLAY(), p->topxwin,
888 a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
889 PropModeReplace, (unsigned char *) &state, 1);
890 }
891 else {
892 XDeleteProperty( GDK_DISPLAY(), p->topxwin, a_NET_WM_WINDOW_TYPE );
893 }
a52c2257
HJYP
894}
895
176fb687 896static void panel_set_visibility(Panel *p, gboolean visible)
897{
898 if ( ! visible) gtk_widget_hide(p->box);
899 p->visible = visible;
900 calculate_position(p);
901 gtk_widget_set_size_request(p->topgwin, p->aw, p->ah);
902 gdk_window_move(p->topgwin->window, p->ax, p->ay);
903 if (visible) gtk_widget_show(p->box);
904 panel_set_wm_strut(p);
905}
906
907static gboolean panel_leave_real(Panel *p)
908{
fab48ed0 909 /* If the pointer is grabbed by this application, leave the panel displayed.
910 * There is no way to determine if it is grabbed by another application, such as an application that has a systray icon. */
176fb687 911 if (gdk_display_pointer_is_grabbed(p->display))
912 return TRUE;
913
fab48ed0 914 /* If the pointer is inside the panel, leave the panel displayed. */
176fb687 915 gint x, y;
916 gdk_display_get_pointer(p->display, NULL, &x, &y, NULL);
917 if ((p->cx <= x) && (x <= (p->cx + p->cw)) && (p->cy <= y) && (y <= (p->cy + p->ch)))
918 return TRUE;
919
fab48ed0 920 /* If the panel is configured to autohide and if it is visible, hide the panel. */
176fb687 921 if ((p->autohide) && (p->visible))
922 panel_set_visibility(p, FALSE);
923
fab48ed0 924 /* Clear the timer. */
176fb687 925 p->hide_timeout = 0;
926 return FALSE;
927}
928
929static gboolean panel_enter(GtkImage *widget, GdkEventCrossing *event, Panel *p)
930{
fab48ed0 931 /* We may receive multiple enter-notify events when the pointer crosses into the panel.
932 * Do extra tests to make sure this does not cause misoperation such as blinking.
933 * If the pointer is inside the panel, unhide it. */
934 gint x, y;
935 gdk_display_get_pointer(p->display, NULL, &x, &y, NULL);
936 if ((p->cx <= x) && (x <= (p->cx + p->cw)) && (p->cy <= y) && (y <= (p->cy + p->ch)))
937 {
938 /* If the pointer is inside the panel and we have not already unhidden it, do so and
939 * set a timer to recheck it in a half second. */
940 if (p->hide_timeout == 0)
941 {
942 p->hide_timeout = g_timeout_add(500, (GSourceFunc) panel_leave_real, p);
943 panel_set_visibility(p, TRUE);
944 }
945 }
946 else
947 {
948 /* If the pointer is not inside the panel, simulate a timer expiration. */
949 panel_leave_real(p);
950 }
176fb687 951 return TRUE;
952}
953
954static gboolean panel_drag_motion(GtkWidget *widget, GdkDragContext *drag_context, gint x,
955 gint y, guint time, Panel *p)
956{
957 panel_enter(NULL, NULL, p);
958 return TRUE;
959}
960
961void panel_establish_autohide(Panel *p)
962{
963 if (p->autohide)
964 {
965 gtk_widget_add_events(p->topgwin, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
966 g_signal_connect(G_OBJECT(p->topgwin), "enter-notify-event", G_CALLBACK(panel_enter), p);
967 g_signal_connect(G_OBJECT(p->topgwin), "drag-motion", (GCallback) panel_drag_motion, p);
968 gtk_drag_dest_set(p->topgwin, GTK_DEST_DEFAULT_MOTION, NULL, 0, 0);
969 gtk_drag_dest_set_track_motion(p->topgwin, TRUE);
970 panel_enter(NULL, NULL, p);
971 }
972 else if ( ! p->visible)
973 {
974 gtk_widget_show(p->box);
975 p->visible = TRUE;
976 }
977}
978
8f9e6256 979/* Set an image from a file with scaling to the panel icon size. */
fcb35553 980void panel_image_set_from_file(Panel * p, GtkWidget * image, const char * file)
8f9e6256 981{
982 GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file_at_scale(file, p->icon_size, p->icon_size, TRUE, NULL);
983 if (pixbuf != NULL)
984 {
985 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
986 g_object_unref(pixbuf);
987 }
988}
989
c14620f2
MJ
990/* Set an image from a icon theme with scaling to the panel icon size. */
991gboolean panel_image_set_icon_theme(Panel * p, GtkWidget * image, const gchar * icon)
992{
1b532bce 993 if (gtk_icon_theme_has_icon(p->icon_theme, icon))
c14620f2 994 {
1b532bce 995 GdkPixbuf * pixbuf = gtk_icon_theme_load_icon(p->icon_theme, icon, p->icon_size, 0, NULL);
c14620f2
MJ
996 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
997 g_object_unref(pixbuf);
998 return TRUE;
999 }
1000 return FALSE;
1001}
1002
0defe4b9 1003static void
22242ed4 1004panel_start_gui(Panel *p)
a52c2257
HJYP
1005{
1006 Atom state[3];
1007 XWMHints wmhints;
1008 guint32 val;
6db11841 1009
a52c2257
HJYP
1010 ENTER;
1011
9dd114c4 1012 p->curdesk = get_net_current_desktop();
1013 p->desknum = get_net_number_of_desktops();
1014 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
1015
cb22c87c
HJYP
1016 /* main toplevel window */
1017 /* p->topgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); */
1018 p->topgwin = (GtkWidget*)g_object_new(PANEL_TOPLEVEL_TYPE, NULL);
1019 gtk_widget_set_name(p->topgwin, "PanelToplevel");
176fb687 1020 p->display = gdk_display_get_default();
a52c2257
HJYP
1021 gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
1022 gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
1023 gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "lxpanel");
1024 gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
1025 gtk_window_set_position(GTK_WINDOW(p->topgwin), GTK_WIN_POS_NONE);
1026 gtk_window_set_decorated(GTK_WINDOW(p->topgwin), FALSE);
77886b88 1027
e2957bd2
HJYP
1028 gtk_window_group_add_window( win_grp, (GtkWindow*)p->topgwin );
1029
a52c2257
HJYP
1030 g_signal_connect(G_OBJECT(p->topgwin), "delete-event",
1031 G_CALLBACK(panel_delete_event), p);
1032 g_signal_connect(G_OBJECT(p->topgwin), "destroy-event",
1033 G_CALLBACK(panel_destroy_event), p);
1034 g_signal_connect (G_OBJECT (p->topgwin), "size-request",
1035 (GCallback) panel_size_req, p);
1036 g_signal_connect (G_OBJECT (p->topgwin), "size-allocate",
1037 (GCallback) panel_size_alloc, p);
1038 g_signal_connect (G_OBJECT (p->topgwin), "configure-event",
1039 (GCallback) panel_configure_event, p);
3e7b8eb7
HJYP
1040
1041 gtk_widget_add_events( p->topgwin, GDK_BUTTON_PRESS_MASK );
8e05828e 1042 g_signal_connect(G_OBJECT (p->topgwin), "button-press-event",
9dd114c4 1043 (GCallback) panel_button_press_event_with_panel, p);
f2d54481 1044
a52c2257
HJYP
1045 g_signal_connect (G_OBJECT (p->topgwin), "realize",
1046 (GCallback) panel_realize, p);
f2d54481 1047
84fc1d55
HJYP
1048 g_signal_connect (G_OBJECT (p->topgwin), "style-set",
1049 (GCallback)panel_style_set, p);
a52c2257
HJYP
1050 gtk_widget_realize(p->topgwin);
1051 //gdk_window_set_decorations(p->topgwin->window, 0);
2de71c90 1052
4542c20d 1053 // main layout manager as a single child of panel
a97d06a6 1054 p->box = p->my_box_new(FALSE, 0);
a52c2257 1055 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
4542c20d
HJYP
1056// gtk_container_add(GTK_CONTAINER(p->bbox), p->box);
1057 gtk_container_add(GTK_CONTAINER(p->topgwin), p->box);
a52c2257 1058 gtk_widget_show(p->box);
a97d06a6
HJYP
1059 if (p->round_corners)
1060 make_round_corners(p);
6db11841 1061
a52c2257
HJYP
1062 p->topxwin = GDK_WINDOW_XWINDOW(GTK_WIDGET(p->topgwin)->window);
1063 DBG("topxwin = %x\n", p->topxwin);
1064
1065 /* the settings that should be done before window is mapped */
1066 wmhints.flags = InputHint;
1067 wmhints.input = 0;
bee4c26e 1068 XSetWMHints (GDK_DISPLAY(), p->topxwin, &wmhints);
24053345 1069#define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
a52c2257
HJYP
1070 val = WIN_HINTS_SKIP_FOCUS;
1071 XChangeProperty(GDK_DISPLAY(), p->topxwin,
1072 XInternAtom(GDK_DISPLAY(), "_WIN_HINTS", False), XA_CARDINAL, 32,
1073 PropModeReplace, (unsigned char *) &val, 1);
1074
bee4c26e 1075 panel_set_dock_type(p);
a52c2257
HJYP
1076
1077 /* window mapping point */
1078 gtk_widget_show_all(p->topgwin);
1079
1080 /* the settings that should be done after window is mapped */
176fb687 1081 panel_establish_autohide(p);
a52c2257
HJYP
1082
1083 /* send it to running wm */
1084 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
1085 /* and assign it ourself just for case when wm is not running */
1086 val = 0xFFFFFFFF;
1087 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
1088 PropModeReplace, (unsigned char *) &val, 1);
1089
1090 state[0] = a_NET_WM_STATE_SKIP_PAGER;
1091 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
1092 state[2] = a_NET_WM_STATE_STICKY;
1093 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STATE, XA_ATOM,
1094 32, PropModeReplace, (unsigned char *) state, 3);
1095
a52c2257
HJYP
1096 calculate_position(p);
1097 gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
bee4c26e 1098 panel_set_wm_strut(p);
77886b88 1099
a52c2257
HJYP
1100 RET();
1101}
1102
2918994e 1103/* Exchange the "width" and "height" terminology for vertical and horizontal panels. */
1104void panel_adjust_geometry_terminology(Panel * p)
9dd114c4 1105{
8ed3b3d4 1106 if ((p->height_label != NULL) && (p->width_label != NULL)
1107 && (p->alignment_left_label != NULL) && (p->alignment_right_label != NULL))
9dd114c4 1108 {
1109 if ((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM))
1110 {
1111 gtk_label_set_text(GTK_LABEL(p->height_label), _("Height:"));
1112 gtk_label_set_text(GTK_LABEL(p->width_label), _("Width:"));
2918994e 1113 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Left"));
1114 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Right"));
9dd114c4 1115 }
1116 else
1117 {
1118 gtk_label_set_text(GTK_LABEL(p->height_label), _("Width:"));
1119 gtk_label_set_text(GTK_LABEL(p->width_label), _("Height:"));
2918994e 1120 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Top"));
1121 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Bottom"));
9dd114c4 1122 }
1123 }
1124}
1125
2918994e 1126/* Draw text into a label, with the user preference color and optionally bold. */
3fd2186c
HG
1127void panel_draw_label_text(Panel * p, GtkWidget * label, char * text, gboolean bold,
1128 float custom_size_factor, gboolean custom_color)
2918994e 1129{
2918994e 1130 if (text == NULL)
1131 {
1132 /* Null string. */
1133 gtk_label_set_text(GTK_LABEL(label), NULL);
83d410c1 1134 return;
2918994e 1135 }
1136
83d410c1
HG
1137 /* Compute an appropriate size so the font will scale with the panel's icon size. */
1138 int font_desc;
1139 if (p->usefontsize)
1140 font_desc = p->fontsize;
f669ce5e 1141 else
2918994e 1142 {
83d410c1
HG
1143 if (p->icon_size < 20)
1144 font_desc = 9;
1145 else if (p->icon_size >= 20 && p->icon_size < 36)
1146 font_desc = 10;
1147 else
1148 font_desc = 12;
1149 }
1150 font_desc *= custom_size_factor;
1151
1152 /* Check the string for characters that need to be escaped.
1153 * If any are found, create the properly escaped string and use it instead. */
1154 char * valid_markup = text;
1155 char * escaped_text = NULL;
1156 char * q;
1157 for (q = text; *q != '\0'; q += 1)
1158 {
1159 if ((*q == '<') || (*q == '>') || (*q == '&'))
2918994e 1160 {
83d410c1
HG
1161 escaped_text = g_markup_escape_text(text, -1);
1162 valid_markup = escaped_text;
1163 break;
2918994e 1164 }
83d410c1 1165 }
2918994e 1166
83d410c1
HG
1167 gchar * formatted_text;
1168 if ((custom_color) && (p->usefontcolor))
1169 {
1170 /* Color, optionally bold. */
1171 formatted_text = g_strdup_printf("<span font_desc=\"%d\" color=\"#%06x\">%s%s%s</span>",
f669ce5e 1172 font_desc,
2918994e 1173 gcolor2rgb24(&p->gfontcolor),
1174 ((bold) ? "<b>" : ""),
1175 valid_markup,
1176 ((bold) ? "</b>" : ""));
83d410c1
HG
1177 }
1178 else
1179 {
1180 /* No color, optionally bold. */
1181 formatted_text = g_strdup_printf("<span font_desc=\"%d\">%s%s%s</span>",
f669ce5e 1182 font_desc,
1183 ((bold) ? "<b>" : ""),
1184 valid_markup,
1185 ((bold) ? "</b>" : ""));
2918994e 1186 }
83d410c1
HG
1187
1188 gtk_label_set_markup(GTK_LABEL(label), formatted_text);
1189 g_free(formatted_text);
1190 g_free(escaped_text);
2918994e 1191}
1192
1193void panel_set_panel_configuration_changed(Panel *p)
a97d06a6 1194{
17fab6e5 1195 GList *plugins, *l;
9dd114c4 1196
cfde283a 1197 GtkOrientation previous_orientation = p->orientation;
a97d06a6 1198 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
cfde283a 1199 ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
9dd114c4 1200
cfde283a
AG
1201 /* either first run or orientation was changed */
1202 if (p->my_box_new == NULL || previous_orientation != p->orientation)
9dd114c4 1203 {
1204 panel_adjust_geometry_terminology(p);
f5c7784a
AG
1205 if (p->my_box_new != NULL)
1206 p->height = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? PANEL_HEIGHT_DEFAULT : PANEL_WIDTH_DEFAULT);
9dd114c4 1207 if (p->height_control != NULL)
1208 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->height_control), p->height);
2918994e 1209 if ((p->widthtype == WIDTH_PIXEL) && (p->width_control != NULL))
1210 {
cfde283a 1211 int value = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? gdk_screen_width() : gdk_screen_height());
2918994e 1212 gtk_spin_button_set_range(GTK_SPIN_BUTTON(p->width_control), 0, value);
1213 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->width_control), value);
1214 }
9dd114c4 1215 }
1216
cfde283a 1217 if (p->orientation == GTK_ORIENTATION_HORIZONTAL) {
a97d06a6
HJYP
1218 p->my_box_new = gtk_hbox_new;
1219 p->my_separator_new = gtk_vseparator_new;
1220 } else {
1221 p->my_box_new = gtk_vbox_new;
1222 p->my_separator_new = gtk_hseparator_new;
1223 }
1224
1225 /* recreate the main layout box */
964b8b7e 1226 if (p->box != NULL)
1227 {
cfde283a 1228 gtk_orientable_set_orientation(GTK_ORIENTABLE(p->box), p->orientation);
a97d06a6 1229 }
9dd114c4 1230
a97d06a6
HJYP
1231 /* NOTE: This loop won't be executed when panel started since
1232 plugins are not loaded at that time.
1233 This is used when the orientation of the panel is changed
1234 from the config dialog, and plugins should be re-layout.
1235 */
17fab6e5
AG
1236 plugins = p->box ? gtk_container_get_children(GTK_CONTAINER(p->box)) : NULL;
1237 for( l = plugins; l; l = l->next ) {
1238 GtkWidget *w = (GtkWidget*)l->data;
1239 LXPanelPluginInit *init = PLUGIN_CLASS(w);
1240 if (init->reconfigure)
1241 init->reconfigure(p, w);
a97d06a6 1242 }
17fab6e5 1243 g_list_free(plugins);
a97d06a6
HJYP
1244}
1245
a52c2257 1246static int
17fab6e5 1247panel_parse_global(Panel *p, config_setting_t *cfg)
a52c2257 1248{
4bca3e51
AG
1249 const char *str;
1250 gint i;
6db11841 1251
17fab6e5
AG
1252 /* check Global config */
1253 if (!cfg || strcmp(config_setting_get_name(cfg), "Global") != 0)
3e7b8eb7 1254 {
17fab6e5
AG
1255 ERR( "lxpanel: Global section not found\n");
1256 RET(0);
1257 }
4bca3e51
AG
1258 if (config_setting_lookup_string(cfg, "edge", &str))
1259 p->edge = str2num(edge_pair, str, EDGE_NONE);
1260 if (config_setting_lookup_string(cfg, "allign", &str))
1261 p->allign = str2num(allign_pair, str, ALLIGN_NONE);
1262 config_setting_lookup_int(cfg, "monitor", &p->monitor);
1263 config_setting_lookup_int(cfg, "margin", &p->margin);
1264 if (config_setting_lookup_string(cfg, "widthtype", &str))
1265 p->widthtype = str2num(width_pair, str, WIDTH_NONE);
1266 config_setting_lookup_int(cfg, "width", &p->width);
1267 if (config_setting_lookup_string(cfg, "heighttype", &str))
1268 p->heighttype = str2num(height_pair, str, HEIGHT_NONE);
1269 config_setting_lookup_int(cfg, "height", &p->height);
1270 if (config_setting_lookup_int(cfg, "spacing", &i) && i > 0)
1271 p->spacing = i;
1272 if (config_setting_lookup_int(cfg, "setdocktype", &i))
1273 p->setdocktype = i != 0;
1274 if (config_setting_lookup_int(cfg, "setpartialstrut", &i))
1275 p->setstrut = i != 0;
1276 if (config_setting_lookup_int(cfg, "RoundCorners", &i))
1277 p->round_corners = i != 0;
1278 if (config_setting_lookup_int(cfg, "transparent", &i))
1279 p->transparent = i != 0;
1280 if (config_setting_lookup_int(cfg, "alpha", &p->alpha))
17fab6e5 1281 {
17fab6e5
AG
1282 if (p->alpha > 255)
1283 p->alpha = 255;
1284 }
4bca3e51
AG
1285 if (config_setting_lookup_int(cfg, "autohide", &i))
1286 p->autohide = i != 0;
1287 config_setting_lookup_int(cfg, "heightwhenhidden", &p->height_when_hidden);
1288 if (config_setting_lookup_string(cfg, "tintcolor", &str))
17fab6e5 1289 {
4bca3e51 1290 if (!gdk_color_parse (str, &p->gtintcolor))
17fab6e5
AG
1291 gdk_color_parse ("white", &p->gtintcolor);
1292 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
1293 DBG("tintcolor=%x\n", p->tintcolor);
1294 }
4bca3e51
AG
1295 if (config_setting_lookup_int(cfg, "usefontcolor", &i))
1296 p->usefontcolor = i != 0;
1297 if (config_setting_lookup_string(cfg, "fontcolor", &str))
17fab6e5 1298 {
4bca3e51 1299 if (!gdk_color_parse (str, &p->gfontcolor))
17fab6e5
AG
1300 gdk_color_parse ("black", &p->gfontcolor);
1301 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
1302 DBG("fontcolor=%x\n", p->fontcolor);
1303 }
4bca3e51
AG
1304 if (config_setting_lookup_int(cfg, "usefontsize", &i))
1305 p->usefontsize = i != 0;
1306 if (config_setting_lookup_int(cfg, "fontsize", &i) && i > 0)
1307 p->fontsize = i;
1308 if (config_setting_lookup_int(cfg, "background", &i))
1309 p->background = i != 0;
1310 if (config_setting_lookup_string(cfg, "backgroundfile", &str))
1311 p->background_file = g_strdup(str);
1312 config_setting_lookup_int(cfg, "iconsize", &p->icon_size);
1313 if (config_setting_lookup_int(cfg, "loglevel", &configured_log_level))
17fab6e5 1314 {
17fab6e5
AG
1315 if (!log_level_set_on_commandline)
1316 log_level = configured_log_level;
a52c2257 1317 }
4542c20d 1318
9dd114c4 1319 panel_normalize_configuration(p);
239cb032 1320
9dd114c4 1321 return 1;
a52c2257
HJYP
1322}
1323
1324static int
17fab6e5 1325panel_parse_plugin(Panel *p, config_setting_t *cfg)
a52c2257 1326{
4bca3e51 1327 const char *type = NULL;
db449f6e 1328
a52c2257 1329 ENTER;
4bca3e51 1330 config_setting_lookup_string(cfg, "type", &type);
17fab6e5 1331 DBG("plug %s\n", type);
db449f6e 1332
17fab6e5 1333 if (!type || lxpanel_add_plugin(p, type, cfg, -1) == NULL) {
a52c2257
HJYP
1334 ERR( "lxpanel: can't load %s plugin\n", type);
1335 goto error;
1336 }
a52c2257 1337 RET(1);
db449f6e 1338
17fab6e5 1339error:
a52c2257 1340 RET(0);
a52c2257
HJYP
1341}
1342
17fab6e5 1343int panel_start( Panel *p )
a52c2257 1344{
17fab6e5
AG
1345 config_setting_t *list, *s;
1346 int i;
db449f6e 1347
a52c2257
HJYP
1348 /* parse global section */
1349 ENTER;
8110399f 1350
17fab6e5
AG
1351 list = config_setting_get_member(config_root_setting(p->config), "");
1352 if (!list || !panel_parse_global(p, config_setting_get_elem(list, 0)))
a52c2257
HJYP
1353 RET(0);
1354
9dd114c4 1355 panel_start_gui(p);
1356
17fab6e5
AG
1357 for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
1358 if (strcmp(config_setting_get_name(s), "Plugin") == 0 &&
1359 panel_parse_plugin(p, s)) /* success on plugin start */
1360 i++;
1361 else /* remove invalid data from config */
1362 config_setting_remove_elem(list, i);
4542c20d
HJYP
1363
1364 /* update backgrond of panel and all plugins */
1365 panel_update_background( p );
9dd114c4 1366 return 1;
a52c2257
HJYP
1367}
1368
8110399f 1369void panel_destroy(Panel *p)
a52c2257
HJYP
1370{
1371 ENTER;
1372
2918994e 1373 if (p->pref_dialog != NULL)
1374 gtk_widget_destroy(p->pref_dialog);
1375 if (p->plugin_pref_dialog != NULL)
4ab8027b
AG
1376 /* just close the dialog, it will do all required cleanup */
1377 gtk_dialog_response(GTK_DIALOG(p->plugin_pref_dialog), GTK_RESPONSE_CLOSE);
2918994e 1378
1379 if (p->bg != NULL)
1380 {
1381 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, p);
1382 g_object_unref(p->bg);
1383 }
1384
930af9fd
HJYP
1385 if( p->config_changed )
1386 panel_config_save( p );
17fab6e5 1387 config_destroy(p->config);
8c44345a 1388
4b93d81e 1389 if( p->topgwin )
17fab6e5
AG
1390 {
1391 gtk_window_group_remove_window( win_grp, GTK_WINDOW( p->topgwin ) );
4b93d81e 1392 gtk_widget_destroy(p->topgwin);
17fab6e5 1393 }
a52c2257 1394 g_free(p->workarea);
2de71c90 1395 g_free( p->background_file );
5297da29 1396 g_slist_free( p->system_menus );
a52c2257
HJYP
1397 gdk_flush();
1398 XFlush(GDK_DISPLAY());
1399 XSync(GDK_DISPLAY(), True);
8110399f
HJYP
1400
1401 g_free( p->name );
2918994e 1402 g_free(p);
a52c2257
HJYP
1403 RET();
1404}
1405
8110399f
HJYP
1406Panel* panel_new( const char* config_file, const char* config_name )
1407{
cf701cb7 1408 Panel* panel = NULL;
16fbda14 1409
17fab6e5 1410 if (G_LIKELY(config_file))
cf701cb7 1411 {
17fab6e5 1412 panel = panel_allocate();
20edd661 1413 panel->name = g_strdup(config_name);
17fab6e5
AG
1414 g_debug("starting panel from file %s",config_file);
1415 if (!config_read_file(panel->config, config_file) ||
1416 !panel_start(panel))
3e7b8eb7 1417 {
17fab6e5
AG
1418 ERR( "lxpanel: can't start panel\n");
1419 panel_destroy( panel );
1420 panel = NULL;
cf701cb7 1421 }
cf701cb7
HJYP
1422 }
1423 return panel;
8110399f 1424}
a52c2257 1425
0defe4b9 1426static void
a52c2257
HJYP
1427usage()
1428{
e7cb732b
HJYP
1429 g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
1430 g_print(_("Command line options:\n"));
1431 g_print(_(" --help -- print this help and exit\n"));
1432 g_print(_(" --version -- print version and exit\n"));
1433 g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
2918994e 1434// g_print(_(" --configure -- launch configuration utility\n"));
e7cb732b
HJYP
1435 g_print(_(" --profile name -- use specified profile\n"));
1436 g_print("\n");
1437 g_print(_(" -h -- same as --help\n"));
1438 g_print(_(" -p -- same as --profile\n"));
1439 g_print(_(" -v -- same as --version\n"));
2918994e 1440 // g_print(_(" -C -- same as --configure\n"));
b37c9aae 1441 g_print(_("\nVisit http://lxde.org/ for detail.\n\n"));
a52c2257
HJYP
1442}
1443
2918994e 1444int panel_handle_x_error(Display * d, XErrorEvent * ev)
a52c2257
HJYP
1445{
1446 char buf[256];
1447
a52c2257
HJYP
1448 if (log_level >= LOG_WARN) {
1449 XGetErrorText(GDK_DISPLAY(), ev->error_code, buf, 256);
1450 LOG(LOG_WARN, "lxpanel : X error: %s\n", buf);
1451 }
2918994e 1452 return 0; /* Ignored */
1453}
1454
1455int panel_handle_x_error_swallow_BadWindow_BadDrawable(Display * d, XErrorEvent * ev)
1456{
1457 if ((ev->error_code != BadWindow) && (ev->error_code != BadDrawable))
1458 panel_handle_x_error(d, ev);
1459 return 0; /* Ignored */
a52c2257
HJYP
1460}
1461
e68b47dc
JH
1462/* Lightweight lock related functions - X clipboard hacks */
1463
1464#define CLIPBOARD_NAME "LXPANEL_SELECTION"
1465
1466/*
1467 * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
1468 */
1469static void
1470clipboard_get_func(
1471 GtkClipboard *clipboard G_GNUC_UNUSED,
1472 GtkSelectionData *selection_data G_GNUC_UNUSED,
1473 guint info G_GNUC_UNUSED,
1474 gpointer user_data_or_owner G_GNUC_UNUSED)
1475{
1476}
1477
1478/*
1479 * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
1480 */
1481static void clipboard_clear_func(
1482 GtkClipboard *clipboard G_GNUC_UNUSED,
1483 gpointer user_data_or_owner G_GNUC_UNUSED)
1484{
1485}
1486
1487/*
1488 * Lightweight version for checking single instance.
1489 * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
1490 *
1491 * Returns TRUE if successfully retrieved and FALSE otherwise.
1492 */
16fb8c2e 1493static gboolean check_main_lock()
e68b47dc
JH
1494{
1495 static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
1496 gboolean retval = FALSE;
1497 GtkClipboard *clipboard;
1498 Atom atom;
1499
1500 atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
1501
1502 XGrabServer(GDK_DISPLAY());
1503
1504 if (XGetSelectionOwner(GDK_DISPLAY(), atom) != None)
1505 goto out;
1506
1507 clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
1508
1509 if (gtk_clipboard_set_with_data(clipboard, targets,
1510 G_N_ELEMENTS (targets),
1511 clipboard_get_func,
1512 clipboard_clear_func, NULL))
1513 retval = TRUE;
1514
1515out:
1516 XUngrabServer (GDK_DISPLAY ());
1517 gdk_flush ();
1518
1519 return retval;
1520}
1521#undef CLIPBOARD_NAME
1522
8110399f
HJYP
1523static gboolean start_all_panels( )
1524{
cf701cb7 1525 gboolean is_global;
4b93d81e 1526 for( is_global = 0; ! all_panels && is_global < 2; ++is_global )
cf701cb7
HJYP
1527 {
1528 char* panel_dir = get_config_file( cprofile, "panels", is_global );
1529 GDir* dir = g_dir_open( panel_dir, 0, NULL );
e3b89f43 1530 const gchar* name;
cf701cb7
HJYP
1531
1532 if( ! dir )
1533 {
1534 g_free( panel_dir );
1535 continue;
1536 }
1537
547ece89 1538 while((name = g_dir_read_name(dir)) != NULL)
cf701cb7
HJYP
1539 {
1540 char* panel_config = g_build_filename( panel_dir, name, NULL );
2918994e 1541 if (strchr(panel_config, '~') == NULL) /* Skip editor backup files in case user has hand edited in this directory */
1542 {
1543 Panel* panel = panel_new( panel_config, name );
1544 if( panel )
1545 all_panels = g_slist_prepend( all_panels, panel );
1546 }
cf701cb7
HJYP
1547 g_free( panel_config );
1548 }
1549 g_dir_close( dir );
1550 g_free( panel_dir );
1551 }
1552 return all_panels != NULL;
8110399f
HJYP
1553}
1554
cf701cb7
HJYP
1555void load_global_config();
1556void free_global_config();
1557
8110399f 1558int main(int argc, char *argv[], char *env[])
a52c2257
HJYP
1559{
1560 int i;
9df6826f 1561 const char* desktop_name;
f277dbb7 1562
a52c2257 1563 setlocale(LC_CTYPE, "");
f277dbb7 1564
1d434622 1565 g_thread_init(NULL);
74bf5dbf
AG
1566/* gdk_threads_init();
1567 gdk_threads_enter(); */
1d434622 1568
a52c2257
HJYP
1569 gtk_init(&argc, &argv);
1570
1571#ifdef ENABLE_NLS
1572 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
1573 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
1574 textdomain ( GETTEXT_PACKAGE );
1575#endif
1576
1577 XSetLocaleModifiers("");
2918994e 1578 XSetErrorHandler((XErrorHandler) panel_handle_x_error);
8110399f 1579
a52c2257 1580 resolve_atoms();
8110399f 1581
9df6826f
HJYP
1582 desktop_name = g_getenv("XDG_CURRENT_DESKTOP");
1583 is_in_lxde = desktop_name && (0 == strcmp(desktop_name, "LXDE"));
95095259 1584
a52c2257
HJYP
1585 for (i = 1; i < argc; i++) {
1586 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
1587 usage();
1588 exit(0);
1589 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
1590 printf("lxpanel %s\n", version);
1591 exit(0);
1592 } else if (!strcmp(argv[i], "--log")) {
1593 i++;
1594 if (i == argc) {
1595 ERR( "lxpanel: missing log level\n");
1596 usage();
1597 exit(1);
1598 } else {
1599 log_level = atoi(argv[i]);
82ca42af 1600 log_level_set_on_commandline = true;
a52c2257
HJYP
1601 }
1602 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
1603 config = 1;
1604 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
1605 i++;
1606 if (i == argc) {
1607 ERR( "lxpanel: missing profile name\n");
1608 usage();
1609 exit(1);
1610 } else {
1611 cprofile = g_strdup(argv[i]);
1612 }
1613 } else {
1614 printf("lxpanel: unknown option - %s\n", argv[i]);
1615 usage();
1616 exit(1);
1617 }
1618 }
f277dbb7 1619
8110399f 1620 /* Check for duplicated lxpanel instances */
e68b47dc 1621 if (!check_main_lock() && !config) {
e7a42ecf 1622 printf("There is already an instance of LXPanel. Now to exit\n");
e68b47dc
JH
1623 exit(1);
1624 }
1625
730e3f7b
JL
1626 /* Add our own icons to the search path of icon theme */
1627 gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(), PACKAGE_DATA_DIR "/lxpanel/images" );
1628
cf701cb7 1629 fbev = fb_ev_new();
e2957bd2 1630 win_grp = gtk_window_group_new();
22242ed4 1631
f7cb330e
HJYP
1632restart:
1633 is_restarting = FALSE;
1634
17fab6e5
AG
1635 /* init LibFM */
1636 fm_gtk_init(NULL);
1637
1638 /* prepare modules data */
1639 _prepare_modules();
1640
cf701cb7
HJYP
1641 load_global_config();
1642
1d9dc649
HJYP
1643 /* NOTE: StructureNotifyMask is required by XRandR
1644 * See init_randr_support() in gdkscreen-x11.c of gtk+ for detail.
1645 */
0f83fb71 1646 gdk_window_set_events(gdk_get_default_root_window(), GDK_STRUCTURE_MASK |
1647 GDK_SUBSTRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK);
cf701cb7 1648 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
8110399f 1649
cf701cb7
HJYP
1650 if( G_UNLIKELY( ! start_all_panels() ) )
1651 g_warning( "Config files are not found.\n" );
8110399f
HJYP
1652/*
1653 * FIXME: configure??
6a6ad54e
HJYP
1654 if (config)
1655 configure();
8110399f 1656*/
6a6ad54e 1657 gtk_main();
8110399f 1658
cf701cb7
HJYP
1659 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), NoEventMask);
1660 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1661
8110399f
HJYP
1662 /* destroy all panels */
1663 g_slist_foreach( all_panels, (GFunc) panel_destroy, NULL );
2a26c0d8
HJYP
1664 g_slist_free( all_panels );
1665 all_panels = NULL;
6a6ad54e 1666 g_free( cfgfile );
5541b8d2 1667
cf701cb7
HJYP
1668 free_global_config();
1669
17fab6e5
AG
1670 _unload_modules();
1671 fm_gtk_finalize();
1672
f7cb330e
HJYP
1673 if( is_restarting )
1674 goto restart;
1675
74bf5dbf 1676 /* gdk_threads_leave(); */
3e71f8af 1677
e2957bd2 1678 g_object_unref(win_grp);
22242ed4
HJYP
1679 g_object_unref(fbev);
1680
5541b8d2 1681 return 0;
a52c2257 1682}
9c338caf 1683
cfde283a 1684extern GtkOrientation panel_get_orientation(Panel *panel)
9c338caf 1685{
cfde283a 1686 return panel->orientation;
9c338caf
AG
1687}
1688
1689extern gint panel_get_icon_size(Panel *panel)
1690{
1691 return panel->icon_size;
1692}
1693
1694extern gint panel_get_height(Panel *panel)
1695{
1696 return panel->height;
1697}
1698
1699extern GtkWindow *panel_get_toplevel_window(Panel *panel)
1700{
4ab8027b 1701 return GTK_WINDOW(panel->topgwin);
9c338caf
AG
1702}
1703
1704extern GtkStyle *panel_get_defstyle(Panel *panel)
1705{
1706 return panel->defstyle;
1707}
1708
1709extern GtkIconTheme *panel_get_icon_theme(Panel *panel)
1710{
1711 return panel->icon_theme;
1712}
1713
1714extern GtkWidget *panel_box_new(Panel *panel, gboolean homogeneous, gint spacing)
1715{
1716 return panel->my_box_new(homogeneous, spacing);
1717}
1718
1719extern GtkWidget *panel_separator_new(Panel *panel)
1720{
1721 return panel->my_separator_new();
1722}
10d93053
AG
1723
1724gboolean _class_is_present(LXPanelPluginInit *init)
1725{
1726 GSList *sl;
1727
1728 for (sl = all_panels; sl; sl = sl->next )
1729 {
1730 Panel *panel = (Panel*)sl->data;
1731 GList *plugins, *p;
1732
1733 plugins = gtk_container_get_children(GTK_CONTAINER(panel->box));
1734 for (p = plugins; p; p = p->next)
1735 if (PLUGIN_CLASS(p->data) == init)
1736 {
1737 g_list_free(plugins);
1738 return TRUE;
1739 }
1740 g_list_free(plugins);
1741 }
1742 return FALSE;
1743}