Use PACKAGE_DATA_DIR as $(datadir)/lxpanel, not equal to $(datadir)
[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 Panel *panel = PLUGIN_PANEL(plugin);
566
131514c9 567 lxpanel_plugin_show_config_dialog(panel, plugin);
930af9fd
HJYP
568
569 /* FIXME: this should be more elegant */
17fab6e5 570 panel->config_changed = TRUE;
cf701cb7
HJYP
571}
572
4b93d81e
HJYP
573static void panel_popupmenu_add_item( GtkMenuItem* item, Panel* panel )
574{
575 /* panel_add_plugin( panel, panel->topgwin ); */
8d8b66da 576 panel_configure( panel, 2 );
cf701cb7
HJYP
577}
578
17fab6e5 579static void panel_popupmenu_remove_item( GtkMenuItem* item, GtkWidget* plugin )
cf701cb7 580{
17fab6e5 581 Panel* panel = PLUGIN_PANEL(plugin);
b7e8ad02
MJ
582
583 /* If the configuration dialog is open, there will certainly be a crash if the
584 * user manipulates the Configured Plugins list, after we remove this entry.
585 * Close the configuration dialog if it is open. */
586 if (panel->pref_dialog != NULL)
587 {
588 gtk_widget_destroy(panel->pref_dialog);
589 panel->pref_dialog = NULL;
590 }
17fab6e5
AG
591 config_setting_destroy(g_object_get_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf));
592 /* reset conf pointer because the widget still may be referenced by configurator */
593 g_object_set_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf, NULL);
b7e8ad02 594
17fab6e5
AG
595 panel_config_save(panel);
596 gtk_widget_destroy(plugin);
cf701cb7
HJYP
597}
598
3e7b8eb7
HJYP
599/* FIXME: Potentially we can support multiple panels at the same edge,
600 * but currently this cannot be done due to some positioning problems. */
64afc832 601static char* gen_panel_name( int edge, gint monitor )
3e7b8eb7
HJYP
602{
603 const char* edge_str = num2str( edge_pair, edge, "" );
604 char* name = NULL;
605 char* dir = get_config_file( cprofile, "panels", FALSE );
606 int i;
607 for( i = 0; i < G_MAXINT; ++i )
608 {
609 char* f;
64afc832
R
610 if(monitor != 0)
611 name = g_strdup_printf( "%s-m%d-%d", edge_str, monitor, i );
612 else if( G_LIKELY( i > 0 ) )
3e7b8eb7
HJYP
613 name = g_strdup_printf( "%s%d", edge_str, i );
614 else
615 name = g_strdup( edge_str );
64afc832 616
3e7b8eb7
HJYP
617 f = g_build_filename( dir, name, NULL );
618 if( ! g_file_test( f, G_FILE_TEST_EXISTS ) )
619 {
620 g_free( f );
621 break;
622 }
623 g_free( name );
624 g_free( f );
625 }
626 g_free( dir );
627 return name;
628}
629
630/* FIXME: Potentially we can support multiple panels at the same edge,
631 * but currently this cannot be done due to some positioning problems. */
cf701cb7
HJYP
632static void panel_popupmenu_create_panel( GtkMenuItem* item, Panel* panel )
633{
64afc832
R
634 gint m, e, monitors;
635 GdkScreen *screen;
636 GtkWidget *err;
9dd114c4 637 Panel* new_panel = panel_allocate();
638
639 /* Allocate the edge. */
64afc832
R
640 screen = gdk_screen_get_default();
641 g_assert(screen);
642 monitors = gdk_screen_get_n_monitors(screen);
643 for(m=0; m<monitors; ++m)
644 {
645 /* try each of the four edges */
646 for(e=1; e<5; ++e)
647 {
648 if(panel_edge_available(new_panel,e,m)) {
649 new_panel->edge = e;
650 new_panel->monitor = m;
651 goto found_edge;
652 }
653 }
654 }
655
17fab6e5 656 panel_destroy(new_panel);
64afc832
R
657 ERR("Error adding panel: There is no room for another panel. All the edges are taken.\n");
658 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."));
659 gtk_dialog_run(GTK_DIALOG(err));
660 gtk_widget_destroy(err);
661 return;
662
663found_edge:
664 new_panel->name = gen_panel_name(new_panel->edge,new_panel->monitor);
9dd114c4 665
17fab6e5 666 /* create new config with first group "Global" */
a8d4af54 667 config_group_add_subgroup(config_root_setting(new_panel->config), "Global");
9dd114c4 668 panel_configure(new_panel, 0);
669 panel_normalize_configuration(new_panel);
670 panel_start_gui(new_panel);
671 gtk_widget_show_all(new_panel->topgwin);
672
673 panel_config_save(new_panel);
674 all_panels = g_slist_prepend(all_panels, new_panel);
cf701cb7
HJYP
675}
676
677static void panel_popupmenu_delete_panel( GtkMenuItem* item, Panel* panel )
678{
679 GtkWidget* dlg;
680 gboolean ok;
e3b89f43 681 dlg = gtk_message_dialog_new_with_markup( GTK_WINDOW(panel->topgwin),
cf701cb7
HJYP
682 GTK_DIALOG_MODAL,
683 GTK_MESSAGE_QUESTION,
684 GTK_BUTTONS_OK_CANCEL,
685 _("Really delete this panel?\n<b>Warning: This can not be recovered.</b>") );
d1d43629 686 panel_apply_icon(GTK_WINDOW(dlg));
cf701cb7
HJYP
687 gtk_window_set_title( (GtkWindow*)dlg, _("Confirm") );
688 ok = ( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK );
689 gtk_widget_destroy( dlg );
690 if( ok )
691 {
4b93d81e 692 gchar *fname, *dir;
cf701cb7 693 all_panels = g_slist_remove( all_panels, panel );
4b93d81e
HJYP
694
695 /* delete the config file of this panel */
696 dir = get_config_file( cprofile, "panels", FALSE );
697 fname = g_build_filename( dir, panel->name, NULL );
698 g_free( dir );
699 g_unlink( fname );
930af9fd 700 panel->config_changed = 0;
cf701cb7
HJYP
701 panel_destroy( panel );
702 }
703}
704
e7a42ecf 705static void panel_popupmenu_about( GtkMenuItem* item, Panel* panel )
706{
707 GtkWidget *about;
708 const gchar* authors[] = {
709 "Hong Jen Yee (PCMan) <pcman.tw@gmail.com>",
710 "Jim Huang <jserv.tw@gmail.com>",
711 "Greg McNew <gmcnew@gmail.com> (battery plugin)",
712 "Fred Chien <cfsghost@gmail.com>",
713 "Daniel Kesler <kesler.daniel@gmail.com>",
714 "Juergen Hoetzel <juergen@archlinux.org>",
2918994e 715 "Marty Jack <martyj19@comcast.net>",
815e1027 716 "Martin Bagge <brother@bsnet.se>",
e7a42ecf 717 NULL
718 };
719 /* TRANSLATORS: Replace this string with your names, one name per line. */
720 gchar *translators = _( "translator-credits" );
721
722 about = gtk_about_dialog_new();
723 panel_apply_icon(GTK_WINDOW(about));
724 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), VERSION);
725 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), _("LXPanel"));
4c91be3e
JL
726
727 if(gtk_icon_theme_has_icon(panel->icon_theme, "video-display"))
728 {
729 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
730 gtk_icon_theme_load_icon(panel->icon_theme, "video-display", 48, 0, NULL));
731 }
732 else if (gtk_icon_theme_has_icon(panel->icon_theme, "start-here"))
733 {
734 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
735 gtk_icon_theme_load_icon(panel->icon_theme, "start-here", 48, 0, NULL));
736 }
737 else
738 {
739 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
0b806437 740 gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL));
4c91be3e
JL
741 }
742
d111d2b8 743 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about), _("Copyright (C) 2008-2013"));
e7a42ecf 744 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), _( "Desktop panel for LXDE project"));
745 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.");
746 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://lxde.org/");
747 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about), authors);
748 gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about), translators);
749 gtk_dialog_run(GTK_DIALOG(about));
750 gtk_widget_destroy(about);
751}
752
753void panel_apply_icon( GtkWindow *w )
754{
d60c9372
MR
755 GdkPixbuf* window_icon;
756
4c91be3e
JL
757 if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "video-display"))
758 {
3ad38785 759 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "video-display", 24, 0, NULL);
d60c9372 760 }
4c91be3e
JL
761 else if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "start-here"))
762 {
763 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "start-here", 24, 0, NULL);
89496346
JL
764 }
765 else
4c91be3e 766 {
0b806437 767 window_icon = gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL);
d60c9372 768 }
21f91705 769 gtk_window_set_icon(w, window_icon);
e7a42ecf 770}
771
17fab6e5 772GtkMenu* lxpanel_get_plugin_menu( Panel* panel, GtkWidget* plugin, gboolean use_sub_menu )
cf701cb7 773{
e3b89f43 774 GtkWidget *menu_item, *img;
775 GtkMenu *ret,*menu;
e56f2fdd 776 LXPanelPluginInit *init;
cf701cb7 777 char* tmp;
e3b89f43 778 ret = menu = GTK_MENU(gtk_menu_new());
cf701cb7 779
4b93d81e
HJYP
780 img = gtk_image_new_from_stock( GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU );
781 menu_item = gtk_image_menu_item_new_with_label(_("Add / Remove Panel Items"));
782 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
783 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
784 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
cf701cb7
HJYP
785
786 if( plugin )
787 {
e56f2fdd 788 init = PLUGIN_CLASS(plugin);
cf701cb7 789 img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
17fab6e5 790 tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(init->name) );
cf701cb7
HJYP
791 menu_item = gtk_image_menu_item_new_with_label( tmp );
792 g_free( tmp );
793 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
794 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
795 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_remove_item), plugin );
796 }
797
798 menu_item = gtk_separator_menu_item_new();
799 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
800
4b93d81e
HJYP
801 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
802 menu_item = gtk_image_menu_item_new_with_label(_("Panel Settings"));
803 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
804 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
805 g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_popupmenu_configure), panel );
806
cf701cb7
HJYP
807 img = gtk_image_new_from_stock( GTK_STOCK_NEW, GTK_ICON_SIZE_MENU );
808 menu_item = gtk_image_menu_item_new_with_label(_("Create New Panel"));
809 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
810 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
811 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_create_panel), panel );
812
813 img = gtk_image_new_from_stock( GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU );
814 menu_item = gtk_image_menu_item_new_with_label(_("Delete This Panel"));
815 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
816 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
817 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_delete_panel), panel );
818 if( ! all_panels->next ) /* if this is the only panel */
819 gtk_widget_set_sensitive( menu_item, FALSE );
820
e7a42ecf 821 menu_item = gtk_separator_menu_item_new();
822 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
823
824 img = gtk_image_new_from_stock( GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU );
825 menu_item = gtk_image_menu_item_new_with_label(_("About"));
826 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
827 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
828 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_about), panel );
829
cf701cb7
HJYP
830 if( use_sub_menu )
831 {
e3b89f43 832 ret = GTK_MENU(gtk_menu_new());
cf701cb7
HJYP
833 menu_item = gtk_image_menu_item_new_with_label(_("Panel"));
834 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
e3b89f43 835 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), GTK_WIDGET(menu) );
cf701cb7 836
e3b89f43 837 gtk_widget_show_all(GTK_WIDGET(ret));
cf701cb7
HJYP
838 }
839
3e7b8eb7
HJYP
840 if( plugin )
841 {
842 menu_item = gtk_separator_menu_item_new();
843 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
844
845 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
17fab6e5 846 tmp = g_strdup_printf( _("\"%s\" Settings"), _(init->name) );
3e7b8eb7
HJYP
847 menu_item = gtk_image_menu_item_new_with_label( tmp );
848 g_free( tmp );
849 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
850 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
17fab6e5 851 if( init->config )
3e7b8eb7
HJYP
852 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
853 else
854 gtk_widget_set_sensitive( menu_item, FALSE );
855 }
856
e3b89f43 857 gtk_widget_show_all(GTK_WIDGET(menu));
3e7b8eb7 858
cf701cb7
HJYP
859 g_signal_connect( ret, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
860 return ret;
861}
862
17fab6e5
AG
863/* for old plugins compatibility */
864GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
865{
866 return lxpanel_get_plugin_menu(panel, plugin->pwid, use_sub_menu);
867}
868
a52c2257
HJYP
869/****************************************************
870 * panel creation *
871 ****************************************************/
176fb687 872
a52c2257 873static void
22242ed4 874make_round_corners(Panel *p)
a52c2257 875{
a97d06a6 876 /* FIXME: This should be re-written with shape extension of X11 */
4542c20d 877 /* gdk_window_shape_combine_mask() can be used */
bee4c26e
HJYP
878}
879
22242ed4 880void panel_set_dock_type(Panel *p)
bee4c26e
HJYP
881{
882 if (p->setdocktype) {
883 Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
884 XChangeProperty(GDK_DISPLAY(), p->topxwin,
885 a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
886 PropModeReplace, (unsigned char *) &state, 1);
887 }
888 else {
889 XDeleteProperty( GDK_DISPLAY(), p->topxwin, a_NET_WM_WINDOW_TYPE );
890 }
a52c2257
HJYP
891}
892
176fb687 893static void panel_set_visibility(Panel *p, gboolean visible)
894{
895 if ( ! visible) gtk_widget_hide(p->box);
896 p->visible = visible;
897 calculate_position(p);
898 gtk_widget_set_size_request(p->topgwin, p->aw, p->ah);
899 gdk_window_move(p->topgwin->window, p->ax, p->ay);
900 if (visible) gtk_widget_show(p->box);
901 panel_set_wm_strut(p);
902}
903
904static gboolean panel_leave_real(Panel *p)
905{
fab48ed0 906 /* If the pointer is grabbed by this application, leave the panel displayed.
907 * There is no way to determine if it is grabbed by another application, such as an application that has a systray icon. */
176fb687 908 if (gdk_display_pointer_is_grabbed(p->display))
909 return TRUE;
910
fab48ed0 911 /* If the pointer is inside the panel, leave the panel displayed. */
176fb687 912 gint x, y;
913 gdk_display_get_pointer(p->display, NULL, &x, &y, NULL);
914 if ((p->cx <= x) && (x <= (p->cx + p->cw)) && (p->cy <= y) && (y <= (p->cy + p->ch)))
915 return TRUE;
916
fab48ed0 917 /* If the panel is configured to autohide and if it is visible, hide the panel. */
176fb687 918 if ((p->autohide) && (p->visible))
919 panel_set_visibility(p, FALSE);
920
fab48ed0 921 /* Clear the timer. */
176fb687 922 p->hide_timeout = 0;
923 return FALSE;
924}
925
926static gboolean panel_enter(GtkImage *widget, GdkEventCrossing *event, Panel *p)
927{
fab48ed0 928 /* We may receive multiple enter-notify events when the pointer crosses into the panel.
929 * Do extra tests to make sure this does not cause misoperation such as blinking.
930 * If the pointer is inside the panel, unhide it. */
931 gint x, y;
932 gdk_display_get_pointer(p->display, NULL, &x, &y, NULL);
933 if ((p->cx <= x) && (x <= (p->cx + p->cw)) && (p->cy <= y) && (y <= (p->cy + p->ch)))
934 {
935 /* If the pointer is inside the panel and we have not already unhidden it, do so and
936 * set a timer to recheck it in a half second. */
937 if (p->hide_timeout == 0)
938 {
939 p->hide_timeout = g_timeout_add(500, (GSourceFunc) panel_leave_real, p);
940 panel_set_visibility(p, TRUE);
941 }
942 }
943 else
944 {
945 /* If the pointer is not inside the panel, simulate a timer expiration. */
946 panel_leave_real(p);
947 }
176fb687 948 return TRUE;
949}
950
951static gboolean panel_drag_motion(GtkWidget *widget, GdkDragContext *drag_context, gint x,
952 gint y, guint time, Panel *p)
953{
954 panel_enter(NULL, NULL, p);
955 return TRUE;
956}
957
958void panel_establish_autohide(Panel *p)
959{
960 if (p->autohide)
961 {
962 gtk_widget_add_events(p->topgwin, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
963 g_signal_connect(G_OBJECT(p->topgwin), "enter-notify-event", G_CALLBACK(panel_enter), p);
964 g_signal_connect(G_OBJECT(p->topgwin), "drag-motion", (GCallback) panel_drag_motion, p);
965 gtk_drag_dest_set(p->topgwin, GTK_DEST_DEFAULT_MOTION, NULL, 0, 0);
966 gtk_drag_dest_set_track_motion(p->topgwin, TRUE);
967 panel_enter(NULL, NULL, p);
968 }
969 else if ( ! p->visible)
970 {
971 gtk_widget_show(p->box);
972 p->visible = TRUE;
973 }
974}
975
8f9e6256 976/* Set an image from a file with scaling to the panel icon size. */
fcb35553 977void panel_image_set_from_file(Panel * p, GtkWidget * image, const char * file)
8f9e6256 978{
979 GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file_at_scale(file, p->icon_size, p->icon_size, TRUE, NULL);
980 if (pixbuf != NULL)
981 {
982 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
983 g_object_unref(pixbuf);
984 }
985}
986
c14620f2
MJ
987/* Set an image from a icon theme with scaling to the panel icon size. */
988gboolean panel_image_set_icon_theme(Panel * p, GtkWidget * image, const gchar * icon)
989{
1b532bce 990 if (gtk_icon_theme_has_icon(p->icon_theme, icon))
c14620f2 991 {
1b532bce 992 GdkPixbuf * pixbuf = gtk_icon_theme_load_icon(p->icon_theme, icon, p->icon_size, 0, NULL);
c14620f2
MJ
993 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
994 g_object_unref(pixbuf);
995 return TRUE;
996 }
997 return FALSE;
998}
999
0defe4b9 1000static void
22242ed4 1001panel_start_gui(Panel *p)
a52c2257
HJYP
1002{
1003 Atom state[3];
1004 XWMHints wmhints;
1005 guint32 val;
6db11841 1006
a52c2257
HJYP
1007 ENTER;
1008
9dd114c4 1009 p->curdesk = get_net_current_desktop();
1010 p->desknum = get_net_number_of_desktops();
1011 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
1012
cb22c87c
HJYP
1013 /* main toplevel window */
1014 /* p->topgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); */
1015 p->topgwin = (GtkWidget*)g_object_new(PANEL_TOPLEVEL_TYPE, NULL);
1016 gtk_widget_set_name(p->topgwin, "PanelToplevel");
176fb687 1017 p->display = gdk_display_get_default();
a52c2257
HJYP
1018 gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
1019 gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
1020 gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "lxpanel");
1021 gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
1022 gtk_window_set_position(GTK_WINDOW(p->topgwin), GTK_WIN_POS_NONE);
1023 gtk_window_set_decorated(GTK_WINDOW(p->topgwin), FALSE);
77886b88 1024
e2957bd2
HJYP
1025 gtk_window_group_add_window( win_grp, (GtkWindow*)p->topgwin );
1026
a52c2257
HJYP
1027 g_signal_connect(G_OBJECT(p->topgwin), "delete-event",
1028 G_CALLBACK(panel_delete_event), p);
1029 g_signal_connect(G_OBJECT(p->topgwin), "destroy-event",
1030 G_CALLBACK(panel_destroy_event), p);
1031 g_signal_connect (G_OBJECT (p->topgwin), "size-request",
1032 (GCallback) panel_size_req, p);
1033 g_signal_connect (G_OBJECT (p->topgwin), "size-allocate",
1034 (GCallback) panel_size_alloc, p);
1035 g_signal_connect (G_OBJECT (p->topgwin), "configure-event",
1036 (GCallback) panel_configure_event, p);
3e7b8eb7
HJYP
1037
1038 gtk_widget_add_events( p->topgwin, GDK_BUTTON_PRESS_MASK );
8e05828e 1039 g_signal_connect(G_OBJECT (p->topgwin), "button-press-event",
9dd114c4 1040 (GCallback) panel_button_press_event_with_panel, p);
f2d54481 1041
a52c2257
HJYP
1042 g_signal_connect (G_OBJECT (p->topgwin), "realize",
1043 (GCallback) panel_realize, p);
f2d54481 1044
84fc1d55
HJYP
1045 g_signal_connect (G_OBJECT (p->topgwin), "style-set",
1046 (GCallback)panel_style_set, p);
a52c2257
HJYP
1047 gtk_widget_realize(p->topgwin);
1048 //gdk_window_set_decorations(p->topgwin->window, 0);
2de71c90 1049
4542c20d 1050 // main layout manager as a single child of panel
a97d06a6 1051 p->box = p->my_box_new(FALSE, 0);
a52c2257 1052 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
4542c20d
HJYP
1053// gtk_container_add(GTK_CONTAINER(p->bbox), p->box);
1054 gtk_container_add(GTK_CONTAINER(p->topgwin), p->box);
a52c2257 1055 gtk_widget_show(p->box);
a97d06a6
HJYP
1056 if (p->round_corners)
1057 make_round_corners(p);
6db11841 1058
a52c2257
HJYP
1059 p->topxwin = GDK_WINDOW_XWINDOW(GTK_WIDGET(p->topgwin)->window);
1060 DBG("topxwin = %x\n", p->topxwin);
1061
1062 /* the settings that should be done before window is mapped */
1063 wmhints.flags = InputHint;
1064 wmhints.input = 0;
bee4c26e 1065 XSetWMHints (GDK_DISPLAY(), p->topxwin, &wmhints);
24053345 1066#define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
a52c2257
HJYP
1067 val = WIN_HINTS_SKIP_FOCUS;
1068 XChangeProperty(GDK_DISPLAY(), p->topxwin,
1069 XInternAtom(GDK_DISPLAY(), "_WIN_HINTS", False), XA_CARDINAL, 32,
1070 PropModeReplace, (unsigned char *) &val, 1);
1071
bee4c26e 1072 panel_set_dock_type(p);
a52c2257
HJYP
1073
1074 /* window mapping point */
1075 gtk_widget_show_all(p->topgwin);
1076
1077 /* the settings that should be done after window is mapped */
176fb687 1078 panel_establish_autohide(p);
a52c2257
HJYP
1079
1080 /* send it to running wm */
1081 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
1082 /* and assign it ourself just for case when wm is not running */
1083 val = 0xFFFFFFFF;
1084 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
1085 PropModeReplace, (unsigned char *) &val, 1);
1086
1087 state[0] = a_NET_WM_STATE_SKIP_PAGER;
1088 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
1089 state[2] = a_NET_WM_STATE_STICKY;
1090 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STATE, XA_ATOM,
1091 32, PropModeReplace, (unsigned char *) state, 3);
1092
a52c2257
HJYP
1093 calculate_position(p);
1094 gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
bee4c26e 1095 panel_set_wm_strut(p);
77886b88 1096
a52c2257
HJYP
1097 RET();
1098}
1099
2918994e 1100/* Exchange the "width" and "height" terminology for vertical and horizontal panels. */
1101void panel_adjust_geometry_terminology(Panel * p)
9dd114c4 1102{
8ed3b3d4 1103 if ((p->height_label != NULL) && (p->width_label != NULL)
1104 && (p->alignment_left_label != NULL) && (p->alignment_right_label != NULL))
9dd114c4 1105 {
1106 if ((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM))
1107 {
1108 gtk_label_set_text(GTK_LABEL(p->height_label), _("Height:"));
1109 gtk_label_set_text(GTK_LABEL(p->width_label), _("Width:"));
2918994e 1110 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Left"));
1111 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Right"));
9dd114c4 1112 }
1113 else
1114 {
1115 gtk_label_set_text(GTK_LABEL(p->height_label), _("Width:"));
1116 gtk_label_set_text(GTK_LABEL(p->width_label), _("Height:"));
2918994e 1117 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Top"));
1118 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Bottom"));
9dd114c4 1119 }
1120 }
1121}
1122
2918994e 1123/* Draw text into a label, with the user preference color and optionally bold. */
38ac664c
AG
1124void panel_draw_label_text(Panel * p, GtkWidget * label, const char * text,
1125 gboolean bold, float custom_size_factor,
1126 gboolean custom_color)
2918994e 1127{
2918994e 1128 if (text == NULL)
1129 {
1130 /* Null string. */
1131 gtk_label_set_text(GTK_LABEL(label), NULL);
83d410c1 1132 return;
2918994e 1133 }
1134
83d410c1
HG
1135 /* Compute an appropriate size so the font will scale with the panel's icon size. */
1136 int font_desc;
1137 if (p->usefontsize)
1138 font_desc = p->fontsize;
f669ce5e 1139 else
2918994e 1140 {
83d410c1
HG
1141 if (p->icon_size < 20)
1142 font_desc = 9;
1143 else if (p->icon_size >= 20 && p->icon_size < 36)
1144 font_desc = 10;
1145 else
1146 font_desc = 12;
1147 }
1148 font_desc *= custom_size_factor;
1149
1150 /* Check the string for characters that need to be escaped.
1151 * If any are found, create the properly escaped string and use it instead. */
38ac664c 1152 const char * valid_markup = text;
83d410c1 1153 char * escaped_text = NULL;
38ac664c 1154 const char * q;
83d410c1
HG
1155 for (q = text; *q != '\0'; q += 1)
1156 {
1157 if ((*q == '<') || (*q == '>') || (*q == '&'))
2918994e 1158 {
83d410c1
HG
1159 escaped_text = g_markup_escape_text(text, -1);
1160 valid_markup = escaped_text;
1161 break;
2918994e 1162 }
83d410c1 1163 }
2918994e 1164
83d410c1
HG
1165 gchar * formatted_text;
1166 if ((custom_color) && (p->usefontcolor))
1167 {
1168 /* Color, optionally bold. */
1169 formatted_text = g_strdup_printf("<span font_desc=\"%d\" color=\"#%06x\">%s%s%s</span>",
f669ce5e 1170 font_desc,
2918994e 1171 gcolor2rgb24(&p->gfontcolor),
1172 ((bold) ? "<b>" : ""),
1173 valid_markup,
1174 ((bold) ? "</b>" : ""));
83d410c1
HG
1175 }
1176 else
1177 {
1178 /* No color, optionally bold. */
1179 formatted_text = g_strdup_printf("<span font_desc=\"%d\">%s%s%s</span>",
f669ce5e 1180 font_desc,
1181 ((bold) ? "<b>" : ""),
1182 valid_markup,
1183 ((bold) ? "</b>" : ""));
2918994e 1184 }
83d410c1
HG
1185
1186 gtk_label_set_markup(GTK_LABEL(label), formatted_text);
1187 g_free(formatted_text);
1188 g_free(escaped_text);
2918994e 1189}
1190
1191void panel_set_panel_configuration_changed(Panel *p)
a97d06a6 1192{
17fab6e5 1193 GList *plugins, *l;
9dd114c4 1194
cfde283a 1195 GtkOrientation previous_orientation = p->orientation;
a97d06a6 1196 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
cfde283a 1197 ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
9dd114c4 1198
cfde283a
AG
1199 /* either first run or orientation was changed */
1200 if (p->my_box_new == NULL || previous_orientation != p->orientation)
9dd114c4 1201 {
1202 panel_adjust_geometry_terminology(p);
f5c7784a
AG
1203 if (p->my_box_new != NULL)
1204 p->height = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? PANEL_HEIGHT_DEFAULT : PANEL_WIDTH_DEFAULT);
9dd114c4 1205 if (p->height_control != NULL)
1206 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->height_control), p->height);
2918994e 1207 if ((p->widthtype == WIDTH_PIXEL) && (p->width_control != NULL))
1208 {
cfde283a 1209 int value = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? gdk_screen_width() : gdk_screen_height());
2918994e 1210 gtk_spin_button_set_range(GTK_SPIN_BUTTON(p->width_control), 0, value);
1211 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->width_control), value);
1212 }
9dd114c4 1213 }
1214
cfde283a 1215 if (p->orientation == GTK_ORIENTATION_HORIZONTAL) {
a97d06a6
HJYP
1216 p->my_box_new = gtk_hbox_new;
1217 p->my_separator_new = gtk_vseparator_new;
1218 } else {
1219 p->my_box_new = gtk_vbox_new;
1220 p->my_separator_new = gtk_hseparator_new;
1221 }
1222
1223 /* recreate the main layout box */
964b8b7e 1224 if (p->box != NULL)
1225 {
cfde283a 1226 gtk_orientable_set_orientation(GTK_ORIENTABLE(p->box), p->orientation);
a97d06a6 1227 }
9dd114c4 1228
a97d06a6
HJYP
1229 /* NOTE: This loop won't be executed when panel started since
1230 plugins are not loaded at that time.
1231 This is used when the orientation of the panel is changed
1232 from the config dialog, and plugins should be re-layout.
1233 */
17fab6e5
AG
1234 plugins = p->box ? gtk_container_get_children(GTK_CONTAINER(p->box)) : NULL;
1235 for( l = plugins; l; l = l->next ) {
1236 GtkWidget *w = (GtkWidget*)l->data;
1237 LXPanelPluginInit *init = PLUGIN_CLASS(w);
1238 if (init->reconfigure)
1239 init->reconfigure(p, w);
a97d06a6 1240 }
17fab6e5 1241 g_list_free(plugins);
a97d06a6
HJYP
1242}
1243
a52c2257 1244static int
17fab6e5 1245panel_parse_global(Panel *p, config_setting_t *cfg)
a52c2257 1246{
4bca3e51
AG
1247 const char *str;
1248 gint i;
6db11841 1249
17fab6e5
AG
1250 /* check Global config */
1251 if (!cfg || strcmp(config_setting_get_name(cfg), "Global") != 0)
3e7b8eb7 1252 {
17fab6e5
AG
1253 ERR( "lxpanel: Global section not found\n");
1254 RET(0);
1255 }
4bca3e51
AG
1256 if (config_setting_lookup_string(cfg, "edge", &str))
1257 p->edge = str2num(edge_pair, str, EDGE_NONE);
1258 if (config_setting_lookup_string(cfg, "allign", &str))
1259 p->allign = str2num(allign_pair, str, ALLIGN_NONE);
1260 config_setting_lookup_int(cfg, "monitor", &p->monitor);
1261 config_setting_lookup_int(cfg, "margin", &p->margin);
1262 if (config_setting_lookup_string(cfg, "widthtype", &str))
1263 p->widthtype = str2num(width_pair, str, WIDTH_NONE);
1264 config_setting_lookup_int(cfg, "width", &p->width);
1265 if (config_setting_lookup_string(cfg, "heighttype", &str))
1266 p->heighttype = str2num(height_pair, str, HEIGHT_NONE);
1267 config_setting_lookup_int(cfg, "height", &p->height);
1268 if (config_setting_lookup_int(cfg, "spacing", &i) && i > 0)
1269 p->spacing = i;
1270 if (config_setting_lookup_int(cfg, "setdocktype", &i))
1271 p->setdocktype = i != 0;
1272 if (config_setting_lookup_int(cfg, "setpartialstrut", &i))
1273 p->setstrut = i != 0;
1274 if (config_setting_lookup_int(cfg, "RoundCorners", &i))
1275 p->round_corners = i != 0;
1276 if (config_setting_lookup_int(cfg, "transparent", &i))
1277 p->transparent = i != 0;
1278 if (config_setting_lookup_int(cfg, "alpha", &p->alpha))
17fab6e5 1279 {
17fab6e5
AG
1280 if (p->alpha > 255)
1281 p->alpha = 255;
1282 }
4bca3e51
AG
1283 if (config_setting_lookup_int(cfg, "autohide", &i))
1284 p->autohide = i != 0;
1285 config_setting_lookup_int(cfg, "heightwhenhidden", &p->height_when_hidden);
1286 if (config_setting_lookup_string(cfg, "tintcolor", &str))
17fab6e5 1287 {
4bca3e51 1288 if (!gdk_color_parse (str, &p->gtintcolor))
17fab6e5
AG
1289 gdk_color_parse ("white", &p->gtintcolor);
1290 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
1291 DBG("tintcolor=%x\n", p->tintcolor);
1292 }
4bca3e51
AG
1293 if (config_setting_lookup_int(cfg, "usefontcolor", &i))
1294 p->usefontcolor = i != 0;
1295 if (config_setting_lookup_string(cfg, "fontcolor", &str))
17fab6e5 1296 {
4bca3e51 1297 if (!gdk_color_parse (str, &p->gfontcolor))
17fab6e5
AG
1298 gdk_color_parse ("black", &p->gfontcolor);
1299 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
1300 DBG("fontcolor=%x\n", p->fontcolor);
1301 }
4bca3e51
AG
1302 if (config_setting_lookup_int(cfg, "usefontsize", &i))
1303 p->usefontsize = i != 0;
1304 if (config_setting_lookup_int(cfg, "fontsize", &i) && i > 0)
1305 p->fontsize = i;
1306 if (config_setting_lookup_int(cfg, "background", &i))
1307 p->background = i != 0;
1308 if (config_setting_lookup_string(cfg, "backgroundfile", &str))
1309 p->background_file = g_strdup(str);
1310 config_setting_lookup_int(cfg, "iconsize", &p->icon_size);
1311 if (config_setting_lookup_int(cfg, "loglevel", &configured_log_level))
17fab6e5 1312 {
17fab6e5
AG
1313 if (!log_level_set_on_commandline)
1314 log_level = configured_log_level;
a52c2257 1315 }
4542c20d 1316
9dd114c4 1317 panel_normalize_configuration(p);
239cb032 1318
9dd114c4 1319 return 1;
a52c2257
HJYP
1320}
1321
1322static int
17fab6e5 1323panel_parse_plugin(Panel *p, config_setting_t *cfg)
a52c2257 1324{
4bca3e51 1325 const char *type = NULL;
db449f6e 1326
a52c2257 1327 ENTER;
4bca3e51 1328 config_setting_lookup_string(cfg, "type", &type);
17fab6e5 1329 DBG("plug %s\n", type);
db449f6e 1330
17fab6e5 1331 if (!type || lxpanel_add_plugin(p, type, cfg, -1) == NULL) {
a52c2257
HJYP
1332 ERR( "lxpanel: can't load %s plugin\n", type);
1333 goto error;
1334 }
a52c2257 1335 RET(1);
db449f6e 1336
17fab6e5 1337error:
a52c2257 1338 RET(0);
a52c2257
HJYP
1339}
1340
17fab6e5 1341int panel_start( Panel *p )
a52c2257 1342{
17fab6e5
AG
1343 config_setting_t *list, *s;
1344 int i;
db449f6e 1345
a52c2257
HJYP
1346 /* parse global section */
1347 ENTER;
8110399f 1348
17fab6e5
AG
1349 list = config_setting_get_member(config_root_setting(p->config), "");
1350 if (!list || !panel_parse_global(p, config_setting_get_elem(list, 0)))
a52c2257
HJYP
1351 RET(0);
1352
9dd114c4 1353 panel_start_gui(p);
1354
17fab6e5
AG
1355 for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
1356 if (strcmp(config_setting_get_name(s), "Plugin") == 0 &&
1357 panel_parse_plugin(p, s)) /* success on plugin start */
1358 i++;
1359 else /* remove invalid data from config */
1360 config_setting_remove_elem(list, i);
4542c20d
HJYP
1361
1362 /* update backgrond of panel and all plugins */
1363 panel_update_background( p );
9dd114c4 1364 return 1;
a52c2257
HJYP
1365}
1366
8110399f 1367void panel_destroy(Panel *p)
a52c2257
HJYP
1368{
1369 ENTER;
1370
2918994e 1371 if (p->pref_dialog != NULL)
1372 gtk_widget_destroy(p->pref_dialog);
1373 if (p->plugin_pref_dialog != NULL)
4ab8027b
AG
1374 /* just close the dialog, it will do all required cleanup */
1375 gtk_dialog_response(GTK_DIALOG(p->plugin_pref_dialog), GTK_RESPONSE_CLOSE);
2918994e 1376
1377 if (p->bg != NULL)
1378 {
1379 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, p);
1380 g_object_unref(p->bg);
1381 }
1382
930af9fd
HJYP
1383 if( p->config_changed )
1384 panel_config_save( p );
17fab6e5 1385 config_destroy(p->config);
8c44345a 1386
4b93d81e 1387 if( p->topgwin )
17fab6e5
AG
1388 {
1389 gtk_window_group_remove_window( win_grp, GTK_WINDOW( p->topgwin ) );
4b93d81e 1390 gtk_widget_destroy(p->topgwin);
17fab6e5 1391 }
a52c2257 1392 g_free(p->workarea);
2de71c90 1393 g_free( p->background_file );
5297da29 1394 g_slist_free( p->system_menus );
a52c2257
HJYP
1395 gdk_flush();
1396 XFlush(GDK_DISPLAY());
1397 XSync(GDK_DISPLAY(), True);
8110399f
HJYP
1398
1399 g_free( p->name );
2918994e 1400 g_free(p);
a52c2257
HJYP
1401 RET();
1402}
1403
8110399f
HJYP
1404Panel* panel_new( const char* config_file, const char* config_name )
1405{
cf701cb7 1406 Panel* panel = NULL;
16fbda14 1407
17fab6e5 1408 if (G_LIKELY(config_file))
cf701cb7 1409 {
17fab6e5 1410 panel = panel_allocate();
20edd661 1411 panel->name = g_strdup(config_name);
17fab6e5
AG
1412 g_debug("starting panel from file %s",config_file);
1413 if (!config_read_file(panel->config, config_file) ||
1414 !panel_start(panel))
3e7b8eb7 1415 {
17fab6e5
AG
1416 ERR( "lxpanel: can't start panel\n");
1417 panel_destroy( panel );
1418 panel = NULL;
cf701cb7 1419 }
cf701cb7
HJYP
1420 }
1421 return panel;
8110399f 1422}
a52c2257 1423
0defe4b9 1424static void
a52c2257
HJYP
1425usage()
1426{
e7cb732b
HJYP
1427 g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
1428 g_print(_("Command line options:\n"));
1429 g_print(_(" --help -- print this help and exit\n"));
1430 g_print(_(" --version -- print version and exit\n"));
1431 g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
2918994e 1432// g_print(_(" --configure -- launch configuration utility\n"));
e7cb732b
HJYP
1433 g_print(_(" --profile name -- use specified profile\n"));
1434 g_print("\n");
1435 g_print(_(" -h -- same as --help\n"));
1436 g_print(_(" -p -- same as --profile\n"));
1437 g_print(_(" -v -- same as --version\n"));
2918994e 1438 // g_print(_(" -C -- same as --configure\n"));
b37c9aae 1439 g_print(_("\nVisit http://lxde.org/ for detail.\n\n"));
a52c2257
HJYP
1440}
1441
2918994e 1442int panel_handle_x_error(Display * d, XErrorEvent * ev)
a52c2257
HJYP
1443{
1444 char buf[256];
1445
a52c2257
HJYP
1446 if (log_level >= LOG_WARN) {
1447 XGetErrorText(GDK_DISPLAY(), ev->error_code, buf, 256);
1448 LOG(LOG_WARN, "lxpanel : X error: %s\n", buf);
1449 }
2918994e 1450 return 0; /* Ignored */
1451}
1452
1453int panel_handle_x_error_swallow_BadWindow_BadDrawable(Display * d, XErrorEvent * ev)
1454{
1455 if ((ev->error_code != BadWindow) && (ev->error_code != BadDrawable))
1456 panel_handle_x_error(d, ev);
1457 return 0; /* Ignored */
a52c2257
HJYP
1458}
1459
e68b47dc
JH
1460/* Lightweight lock related functions - X clipboard hacks */
1461
1462#define CLIPBOARD_NAME "LXPANEL_SELECTION"
1463
1464/*
1465 * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
1466 */
1467static void
1468clipboard_get_func(
1469 GtkClipboard *clipboard G_GNUC_UNUSED,
1470 GtkSelectionData *selection_data G_GNUC_UNUSED,
1471 guint info G_GNUC_UNUSED,
1472 gpointer user_data_or_owner G_GNUC_UNUSED)
1473{
1474}
1475
1476/*
1477 * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
1478 */
1479static void clipboard_clear_func(
1480 GtkClipboard *clipboard G_GNUC_UNUSED,
1481 gpointer user_data_or_owner G_GNUC_UNUSED)
1482{
1483}
1484
1485/*
1486 * Lightweight version for checking single instance.
1487 * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
1488 *
1489 * Returns TRUE if successfully retrieved and FALSE otherwise.
1490 */
16fb8c2e 1491static gboolean check_main_lock()
e68b47dc
JH
1492{
1493 static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
1494 gboolean retval = FALSE;
1495 GtkClipboard *clipboard;
1496 Atom atom;
1497
1498 atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
1499
1500 XGrabServer(GDK_DISPLAY());
1501
1502 if (XGetSelectionOwner(GDK_DISPLAY(), atom) != None)
1503 goto out;
1504
1505 clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
1506
1507 if (gtk_clipboard_set_with_data(clipboard, targets,
1508 G_N_ELEMENTS (targets),
1509 clipboard_get_func,
1510 clipboard_clear_func, NULL))
1511 retval = TRUE;
1512
1513out:
1514 XUngrabServer (GDK_DISPLAY ());
1515 gdk_flush ();
1516
1517 return retval;
1518}
1519#undef CLIPBOARD_NAME
1520
8110399f
HJYP
1521static gboolean start_all_panels( )
1522{
cf701cb7 1523 gboolean is_global;
4b93d81e 1524 for( is_global = 0; ! all_panels && is_global < 2; ++is_global )
cf701cb7
HJYP
1525 {
1526 char* panel_dir = get_config_file( cprofile, "panels", is_global );
1527 GDir* dir = g_dir_open( panel_dir, 0, NULL );
e3b89f43 1528 const gchar* name;
cf701cb7
HJYP
1529
1530 if( ! dir )
1531 {
1532 g_free( panel_dir );
1533 continue;
1534 }
1535
547ece89 1536 while((name = g_dir_read_name(dir)) != NULL)
cf701cb7
HJYP
1537 {
1538 char* panel_config = g_build_filename( panel_dir, name, NULL );
2918994e 1539 if (strchr(panel_config, '~') == NULL) /* Skip editor backup files in case user has hand edited in this directory */
1540 {
1541 Panel* panel = panel_new( panel_config, name );
1542 if( panel )
1543 all_panels = g_slist_prepend( all_panels, panel );
1544 }
cf701cb7
HJYP
1545 g_free( panel_config );
1546 }
1547 g_dir_close( dir );
1548 g_free( panel_dir );
1549 }
1550 return all_panels != NULL;
8110399f
HJYP
1551}
1552
cf701cb7
HJYP
1553void load_global_config();
1554void free_global_config();
1555
8110399f 1556int main(int argc, char *argv[], char *env[])
a52c2257
HJYP
1557{
1558 int i;
9df6826f 1559 const char* desktop_name;
f277dbb7 1560
a52c2257 1561 setlocale(LC_CTYPE, "");
f277dbb7 1562
1d434622 1563 g_thread_init(NULL);
74bf5dbf
AG
1564/* gdk_threads_init();
1565 gdk_threads_enter(); */
1d434622 1566
a52c2257
HJYP
1567 gtk_init(&argc, &argv);
1568
1569#ifdef ENABLE_NLS
1570 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
1571 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
1572 textdomain ( GETTEXT_PACKAGE );
1573#endif
1574
1575 XSetLocaleModifiers("");
2918994e 1576 XSetErrorHandler((XErrorHandler) panel_handle_x_error);
8110399f 1577
a52c2257 1578 resolve_atoms();
8110399f 1579
9df6826f
HJYP
1580 desktop_name = g_getenv("XDG_CURRENT_DESKTOP");
1581 is_in_lxde = desktop_name && (0 == strcmp(desktop_name, "LXDE"));
95095259 1582
a52c2257
HJYP
1583 for (i = 1; i < argc; i++) {
1584 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
1585 usage();
1586 exit(0);
1587 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
1588 printf("lxpanel %s\n", version);
1589 exit(0);
1590 } else if (!strcmp(argv[i], "--log")) {
1591 i++;
1592 if (i == argc) {
1593 ERR( "lxpanel: missing log level\n");
1594 usage();
1595 exit(1);
1596 } else {
1597 log_level = atoi(argv[i]);
82ca42af 1598 log_level_set_on_commandline = true;
a52c2257
HJYP
1599 }
1600 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
1601 config = 1;
1602 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
1603 i++;
1604 if (i == argc) {
1605 ERR( "lxpanel: missing profile name\n");
1606 usage();
1607 exit(1);
1608 } else {
1609 cprofile = g_strdup(argv[i]);
1610 }
1611 } else {
1612 printf("lxpanel: unknown option - %s\n", argv[i]);
1613 usage();
1614 exit(1);
1615 }
1616 }
f277dbb7 1617
8110399f 1618 /* Check for duplicated lxpanel instances */
e68b47dc 1619 if (!check_main_lock() && !config) {
e7a42ecf 1620 printf("There is already an instance of LXPanel. Now to exit\n");
e68b47dc
JH
1621 exit(1);
1622 }
1623
730e3f7b 1624 /* Add our own icons to the search path of icon theme */
0b806437 1625 gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(), PACKAGE_DATA_DIR "/images" );
730e3f7b 1626
cf701cb7 1627 fbev = fb_ev_new();
e2957bd2 1628 win_grp = gtk_window_group_new();
22242ed4 1629
f7cb330e
HJYP
1630restart:
1631 is_restarting = FALSE;
1632
17fab6e5
AG
1633 /* init LibFM */
1634 fm_gtk_init(NULL);
1635
1636 /* prepare modules data */
1637 _prepare_modules();
1638
cf701cb7
HJYP
1639 load_global_config();
1640
1d9dc649
HJYP
1641 /* NOTE: StructureNotifyMask is required by XRandR
1642 * See init_randr_support() in gdkscreen-x11.c of gtk+ for detail.
1643 */
0f83fb71 1644 gdk_window_set_events(gdk_get_default_root_window(), GDK_STRUCTURE_MASK |
1645 GDK_SUBSTRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK);
cf701cb7 1646 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
8110399f 1647
cf701cb7
HJYP
1648 if( G_UNLIKELY( ! start_all_panels() ) )
1649 g_warning( "Config files are not found.\n" );
8110399f
HJYP
1650/*
1651 * FIXME: configure??
6a6ad54e
HJYP
1652 if (config)
1653 configure();
8110399f 1654*/
6a6ad54e 1655 gtk_main();
8110399f 1656
cf701cb7
HJYP
1657 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), NoEventMask);
1658 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1659
8110399f
HJYP
1660 /* destroy all panels */
1661 g_slist_foreach( all_panels, (GFunc) panel_destroy, NULL );
2a26c0d8
HJYP
1662 g_slist_free( all_panels );
1663 all_panels = NULL;
6a6ad54e 1664 g_free( cfgfile );
5541b8d2 1665
cf701cb7
HJYP
1666 free_global_config();
1667
17fab6e5
AG
1668 _unload_modules();
1669 fm_gtk_finalize();
1670
f7cb330e
HJYP
1671 if( is_restarting )
1672 goto restart;
1673
74bf5dbf 1674 /* gdk_threads_leave(); */
3e71f8af 1675
e2957bd2 1676 g_object_unref(win_grp);
22242ed4
HJYP
1677 g_object_unref(fbev);
1678
5541b8d2 1679 return 0;
a52c2257 1680}
9c338caf 1681
cfde283a 1682extern GtkOrientation panel_get_orientation(Panel *panel)
9c338caf 1683{
cfde283a 1684 return panel->orientation;
9c338caf
AG
1685}
1686
1687extern gint panel_get_icon_size(Panel *panel)
1688{
1689 return panel->icon_size;
1690}
1691
1692extern gint panel_get_height(Panel *panel)
1693{
1694 return panel->height;
1695}
1696
1697extern GtkWindow *panel_get_toplevel_window(Panel *panel)
1698{
4ab8027b 1699 return GTK_WINDOW(panel->topgwin);
9c338caf
AG
1700}
1701
1702extern GtkStyle *panel_get_defstyle(Panel *panel)
1703{
1704 return panel->defstyle;
1705}
1706
1707extern GtkIconTheme *panel_get_icon_theme(Panel *panel)
1708{
1709 return panel->icon_theme;
1710}
1711
1712extern GtkWidget *panel_box_new(Panel *panel, gboolean homogeneous, gint spacing)
1713{
1714 return panel->my_box_new(homogeneous, spacing);
1715}
1716
1717extern GtkWidget *panel_separator_new(Panel *panel)
1718{
1719 return panel->my_separator_new();
1720}
10d93053
AG
1721
1722gboolean _class_is_present(LXPanelPluginInit *init)
1723{
1724 GSList *sl;
1725
1726 for (sl = all_panels; sl; sl = sl->next )
1727 {
1728 Panel *panel = (Panel*)sl->data;
1729 GList *plugins, *p;
1730
1731 plugins = gtk_container_get_children(GTK_CONTAINER(panel->box));
1732 for (p = plugins; p; p = p->next)
1733 if (PLUGIN_CLASS(p->data) == init)
1734 {
1735 g_list_free(plugins);
1736 return TRUE;
1737 }
1738 g_list_free(plugins);
1739 }
1740 return FALSE;
1741}