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