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