Migrate built-in plugin "launchbar" to libfm API and new plugins API.
[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
e996608e 228/* defined in plugins/menu.c */
8c44345a 229gboolean show_system_menu( gpointer system_menu );
e996608e 230
3e7b8eb7
HJYP
231/* defined in configurator.c */
232void panel_configure(Panel* p, int sel_page );
64afc832 233gboolean panel_edge_available(Panel* p, int edge, gint monitor);
3e7b8eb7 234
e996608e 235/* built-in commands, defined in configurator.c */
77886b88
HJYP
236void restart(void);
237void gtk_run(void);
e3b89f43 238void panel_destroy(Panel *p);
77886b88 239
d18c9409 240static void process_client_msg ( XClientMessageEvent* ev )
77886b88 241{
8c44345a 242 int cmd = ev->data.b[0];
77886b88
HJYP
243 switch( cmd )
244 {
ace2a572 245#ifndef DISABLE_MENU
77886b88 246 case LXPANEL_CMD_SYS_MENU:
d18c9409
HJYP
247 {
248 GSList* l;
249 for( l = all_panels; l; l = l->next )
8c44345a 250 {
d18c9409
HJYP
251 Panel* p = (Panel*)l->data;
252 if( p->system_menus )
253 {
254 /* show_system_menu( p->system_menus->data ); */
255 /* FIXME: I've no idea why this doesn't work without timeout
256 under some WMs, like icewm. */
257 g_timeout_add( 200, (GSourceFunc)show_system_menu,
258 p->system_menus->data );
259 }
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
HJYP
496 if (p->widthtype == WIDTH_REQUEST)
497 p->width = (p->orientation == ORIENT_HORIZ) ? req->width : req->height;
498 if (p->heighttype == HEIGHT_REQUEST)
499 p->height = (p->orientation == ORIENT_HORIZ) ? 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
HJYP
512 if (p->widthtype == WIDTH_REQUEST)
513 p->width = (p->orientation == ORIENT_HORIZ) ? a->width : a->height;
514 if (p->heighttype == HEIGHT_REQUEST)
515 p->height = (p->orientation == ORIENT_HORIZ) ? a->height : a->width;
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
1197 int previous_orientation = p->orientation;
a97d06a6
HJYP
1198 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
1199 ? ORIENT_HORIZ : ORIENT_VERT;
9dd114c4 1200
1201 if (previous_orientation != p->orientation)
1202 {
1203 panel_adjust_geometry_terminology(p);
1b0b2df6 1204 if (previous_orientation != ORIENT_NONE)
1205 p->height = ((p->orientation == ORIENT_HORIZ) ? PANEL_HEIGHT_DEFAULT : PANEL_WIDTH_DEFAULT);
9dd114c4 1206 if (p->height_control != NULL)
1207 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->height_control), p->height);
2918994e 1208 if ((p->widthtype == WIDTH_PIXEL) && (p->width_control != NULL))
1209 {
1210 int value = ((p->orientation == ORIENT_HORIZ) ? gdk_screen_width() : gdk_screen_height());
1211 gtk_spin_button_set_range(GTK_SPIN_BUTTON(p->width_control), 0, value);
1212 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->width_control), value);
1213 }
1214
9dd114c4 1215 }
1216
a97d06a6
HJYP
1217 if (p->orientation == ORIENT_HORIZ) {
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 {
964b8b7e 1228 GtkOrientation bo = (p->orientation == ORIENT_HORIZ) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
1229 gtk_orientable_set_orientation(GTK_ORIENTABLE(p->box), bo);
a97d06a6 1230 }
9dd114c4 1231
a97d06a6
HJYP
1232 /* NOTE: This loop won't be executed when panel started since
1233 plugins are not loaded at that time.
1234 This is used when the orientation of the panel is changed
1235 from the config dialog, and plugins should be re-layout.
1236 */
17fab6e5
AG
1237 plugins = p->box ? gtk_container_get_children(GTK_CONTAINER(p->box)) : NULL;
1238 for( l = plugins; l; l = l->next ) {
1239 GtkWidget *w = (GtkWidget*)l->data;
1240 LXPanelPluginInit *init = PLUGIN_CLASS(w);
1241 if (init->reconfigure)
1242 init->reconfigure(p, w);
a97d06a6 1243 }
17fab6e5 1244 g_list_free(plugins);
a97d06a6
HJYP
1245}
1246
a52c2257 1247static int
17fab6e5 1248panel_parse_global(Panel *p, config_setting_t *cfg)
a52c2257 1249{
4bca3e51
AG
1250 const char *str;
1251 gint i;
6db11841 1252
17fab6e5
AG
1253 /* check Global config */
1254 if (!cfg || strcmp(config_setting_get_name(cfg), "Global") != 0)
3e7b8eb7 1255 {
17fab6e5
AG
1256 ERR( "lxpanel: Global section not found\n");
1257 RET(0);
1258 }
4bca3e51
AG
1259 if (config_setting_lookup_string(cfg, "edge", &str))
1260 p->edge = str2num(edge_pair, str, EDGE_NONE);
1261 if (config_setting_lookup_string(cfg, "allign", &str))
1262 p->allign = str2num(allign_pair, str, ALLIGN_NONE);
1263 config_setting_lookup_int(cfg, "monitor", &p->monitor);
1264 config_setting_lookup_int(cfg, "margin", &p->margin);
1265 if (config_setting_lookup_string(cfg, "widthtype", &str))
1266 p->widthtype = str2num(width_pair, str, WIDTH_NONE);
1267 config_setting_lookup_int(cfg, "width", &p->width);
1268 if (config_setting_lookup_string(cfg, "heighttype", &str))
1269 p->heighttype = str2num(height_pair, str, HEIGHT_NONE);
1270 config_setting_lookup_int(cfg, "height", &p->height);
1271 if (config_setting_lookup_int(cfg, "spacing", &i) && i > 0)
1272 p->spacing = i;
1273 if (config_setting_lookup_int(cfg, "setdocktype", &i))
1274 p->setdocktype = i != 0;
1275 if (config_setting_lookup_int(cfg, "setpartialstrut", &i))
1276 p->setstrut = i != 0;
1277 if (config_setting_lookup_int(cfg, "RoundCorners", &i))
1278 p->round_corners = i != 0;
1279 if (config_setting_lookup_int(cfg, "transparent", &i))
1280 p->transparent = i != 0;
1281 if (config_setting_lookup_int(cfg, "alpha", &p->alpha))
17fab6e5 1282 {
17fab6e5
AG
1283 if (p->alpha > 255)
1284 p->alpha = 255;
1285 }
4bca3e51
AG
1286 if (config_setting_lookup_int(cfg, "autohide", &i))
1287 p->autohide = i != 0;
1288 config_setting_lookup_int(cfg, "heightwhenhidden", &p->height_when_hidden);
1289 if (config_setting_lookup_string(cfg, "tintcolor", &str))
17fab6e5 1290 {
4bca3e51 1291 if (!gdk_color_parse (str, &p->gtintcolor))
17fab6e5
AG
1292 gdk_color_parse ("white", &p->gtintcolor);
1293 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
1294 DBG("tintcolor=%x\n", p->tintcolor);
1295 }
4bca3e51
AG
1296 if (config_setting_lookup_int(cfg, "usefontcolor", &i))
1297 p->usefontcolor = i != 0;
1298 if (config_setting_lookup_string(cfg, "fontcolor", &str))
17fab6e5 1299 {
4bca3e51 1300 if (!gdk_color_parse (str, &p->gfontcolor))
17fab6e5
AG
1301 gdk_color_parse ("black", &p->gfontcolor);
1302 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
1303 DBG("fontcolor=%x\n", p->fontcolor);
1304 }
4bca3e51
AG
1305 if (config_setting_lookup_int(cfg, "usefontsize", &i))
1306 p->usefontsize = i != 0;
1307 if (config_setting_lookup_int(cfg, "fontsize", &i) && i > 0)
1308 p->fontsize = i;
1309 if (config_setting_lookup_int(cfg, "background", &i))
1310 p->background = i != 0;
1311 if (config_setting_lookup_string(cfg, "backgroundfile", &str))
1312 p->background_file = g_strdup(str);
1313 config_setting_lookup_int(cfg, "iconsize", &p->icon_size);
1314 if (config_setting_lookup_int(cfg, "loglevel", &configured_log_level))
17fab6e5 1315 {
17fab6e5
AG
1316 if (!log_level_set_on_commandline)
1317 log_level = configured_log_level;
a52c2257 1318 }
4542c20d 1319
9dd114c4 1320 panel_normalize_configuration(p);
239cb032 1321
9dd114c4 1322 return 1;
a52c2257
HJYP
1323}
1324
1325static int
17fab6e5 1326panel_parse_plugin(Panel *p, config_setting_t *cfg)
a52c2257 1327{
4bca3e51 1328 const char *type = NULL;
db449f6e 1329
a52c2257 1330 ENTER;
4bca3e51 1331 config_setting_lookup_string(cfg, "type", &type);
17fab6e5 1332 DBG("plug %s\n", type);
db449f6e 1333
17fab6e5 1334 if (!type || lxpanel_add_plugin(p, type, cfg, -1) == NULL) {
a52c2257
HJYP
1335 ERR( "lxpanel: can't load %s plugin\n", type);
1336 goto error;
1337 }
a52c2257 1338 RET(1);
db449f6e 1339
17fab6e5 1340error:
a52c2257 1341 RET(0);
a52c2257
HJYP
1342}
1343
17fab6e5 1344int panel_start( Panel *p )
a52c2257 1345{
17fab6e5
AG
1346 config_setting_t *list, *s;
1347 int i;
db449f6e 1348
a52c2257
HJYP
1349 /* parse global section */
1350 ENTER;
8110399f 1351
17fab6e5
AG
1352 list = config_setting_get_member(config_root_setting(p->config), "");
1353 if (!list || !panel_parse_global(p, config_setting_get_elem(list, 0)))
a52c2257
HJYP
1354 RET(0);
1355
9dd114c4 1356 panel_start_gui(p);
1357
17fab6e5
AG
1358 for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
1359 if (strcmp(config_setting_get_name(s), "Plugin") == 0 &&
1360 panel_parse_plugin(p, s)) /* success on plugin start */
1361 i++;
1362 else /* remove invalid data from config */
1363 config_setting_remove_elem(list, i);
4542c20d
HJYP
1364
1365 /* update backgrond of panel and all plugins */
1366 panel_update_background( p );
9dd114c4 1367 return 1;
a52c2257
HJYP
1368}
1369
8110399f 1370void panel_destroy(Panel *p)
a52c2257
HJYP
1371{
1372 ENTER;
1373
2918994e 1374 if (p->pref_dialog != NULL)
1375 gtk_widget_destroy(p->pref_dialog);
1376 if (p->plugin_pref_dialog != NULL)
4ab8027b
AG
1377 /* just close the dialog, it will do all required cleanup */
1378 gtk_dialog_response(GTK_DIALOG(p->plugin_pref_dialog), GTK_RESPONSE_CLOSE);
2918994e 1379
1380 if (p->bg != NULL)
1381 {
1382 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, p);
1383 g_object_unref(p->bg);
1384 }
1385
930af9fd
HJYP
1386 if( p->config_changed )
1387 panel_config_save( p );
17fab6e5 1388 config_destroy(p->config);
8c44345a 1389
5297da29 1390 if( p->system_menus ){
8c44345a 1391 do{
5297da29 1392 } while ( g_source_remove_by_user_data( p->system_menus ) );
8c44345a
HJYP
1393 }
1394
4b93d81e 1395 if( p->topgwin )
17fab6e5
AG
1396 {
1397 gtk_window_group_remove_window( win_grp, GTK_WINDOW( p->topgwin ) );
4b93d81e 1398 gtk_widget_destroy(p->topgwin);
17fab6e5 1399 }
a52c2257 1400 g_free(p->workarea);
2de71c90 1401 g_free( p->background_file );
5297da29 1402 g_slist_free( p->system_menus );
a52c2257
HJYP
1403 gdk_flush();
1404 XFlush(GDK_DISPLAY());
1405 XSync(GDK_DISPLAY(), True);
8110399f
HJYP
1406
1407 g_free( p->name );
2918994e 1408 g_free(p);
a52c2257
HJYP
1409 RET();
1410}
1411
8110399f
HJYP
1412Panel* panel_new( const char* config_file, const char* config_name )
1413{
cf701cb7 1414 Panel* panel = NULL;
16fbda14 1415
17fab6e5 1416 if (G_LIKELY(config_file))
cf701cb7 1417 {
17fab6e5 1418 panel = panel_allocate();
20edd661 1419 panel->name = g_strdup(config_name);
17fab6e5
AG
1420 g_debug("starting panel from file %s",config_file);
1421 if (!config_read_file(panel->config, config_file) ||
1422 !panel_start(panel))
3e7b8eb7 1423 {
17fab6e5
AG
1424 ERR( "lxpanel: can't start panel\n");
1425 panel_destroy( panel );
1426 panel = NULL;
cf701cb7 1427 }
cf701cb7
HJYP
1428 }
1429 return panel;
8110399f 1430}
a52c2257 1431
0defe4b9 1432static void
a52c2257
HJYP
1433usage()
1434{
e7cb732b
HJYP
1435 g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
1436 g_print(_("Command line options:\n"));
1437 g_print(_(" --help -- print this help and exit\n"));
1438 g_print(_(" --version -- print version and exit\n"));
1439 g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
2918994e 1440// g_print(_(" --configure -- launch configuration utility\n"));
e7cb732b
HJYP
1441 g_print(_(" --profile name -- use specified profile\n"));
1442 g_print("\n");
1443 g_print(_(" -h -- same as --help\n"));
1444 g_print(_(" -p -- same as --profile\n"));
1445 g_print(_(" -v -- same as --version\n"));
2918994e 1446 // g_print(_(" -C -- same as --configure\n"));
b37c9aae 1447 g_print(_("\nVisit http://lxde.org/ for detail.\n\n"));
a52c2257
HJYP
1448}
1449
2918994e 1450int panel_handle_x_error(Display * d, XErrorEvent * ev)
a52c2257
HJYP
1451{
1452 char buf[256];
1453
a52c2257
HJYP
1454 if (log_level >= LOG_WARN) {
1455 XGetErrorText(GDK_DISPLAY(), ev->error_code, buf, 256);
1456 LOG(LOG_WARN, "lxpanel : X error: %s\n", buf);
1457 }
2918994e 1458 return 0; /* Ignored */
1459}
1460
1461int panel_handle_x_error_swallow_BadWindow_BadDrawable(Display * d, XErrorEvent * ev)
1462{
1463 if ((ev->error_code != BadWindow) && (ev->error_code != BadDrawable))
1464 panel_handle_x_error(d, ev);
1465 return 0; /* Ignored */
a52c2257
HJYP
1466}
1467
e68b47dc
JH
1468/* Lightweight lock related functions - X clipboard hacks */
1469
1470#define CLIPBOARD_NAME "LXPANEL_SELECTION"
1471
1472/*
1473 * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
1474 */
1475static void
1476clipboard_get_func(
1477 GtkClipboard *clipboard G_GNUC_UNUSED,
1478 GtkSelectionData *selection_data G_GNUC_UNUSED,
1479 guint info G_GNUC_UNUSED,
1480 gpointer user_data_or_owner G_GNUC_UNUSED)
1481{
1482}
1483
1484/*
1485 * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
1486 */
1487static void clipboard_clear_func(
1488 GtkClipboard *clipboard G_GNUC_UNUSED,
1489 gpointer user_data_or_owner G_GNUC_UNUSED)
1490{
1491}
1492
1493/*
1494 * Lightweight version for checking single instance.
1495 * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
1496 *
1497 * Returns TRUE if successfully retrieved and FALSE otherwise.
1498 */
16fb8c2e 1499static gboolean check_main_lock()
e68b47dc
JH
1500{
1501 static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
1502 gboolean retval = FALSE;
1503 GtkClipboard *clipboard;
1504 Atom atom;
1505
1506 atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
1507
1508 XGrabServer(GDK_DISPLAY());
1509
1510 if (XGetSelectionOwner(GDK_DISPLAY(), atom) != None)
1511 goto out;
1512
1513 clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
1514
1515 if (gtk_clipboard_set_with_data(clipboard, targets,
1516 G_N_ELEMENTS (targets),
1517 clipboard_get_func,
1518 clipboard_clear_func, NULL))
1519 retval = TRUE;
1520
1521out:
1522 XUngrabServer (GDK_DISPLAY ());
1523 gdk_flush ();
1524
1525 return retval;
1526}
1527#undef CLIPBOARD_NAME
1528
8110399f
HJYP
1529static gboolean start_all_panels( )
1530{
cf701cb7 1531 gboolean is_global;
4b93d81e 1532 for( is_global = 0; ! all_panels && is_global < 2; ++is_global )
cf701cb7
HJYP
1533 {
1534 char* panel_dir = get_config_file( cprofile, "panels", is_global );
1535 GDir* dir = g_dir_open( panel_dir, 0, NULL );
e3b89f43 1536 const gchar* name;
cf701cb7
HJYP
1537
1538 if( ! dir )
1539 {
1540 g_free( panel_dir );
1541 continue;
1542 }
1543
547ece89 1544 while((name = g_dir_read_name(dir)) != NULL)
cf701cb7
HJYP
1545 {
1546 char* panel_config = g_build_filename( panel_dir, name, NULL );
2918994e 1547 if (strchr(panel_config, '~') == NULL) /* Skip editor backup files in case user has hand edited in this directory */
1548 {
1549 Panel* panel = panel_new( panel_config, name );
1550 if( panel )
1551 all_panels = g_slist_prepend( all_panels, panel );
1552 }
cf701cb7
HJYP
1553 g_free( panel_config );
1554 }
1555 g_dir_close( dir );
1556 g_free( panel_dir );
1557 }
1558 return all_panels != NULL;
8110399f
HJYP
1559}
1560
cf701cb7
HJYP
1561void load_global_config();
1562void free_global_config();
1563
8110399f 1564int main(int argc, char *argv[], char *env[])
a52c2257
HJYP
1565{
1566 int i;
9df6826f 1567 const char* desktop_name;
f277dbb7 1568
a52c2257 1569 setlocale(LC_CTYPE, "");
f277dbb7 1570
1d434622
HJYP
1571 g_thread_init(NULL);
1572 gdk_threads_init();
3e71f8af 1573 gdk_threads_enter();
1d434622 1574
a52c2257
HJYP
1575 gtk_init(&argc, &argv);
1576
1577#ifdef ENABLE_NLS
1578 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
1579 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
1580 textdomain ( GETTEXT_PACKAGE );
1581#endif
1582
1583 XSetLocaleModifiers("");
2918994e 1584 XSetErrorHandler((XErrorHandler) panel_handle_x_error);
8110399f 1585
a52c2257 1586 resolve_atoms();
8110399f 1587
9df6826f
HJYP
1588 desktop_name = g_getenv("XDG_CURRENT_DESKTOP");
1589 is_in_lxde = desktop_name && (0 == strcmp(desktop_name, "LXDE"));
95095259 1590
a52c2257
HJYP
1591 for (i = 1; i < argc; i++) {
1592 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
1593 usage();
1594 exit(0);
1595 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
1596 printf("lxpanel %s\n", version);
1597 exit(0);
1598 } else if (!strcmp(argv[i], "--log")) {
1599 i++;
1600 if (i == argc) {
1601 ERR( "lxpanel: missing log level\n");
1602 usage();
1603 exit(1);
1604 } else {
1605 log_level = atoi(argv[i]);
82ca42af 1606 log_level_set_on_commandline = true;
a52c2257
HJYP
1607 }
1608 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
1609 config = 1;
1610 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
1611 i++;
1612 if (i == argc) {
1613 ERR( "lxpanel: missing profile name\n");
1614 usage();
1615 exit(1);
1616 } else {
1617 cprofile = g_strdup(argv[i]);
1618 }
1619 } else {
1620 printf("lxpanel: unknown option - %s\n", argv[i]);
1621 usage();
1622 exit(1);
1623 }
1624 }
f277dbb7 1625
8110399f 1626 /* Check for duplicated lxpanel instances */
e68b47dc 1627 if (!check_main_lock() && !config) {
e7a42ecf 1628 printf("There is already an instance of LXPanel. Now to exit\n");
e68b47dc
JH
1629 exit(1);
1630 }
1631
730e3f7b
JL
1632 /* Add our own icons to the search path of icon theme */
1633 gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(), PACKAGE_DATA_DIR "/lxpanel/images" );
1634
cf701cb7 1635 fbev = fb_ev_new();
e2957bd2 1636 win_grp = gtk_window_group_new();
22242ed4 1637
f7cb330e
HJYP
1638restart:
1639 is_restarting = FALSE;
1640
17fab6e5
AG
1641 /* init LibFM */
1642 fm_gtk_init(NULL);
1643
1644 /* prepare modules data */
1645 _prepare_modules();
1646
cf701cb7
HJYP
1647 load_global_config();
1648
1d9dc649
HJYP
1649 /* NOTE: StructureNotifyMask is required by XRandR
1650 * See init_randr_support() in gdkscreen-x11.c of gtk+ for detail.
1651 */
0f83fb71 1652 gdk_window_set_events(gdk_get_default_root_window(), GDK_STRUCTURE_MASK |
1653 GDK_SUBSTRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK);
cf701cb7 1654 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
8110399f 1655
cf701cb7
HJYP
1656 if( G_UNLIKELY( ! start_all_panels() ) )
1657 g_warning( "Config files are not found.\n" );
8110399f
HJYP
1658/*
1659 * FIXME: configure??
6a6ad54e
HJYP
1660 if (config)
1661 configure();
8110399f 1662*/
6a6ad54e 1663 gtk_main();
8110399f 1664
cf701cb7
HJYP
1665 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), NoEventMask);
1666 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1667
8110399f
HJYP
1668 /* destroy all panels */
1669 g_slist_foreach( all_panels, (GFunc) panel_destroy, NULL );
2a26c0d8
HJYP
1670 g_slist_free( all_panels );
1671 all_panels = NULL;
6a6ad54e 1672 g_free( cfgfile );
5541b8d2 1673
cf701cb7
HJYP
1674 free_global_config();
1675
17fab6e5
AG
1676 _unload_modules();
1677 fm_gtk_finalize();
1678
f7cb330e
HJYP
1679 if( is_restarting )
1680 goto restart;
1681
3e71f8af
HG
1682 gdk_threads_leave();
1683
e2957bd2 1684 g_object_unref(win_grp);
22242ed4
HJYP
1685 g_object_unref(fbev);
1686
5541b8d2 1687 return 0;
a52c2257 1688}
9c338caf 1689
10b7f93c 1690extern gboolean panel_is_horizontal(Panel *panel)
9c338caf
AG
1691{
1692 return (panel->orientation == ORIENT_HORIZ);
1693}
1694
1695extern gint panel_get_icon_size(Panel *panel)
1696{
1697 return panel->icon_size;
1698}
1699
1700extern gint panel_get_height(Panel *panel)
1701{
1702 return panel->height;
1703}
1704
1705extern GtkWindow *panel_get_toplevel_window(Panel *panel)
1706{
4ab8027b 1707 return GTK_WINDOW(panel->topgwin);
9c338caf
AG
1708}
1709
1710extern GtkStyle *panel_get_defstyle(Panel *panel)
1711{
1712 return panel->defstyle;
1713}
1714
1715extern GtkIconTheme *panel_get_icon_theme(Panel *panel)
1716{
1717 return panel->icon_theme;
1718}
1719
1720extern GtkWidget *panel_box_new(Panel *panel, gboolean homogeneous, gint spacing)
1721{
1722 return panel->my_box_new(homogeneous, spacing);
1723}
1724
1725extern GtkWidget *panel_separator_new(Panel *panel)
1726{
1727 return panel->my_separator_new();
1728}
10d93053
AG
1729
1730gboolean _class_is_present(LXPanelPluginInit *init)
1731{
1732 GSList *sl;
1733
1734 for (sl = all_panels; sl; sl = sl->next )
1735 {
1736 Panel *panel = (Panel*)sl->data;
1737 GList *plugins, *p;
1738
1739 plugins = gtk_container_get_children(GTK_CONTAINER(panel->box));
1740 for (p = plugins; p; p = p->next)
1741 if (PLUGIN_CLASS(p->data) == init)
1742 {
1743 g_list_free(plugins);
1744 return TRUE;
1745 }
1746 g_list_free(plugins);
1747 }
1748 return FALSE;
1749}