Little fix
[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
HJYP
24#include <stdlib.h>
25#include <stdio.h>
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
8110399f 39#include "glib-mem.h"
77886b88 40#include "lxpanelctl.h"
cf701cb7 41#include "dbg.h"
77886b88 42
a52c2257
HJYP
43static gchar *cfgfile = NULL;
44static gchar version[] = VERSION;
45gchar *cprofile = "default";
46
e2957bd2
HJYP
47static GtkWindowGroup* win_grp; /* window group used to limit the scope of model dialog. */
48
e68b47dc 49static int config = 0;
22242ed4 50FbEv *fbev = NULL;
a52c2257 51
a52c2257 52int log_level;
8110399f 53
cf701cb7 54GSList* all_panels = NULL; /* a single-linked list storing all panels */
a52c2257 55
f7cb330e
HJYP
56gboolean is_restarting = FALSE;
57
3e7b8eb7 58static int panel_start( Panel *p, char **fp );
4b93d81e
HJYP
59void panel_config_save(Panel* panel); /* defined in configurator.c */
60
95095259
HJYP
61gboolean is_in_lxde = FALSE;
62
a52c2257
HJYP
63/****************************************************
64 * panel's handlers for WM events *
65 ****************************************************/
66/*
67static void
22242ed4 68panel_del_wm_strut(Panel *p)
a52c2257
HJYP
69{
70 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT);
71 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL);
72}
73*/
74
75
22242ed4 76void panel_set_wm_strut(Panel *p)
a52c2257
HJYP
77{
78 gulong data[12] = { 0 };
79 int i = 4;
80
a52c2257
HJYP
81 if (!GTK_WIDGET_MAPPED (p->topgwin))
82 return;
bee4c26e
HJYP
83 if ( ! p->setstrut )
84 {
85 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL);
86 /* old spec, for wms that do not support STRUT_PARTIAL */
87 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT);
88 return;
89 }
90
a52c2257
HJYP
91 switch (p->edge) {
92 case EDGE_LEFT:
93 i = 0;
94 data[i] = p->aw;
95 data[4 + i*2] = p->ay;
96 data[5 + i*2] = p->ay + p->ah;
97 break;
98 case EDGE_RIGHT:
99 i = 1;
100 data[i] = p->aw;
101 data[4 + i*2] = p->ay;
102 data[5 + i*2] = p->ay + p->ah;
103 break;
104 case EDGE_TOP:
105 i = 2;
106 data[i] = p->ah;
107 data[4 + i*2] = p->ax;
108 data[5 + i*2] = p->ax + p->aw;
109 break;
110 case EDGE_BOTTOM:
111 i = 3;
112 data[i] = p->ah;
113 data[4 + i*2] = p->ax;
114 data[5 + i*2] = p->ax + p->aw;
115 break;
116 default:
117 ERR("wrong edge %d. strut won't be set\n", p->edge);
118 RET();
bee4c26e 119 }
a52c2257 120 DBG("type %d. width %d. from %d to %d\n", i, data[i], data[4 + i*2], data[5 + i*2]);
bee4c26e 121
a52c2257 122 /* if wm supports STRUT_PARTIAL it will ignore STRUT */
bee4c26e 123 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL,
a52c2257
HJYP
124 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 12);
125 /* old spec, for wms that do not support STRUT_PARTIAL */
bee4c26e
HJYP
126 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT,
127 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 4);
a52c2257
HJYP
128
129 RET();
130}
131
1d9dc649 132#if 0
a52c2257 133static void
22242ed4 134print_wmdata(Panel *p)
a52c2257
HJYP
135{
136 int i;
137
a52c2257
HJYP
138 RET();
139 DBG("desktop %d/%d\n", p->curdesk, p->desknum);
140 DBG("workarea\n");
141 for (i = 0; i < p->wa_len/4; i++)
142 DBG("(%d, %d) x (%d, %d)\n",
143 p->workarea[4*i + 0],
144 p->workarea[4*i + 1],
145 p->workarea[4*i + 2],
146 p->workarea[4*i + 3]);
147 RET();
148}
1d9dc649 149#endif
a52c2257 150
e996608e 151/* defined in plugins/menu.c */
8c44345a 152gboolean show_system_menu( gpointer system_menu );
e996608e 153
3e7b8eb7
HJYP
154/* defined in configurator.c */
155void panel_configure(Panel* p, int sel_page );
156
e996608e 157/* built-in commands, defined in configurator.c */
77886b88
HJYP
158void restart(void);
159void gtk_run(void);
e3b89f43 160void panel_destroy(Panel *p);
77886b88 161
d18c9409 162static void process_client_msg ( XClientMessageEvent* ev )
77886b88 163{
8c44345a 164 int cmd = ev->data.b[0];
77886b88
HJYP
165 switch( cmd )
166 {
167 case LXPANEL_CMD_SYS_MENU:
d18c9409
HJYP
168 {
169 GSList* l;
170 for( l = all_panels; l; l = l->next )
8c44345a 171 {
d18c9409
HJYP
172 Panel* p = (Panel*)l->data;
173 if( p->system_menus )
174 {
175 /* show_system_menu( p->system_menus->data ); */
176 /* FIXME: I've no idea why this doesn't work without timeout
177 under some WMs, like icewm. */
178 g_timeout_add( 200, (GSourceFunc)show_system_menu,
179 p->system_menus->data );
180 }
8c44345a 181 }
77886b88 182 break;
d18c9409 183 }
77886b88
HJYP
184 case LXPANEL_CMD_RUN:
185 gtk_run();
186 break;
187 case LXPANEL_CMD_CONFIG:
8110399f 188 //FIXME: configure();
77886b88
HJYP
189 break;
190 case LXPANEL_CMD_RESTART:
191 restart();
192 break;
193 case LXPANEL_CMD_EXIT:
194 gtk_main_quit();
195 break;
196 }
197}
198
a52c2257 199static GdkFilterReturn
cf701cb7 200panel_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer not_used)
a52c2257
HJYP
201{
202 Atom at;
203 Window win;
204 XEvent *ev = (XEvent *) xevent;
205
206 ENTER;
207 DBG("win = 0x%x\n", ev->xproperty.window);
77886b88
HJYP
208 if (ev->type != PropertyNotify ) {
209 /* private client message from lxpanelctl */
210 if( ev->type == ClientMessage && ev->xproperty.atom == a_LXPANEL_CMD )
211 {
d18c9409 212 process_client_msg( (XClientMessageEvent*)ev );
77886b88 213 }
22242ed4
HJYP
214 else if( ev->type == DestroyNotify )
215 {
cf701cb7 216 fb_ev_emit_destroy( fbev, ((XDestroyWindowEvent*)ev)->window );
22242ed4 217 }
a52c2257 218 RET(GDK_FILTER_CONTINUE);
24053345 219 }
77886b88 220
a52c2257
HJYP
221 at = ev->xproperty.atom;
222 win = ev->xproperty.window;
a52c2257 223 if (win == GDK_ROOT_WINDOW()) {
cf701cb7
HJYP
224 if (at == a_NET_CLIENT_LIST) {
225 fb_ev_emit(fbev, EV_CLIENT_LIST);
226 } else if (at == a_NET_CURRENT_DESKTOP) {
227 GSList* l;
228 for( l = all_panels; l; l = l->next )
229 ((Panel*)l->data)->curdesk = get_net_current_desktop();
22242ed4 230 fb_ev_emit(fbev, EV_CURRENT_DESKTOP);
cf701cb7
HJYP
231 } else if (at == a_NET_NUMBER_OF_DESKTOPS) {
232 GSList* l;
233 for( l = all_panels; l; l = l->next )
234 ((Panel*)l->data)->desknum = get_net_number_of_desktops();
22242ed4 235 fb_ev_emit(fbev, EV_NUMBER_OF_DESKTOPS);
cf701cb7 236 } else if (at == a_NET_DESKTOP_NAMES) {
22242ed4 237 fb_ev_emit(fbev, EV_DESKTOP_NAMES);
a52c2257 238 } else if (at == a_NET_ACTIVE_WINDOW) {
22242ed4 239 fb_ev_emit(fbev, EV_ACTIVE_WINDOW );
cf701cb7 240 } else if (at == a_NET_CLIENT_LIST_STACKING) {
22242ed4 241 fb_ev_emit(fbev, EV_CLIENT_LIST_STACKING);
a52c2257 242 } else if (at == a_XROOTPMAP_ID) {
cf701cb7
HJYP
243 GSList* l;
244 for( l = all_panels; l; l = l->next )
245 {
246 Panel* p = (Panel*)l->data;
247 if (p->transparent) {
248 fb_bg_notify_changed_bg(p->bg);
249 }
250 }
251 } else if (at == a_NET_WORKAREA) {
252 GSList* l;
253 for( l = all_panels; l; l = l->next )
254 {
255 Panel* p = (Panel*)l->data;
256 g_free( p->workarea );
257 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
1d9dc649 258 /* print_wmdata(p); */
a52c2257 259 }
a52c2257 260 } else
cf701cb7
HJYP
261 return GDK_FILTER_CONTINUE;
262
263 return GDK_FILTER_REMOVE;
a52c2257 264 }
cf701cb7 265 return GDK_FILTER_CONTINUE;
a52c2257
HJYP
266}
267
268/****************************************************
269 * panel's handlers for GTK events *
270 ****************************************************/
271
bee4c26e 272
a52c2257
HJYP
273static gint
274panel_delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
275{
276 ENTER;
277 RET(FALSE);
278}
279
280static gint
281panel_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer data)
282{
22242ed4 283 //Panel *p = (Panel *) data;
a52c2257
HJYP
284 //if (!p->self_destroy)
285 gtk_main_quit();
286 RET(FALSE);
287}
288
4542c20d 289static void
22242ed4 290on_root_bg_changed(FbBg *bg, Panel* p)
4542c20d
HJYP
291{
292 panel_update_background( p );
293}
294
295/* This function should only be called after the panel has been realized */
22242ed4 296void panel_update_background( Panel* p )
4542c20d
HJYP
297{
298 GList* l;
299 GdkPixmap* pixmap = NULL;
300
301 /* handle background image of panel */
302 gtk_widget_set_app_paintable(p->topgwin, TRUE);
303
304 if (p->background) {
305 pixmap = fb_bg_get_pix_from_file(p->topgwin, p->background_file);
306 if( p->bg )
307 {
308 g_object_unref( p->bg );
309 p->bg = NULL;
310 }
311 } else if (p->transparent) {
312 if( ! p->bg )
313 {
314 p->bg = fb_bg_get_for_display();
315 g_signal_connect(G_OBJECT(p->bg), "changed", G_CALLBACK(on_root_bg_changed), p);
316 }
317 pixmap = fb_bg_get_xroot_pix_for_win( p->bg, p->topgwin );
318
319 if (pixmap && pixmap != GDK_NO_BG) {
320 if (p->alpha)
321 fb_bg_composite( pixmap, p->topgwin->style->black_gc, p->tintcolor, p->alpha );
322 }
323 }
324 else
325 {
326 if( p->bg )
327 {
328 g_object_unref( p->bg );
329 p->bg = NULL;
330 }
331 }
332
333 if( pixmap )
334 {
335 gtk_widget_set_app_paintable( p->topgwin, TRUE );
336 gdk_window_set_back_pixmap( p->topgwin->window, pixmap, FALSE );
337 g_object_unref( pixmap );
338 }
339 else
340 {
341// gdk_window_set_back_pixmap( p->topgwin->window, p->topgwin->style->bg_pixmap[0], FALSE );
342 gtk_widget_set_app_paintable( p->topgwin, FALSE );
343// gdk_window_set_background( p->topgwin->window, &p->topgwin->style->bg[0] );
344 }
345
346 for( l = p->plugins; l; l = l->next )
347 {
22242ed4 348 Plugin* pl = (Plugin*)l->data;
4542c20d
HJYP
349 plugin_set_background( pl, p );
350 }
351
352 gdk_window_clear( p->topgwin->window );
353 gtk_widget_queue_draw( p->topgwin );
354}
a52c2257 355
84fc1d55
HJYP
356static gboolean delay_update_background( Panel* p )
357{
cbf65dac
HJYP
358 /* FIXME: can this work? */
359 gdk_display_sync( gtk_widget_get_display(p->topgwin) );
cf701cb7
HJYP
360 panel_update_background( p );
361 return FALSE;
84fc1d55
HJYP
362}
363
364static void
f2d54481
HJYP
365panel_realize(GtkWidget *widget, Panel *p)
366{
e3b89f43 367 g_idle_add_full( G_PRIORITY_LOW,
368 (GSourceFunc)delay_update_background, p, NULL );
f2d54481
HJYP
369}
370
371static void
84fc1d55
HJYP
372panel_style_set(GtkWidget *widget, GtkStyle* prev, Panel *p)
373{
0987f648 374 /* FIXME: This dirty hack is used to fix the background of systray... */
cf701cb7 375 if( GTK_WIDGET_REALIZED( widget ) )
e3b89f43 376 g_idle_add_full( G_PRIORITY_LOW,
377 (GSourceFunc)delay_update_background, p, NULL );
84fc1d55 378}
4542c20d 379
a52c2257 380static gint
22242ed4 381panel_size_req(GtkWidget *widget, GtkRequisition *req, Panel *p)
a52c2257
HJYP
382{
383 ENTER;
4542c20d 384
a52c2257
HJYP
385 if (p->widthtype == WIDTH_REQUEST)
386 p->width = (p->orientation == ORIENT_HORIZ) ? req->width : req->height;
387 if (p->heighttype == HEIGHT_REQUEST)
388 p->height = (p->orientation == ORIENT_HORIZ) ? req->height : req->width;
389 calculate_position(p);
390 req->width = p->aw;
391 req->height = p->ah;
4542c20d 392
a52c2257
HJYP
393 RET( TRUE );
394}
395
396static gint
22242ed4 397panel_size_alloc(GtkWidget *widget, GtkAllocation *a, Panel *p)
a52c2257
HJYP
398{
399 ENTER;
a52c2257
HJYP
400 if (p->widthtype == WIDTH_REQUEST)
401 p->width = (p->orientation == ORIENT_HORIZ) ? a->width : a->height;
402 if (p->heighttype == HEIGHT_REQUEST)
403 p->height = (p->orientation == ORIENT_HORIZ) ? a->height : a->width;
404 calculate_position(p);
4542c20d 405
a52c2257 406 if (a->width == p->aw && a->height == p->ah && a->x == p->ax && a->y == p ->ay) {
a52c2257
HJYP
407 RET(TRUE);
408 }
409
410 gtk_window_move(GTK_WINDOW(p->topgwin), p->ax, p->ay);
bee4c26e 411 panel_set_wm_strut(p);
a52c2257
HJYP
412 RET(TRUE);
413}
414
a52c2257 415static gboolean
22242ed4 416panel_configure_event (GtkWidget *widget, GdkEventConfigure *e, Panel *p)
a52c2257
HJYP
417{
418 ENTER;
419 if (e->width == p->cw && e->height == p->ch && e->x == p->cx && e->y == p->cy)
420 RET(TRUE);
421 p->cw = e->width;
422 p->ch = e->height;
423 p->cx = e->x;
424 p->cy = e->y;
4542c20d 425
a52c2257
HJYP
426 if (p->transparent)
427 fb_bg_notify_changed_bg(p->bg);
bee4c26e 428
4542c20d 429 RET(FALSE);
a52c2257
HJYP
430}
431
fddae119
FC
432static gint
433panel_popupmenu_configure(GtkWidget *widget, gpointer user_data)
434{
4b93d81e
HJYP
435 panel_configure( (Panel*)user_data, 0 );
436 return TRUE;
fddae119
FC
437}
438
439static gint
440panel_press_button_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
441{
442 GdkEventButton *event_button;
cf701cb7 443 GtkWidget* img;
fddae119
FC
444
445 g_return_val_if_fail (event != NULL, FALSE);
446 event_button = (GdkEventButton *)event;
447 if (event_button->button == 3) {
e3b89f43 448 GtkMenu *menu;
cf701cb7 449 Panel* panel = (Panel*)user_data;
fddae119 450 /* create menu */
3e7b8eb7 451 menu = lxpanel_get_panel_menu( panel, NULL, FALSE );
fddae119
FC
452 gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event_button->button, event_button->time);
453 return TRUE;
454 }
455
456 return FALSE;
457}
458
cf701cb7
HJYP
459static void panel_popupmenu_config_plugin( GtkMenuItem* item, Plugin* plugin )
460{
e3b89f43 461 plugin->class->config( plugin, GTK_WINDOW(plugin->panel->topgwin) );
930af9fd
HJYP
462
463 /* FIXME: this should be more elegant */
464 plugin->panel->config_changed = TRUE;
cf701cb7
HJYP
465}
466
4b93d81e
HJYP
467#if 0
468static void on_add_plugin_response( GtkDialog* dlg,
469 int response,
470 Panel* p )
cf701cb7 471{
4b93d81e
HJYP
472 if( response == GTK_RESPONSE_OK )
473 {
474 GtkTreeView* view;
475 GtkTreeSelection* tree_sel;
476 GtkTreeIter it;
477 GtkTreeModel* model;
478
479 view = (GtkTreeView*)g_object_get_data( G_OBJECT(dlg), "avail-plugins" );
480 tree_sel = gtk_tree_view_get_selection( view );
481 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
482 {
483 char* type = NULL;
484 Plugin* pl;
485 gtk_tree_model_get( model, &it, 1, &type, -1 );
486 if( pl = plugin_load( type ) )
487 {
488 GtkTreePath* tree_path;
cf701cb7 489
4b93d81e
HJYP
490 pl->panel = p;
491 plugin_start( pl, NULL );
492 p->plugins = g_list_append(p->plugins, pl);
493 /* FIXME: will show all cause problems? */
494 gtk_widget_show_all( pl->pwid );
495
496 /* update background of the newly added plugin */
497 plugin_widget_set_background( pl->pwid, pl->panel );
498 }
499 g_free( type );
500 }
501 }
502 gtk_widget_destroy( (GtkWidget*)dlg );
503}
504
505void panel_add_plugin( Panel* panel, GtkWindow* parent_win )
506{
507 GtkWidget* dlg, *scroll;
508 GList* classes;
509 GList* tmp;
510 GtkTreeViewColumn* col;
511 GtkCellRenderer* render;
512 GtkTreeView* view;
513 GtkListStore* list;
514 GtkTreeSelection* tree_sel;
515
516 classes = plugin_get_available_classes();
517
518 dlg = gtk_dialog_new_with_buttons( _("Add plugin to panel"),
519 GTK_WINDOW(parent_win), 0,
520 GTK_STOCK_CANCEL,
521 GTK_RESPONSE_CANCEL,
522 GTK_STOCK_ADD,
523 GTK_RESPONSE_OK, NULL );
524
525 /* gtk_widget_set_sensitive( parent_win, FALSE ); */
526 scroll = gtk_scrolled_window_new( NULL, NULL );
527 gtk_scrolled_window_set_shadow_type( (GtkScrolledWindow*)scroll,
528 GTK_SHADOW_IN );
529 gtk_scrolled_window_set_policy((GtkScrolledWindow*)scroll,
530 GTK_POLICY_AUTOMATIC,
531 GTK_POLICY_AUTOMATIC );
532 gtk_box_pack_start( (GtkBox*)GTK_DIALOG(dlg)->vbox, scroll,
533 TRUE, TRUE, 4 );
534 view = (GtkTreeView*)gtk_tree_view_new();
535 gtk_container_add( (GtkContainer*)scroll, view );
536 tree_sel = gtk_tree_view_get_selection( view );
537 gtk_tree_selection_set_mode( tree_sel, GTK_SELECTION_BROWSE );
538
539 render = gtk_cell_renderer_text_new();
540 col = gtk_tree_view_column_new_with_attributes(
541 _("Available plugins"),
542 render, "text", 0, NULL );
543 gtk_tree_view_append_column( view, col );
544
545 list = gtk_list_store_new( 2,
546 G_TYPE_STRING,
547 G_TYPE_STRING );
548
549 for( tmp = classes; tmp; tmp = tmp->next ) {
550 PluginClass* pc = (PluginClass*)tmp->data;
551 if( ! pc->invisible ) {
552 /* FIXME: should we display invisible plugins? */
553 GtkTreeIter it;
554 gtk_list_store_append( list, &it );
555 gtk_list_store_set( list, &it,
556 0, _(pc->name),
557 1, pc->type, -1 );
558 /* g_debug( "%s (%s)", pc->type, _(pc->name) ); */
559 }
560 }
561
562 gtk_tree_view_set_model( view, GTK_TREE_MODEL(list) );
563 g_object_unref( list );
564
565 g_signal_connect( dlg, "response",
566 on_add_plugin_response, panel );
567 g_object_set_data( dlg, "avail-plugins", view );
568 g_object_weak_ref( dlg, plugin_class_list_free, classes );
569
570 gtk_window_set_default_size( (GtkWindow*)dlg, 320, 400 );
571 gtk_widget_show_all( dlg );
572}
573#endif
574
575static void panel_popupmenu_add_item( GtkMenuItem* item, Panel* panel )
576{
577 /* panel_add_plugin( panel, panel->topgwin ); */
578 panel_configure( panel, 1 );
cf701cb7
HJYP
579}
580
581static void panel_popupmenu_remove_item( GtkMenuItem* item, Plugin* plugin )
582{
583 Panel* panel = plugin->panel;
584 panel->plugins = g_list_remove( panel->plugins, plugin );
585 plugin_stop( plugin ); /* free the plugin widget & its data */
586 plugin_put( plugin ); /* free the lib if necessary */
4b93d81e
HJYP
587
588 panel_config_save( plugin->panel );
cf701cb7
HJYP
589}
590
3e7b8eb7
HJYP
591/* FIXME: Potentially we can support multiple panels at the same edge,
592 * but currently this cannot be done due to some positioning problems. */
593static char* gen_panel_name( int edge )
594{
595 const char* edge_str = num2str( edge_pair, edge, "" );
596 char* name = NULL;
597 char* dir = get_config_file( cprofile, "panels", FALSE );
598 int i;
599 for( i = 0; i < G_MAXINT; ++i )
600 {
601 char* f;
602 if( G_LIKELY( i > 0 ) )
603 name = g_strdup_printf( "%s%d", edge_str, i );
604 else
605 name = g_strdup( edge_str );
606 f = g_build_filename( dir, name, NULL );
607 if( ! g_file_test( f, G_FILE_TEST_EXISTS ) )
608 {
609 g_free( f );
610 break;
611 }
612 g_free( name );
613 g_free( f );
614 }
615 g_free( dir );
616 return name;
617}
618
619/* FIXME: Potentially we can support multiple panels at the same edge,
620 * but currently this cannot be done due to some positioning problems. */
cf701cb7
HJYP
621static void panel_popupmenu_create_panel( GtkMenuItem* item, Panel* panel )
622{
3e7b8eb7
HJYP
623 int i;
624 GSList* group = NULL;
625 GtkWidget* btns[ 4 ], *box, *frame;
626 const char* edges[]={N_("Left"), N_("Right"), N_("Top"), N_("Bottom")};
7414a73f
HJYP
627 GtkWidget* dlg = gtk_dialog_new_with_buttons(
628 _("Create New Panel"),
e3b89f43 629 GTK_WINDOW(panel->topgwin),
7414a73f
HJYP
630 GTK_DIALOG_MODAL,
631 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
632 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL );
3e7b8eb7
HJYP
633 gtk_container_set_border_width( (GtkContainer*)dlg, 8 );
634 frame = gtk_frame_new( _("Where to put the panel?"));
635 gtk_box_pack_start( (GtkBox*)((GtkDialog*)dlg)->vbox, frame, TRUE, TRUE, 0 );
636 box = gtk_vbox_new( FALSE, 2 );
637 gtk_container_add( (GtkContainer*)frame, box );
638 for( i = 0; i < 4; ++i )
639 {
640 GSList* l;
641 btns[ i ] = gtk_radio_button_new_with_label( group, _(edges[i]) );
642 group = gtk_radio_button_get_group( (GtkRadioButton*)btns[ i ] );
e3b89f43 643 gtk_box_pack_start( GTK_BOX(box), btns[ i ], FALSE, TRUE, 2 );
3e7b8eb7
HJYP
644 for( l = all_panels; l; l = l->next )
645 {
646 Panel* p = (Panel*)l->data;
647 /* If there is already a panel on this edge */
648 if( p->edge == (i + 1) )
649 gtk_widget_set_sensitive( btns[i], FALSE );
650 /* FIXME: multiple panel at the same edge should be supported in the future. */
651 }
652 }
653 gtk_widget_show_all( dlg );
654
e3b89f43 655 if( gtk_dialog_run( GTK_DIALOG(dlg) ) == GTK_RESPONSE_OK )
3e7b8eb7
HJYP
656 {
657 char* pfp;
658 char default_conf[128];
659 for( i = 0; i < 4; ++i )
660 {
661 if( gtk_toggle_button_get_active( (GtkToggleButton*)btns[i] ) )
662 break;
663 }
664 ++i; /* 0 is EDGE_NONE, all edge values start from 1 */
665 g_snprintf( default_conf, 128,
666 "global{\n"
667 "edge=%s\n"
668 "}\n",
669 num2str( edge_pair, i, "bottom" ) );
670 panel = g_slice_new0( Panel );
671 panel->name = gen_panel_name(i);
672 pfp = default_conf;
673 if ( panel_start( panel, &pfp )) {
674 panel_config_save( panel );
675 all_panels = g_slist_prepend( all_panels, panel );
676 }
677 else {
678 panel_destroy( panel );
679 }
680 }
7414a73f 681 gtk_widget_destroy( dlg );
cf701cb7
HJYP
682}
683
684static void panel_popupmenu_delete_panel( GtkMenuItem* item, Panel* panel )
685{
686 GtkWidget* dlg;
687 gboolean ok;
e3b89f43 688 dlg = gtk_message_dialog_new_with_markup( GTK_WINDOW(panel->topgwin),
cf701cb7
HJYP
689 GTK_DIALOG_MODAL,
690 GTK_MESSAGE_QUESTION,
691 GTK_BUTTONS_OK_CANCEL,
692 _("Really delete this panel?\n<b>Warning: This can not be recovered.</b>") );
693 gtk_window_set_title( (GtkWindow*)dlg, _("Confirm") );
694 ok = ( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK );
695 gtk_widget_destroy( dlg );
696 if( ok )
697 {
4b93d81e 698 gchar *fname, *dir;
cf701cb7 699 all_panels = g_slist_remove( all_panels, panel );
4b93d81e
HJYP
700
701 /* delete the config file of this panel */
702 dir = get_config_file( cprofile, "panels", FALSE );
703 fname = g_build_filename( dir, panel->name, NULL );
704 g_free( dir );
705 g_unlink( fname );
930af9fd 706 panel->config_changed = 0;
cf701cb7
HJYP
707 panel_destroy( panel );
708 }
709}
710
e3b89f43 711extern GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
cf701cb7 712{
e3b89f43 713 GtkWidget *menu_item, *img;
714 GtkMenu *ret,*menu;
715
cf701cb7 716 char* tmp;
e3b89f43 717 ret = menu = GTK_MENU(gtk_menu_new());
cf701cb7 718
4b93d81e 719/*
cf701cb7
HJYP
720 img = gtk_image_new_from_stock( GTK_STOCK_ADD, GTK_ICON_SIZE_MENU );
721 menu_item = gtk_image_menu_item_new_with_label(_("Add Item To Panel"));
722 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
723 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
724 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
4b93d81e
HJYP
725*/
726
727 img = gtk_image_new_from_stock( GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU );
728 menu_item = gtk_image_menu_item_new_with_label(_("Add / Remove Panel Items"));
729 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
730 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
731 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
cf701cb7
HJYP
732
733 if( plugin )
734 {
735 img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
736 tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(plugin->class->name) );
737 menu_item = gtk_image_menu_item_new_with_label( tmp );
738 g_free( tmp );
739 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
740 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
741 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_remove_item), plugin );
742 }
743
744 menu_item = gtk_separator_menu_item_new();
745 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
746
4b93d81e
HJYP
747 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
748 menu_item = gtk_image_menu_item_new_with_label(_("Panel Settings"));
749 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
750 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
751 g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_popupmenu_configure), panel );
752
cf701cb7
HJYP
753 img = gtk_image_new_from_stock( GTK_STOCK_NEW, GTK_ICON_SIZE_MENU );
754 menu_item = gtk_image_menu_item_new_with_label(_("Create New Panel"));
755 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
756 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
757 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_create_panel), panel );
3e7b8eb7
HJYP
758 /* FIXME: Potentially we can support multiple panels at the same edge,
759 * but currently this cannot be done due to some positioning problems. */
760 /* currently, disable the option when there are already four panels */
761 if( g_slist_length( all_panels ) >= 4 )
762 gtk_widget_set_sensitive( menu_item, FALSE );
cf701cb7
HJYP
763
764 img = gtk_image_new_from_stock( GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU );
765 menu_item = gtk_image_menu_item_new_with_label(_("Delete This Panel"));
766 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
767 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
768 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_delete_panel), panel );
769 if( ! all_panels->next ) /* if this is the only panel */
770 gtk_widget_set_sensitive( menu_item, FALSE );
771
cf701cb7
HJYP
772 if( use_sub_menu )
773 {
e3b89f43 774 ret = GTK_MENU(gtk_menu_new());
cf701cb7
HJYP
775 menu_item = gtk_image_menu_item_new_with_label(_("Panel"));
776 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
e3b89f43 777 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), GTK_WIDGET(menu) );
cf701cb7 778
e3b89f43 779 gtk_widget_show_all(GTK_WIDGET(ret));
cf701cb7
HJYP
780 }
781
3e7b8eb7
HJYP
782 if( plugin )
783 {
784 menu_item = gtk_separator_menu_item_new();
785 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
786
787 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
788 tmp = g_strdup_printf( _("\"%s\" Settings"), _(plugin->class->name) );
789 menu_item = gtk_image_menu_item_new_with_label( tmp );
790 g_free( tmp );
791 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
792 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
793 if( plugin->class->config )
794 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
795 else
796 gtk_widget_set_sensitive( menu_item, FALSE );
797 }
798
e3b89f43 799 gtk_widget_show_all(GTK_WIDGET(menu));
3e7b8eb7 800
cf701cb7
HJYP
801 g_signal_connect( ret, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
802 return ret;
803}
804
a52c2257
HJYP
805/****************************************************
806 * panel creation *
807 ****************************************************/
808static void
22242ed4 809make_round_corners(Panel *p)
a52c2257 810{
a97d06a6 811 /* FIXME: This should be re-written with shape extension of X11 */
4542c20d 812 /* gdk_window_shape_combine_mask() can be used */
bee4c26e
HJYP
813}
814
22242ed4 815void panel_set_dock_type(Panel *p)
bee4c26e
HJYP
816{
817 if (p->setdocktype) {
818 Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
819 XChangeProperty(GDK_DISPLAY(), p->topxwin,
820 a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
821 PropModeReplace, (unsigned char *) &state, 1);
822 }
823 else {
824 XDeleteProperty( GDK_DISPLAY(), p->topxwin, a_NET_WM_WINDOW_TYPE );
825 }
a52c2257
HJYP
826}
827
0defe4b9 828static void
22242ed4 829panel_start_gui(Panel *p)
a52c2257
HJYP
830{
831 Atom state[3];
832 XWMHints wmhints;
833 guint32 val;
6db11841 834
a52c2257
HJYP
835 ENTER;
836
837 // main toplevel window
838 p->topgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
839 gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
840 gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
841 gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "lxpanel");
842 gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
843 gtk_window_set_position(GTK_WINDOW(p->topgwin), GTK_WIN_POS_NONE);
844 gtk_window_set_decorated(GTK_WINDOW(p->topgwin), FALSE);
77886b88 845
e2957bd2
HJYP
846 gtk_window_group_add_window( win_grp, (GtkWindow*)p->topgwin );
847
a52c2257
HJYP
848 g_signal_connect(G_OBJECT(p->topgwin), "delete-event",
849 G_CALLBACK(panel_delete_event), p);
850 g_signal_connect(G_OBJECT(p->topgwin), "destroy-event",
851 G_CALLBACK(panel_destroy_event), p);
852 g_signal_connect (G_OBJECT (p->topgwin), "size-request",
853 (GCallback) panel_size_req, p);
854 g_signal_connect (G_OBJECT (p->topgwin), "size-allocate",
855 (GCallback) panel_size_alloc, p);
856 g_signal_connect (G_OBJECT (p->topgwin), "configure-event",
857 (GCallback) panel_configure_event, p);
3e7b8eb7
HJYP
858
859 gtk_widget_add_events( p->topgwin, GDK_BUTTON_PRESS_MASK );
fddae119 860 g_signal_connect(G_OBJECT (p->topgwin), "button_press_event",
8110399f 861 (GCallback) panel_press_button_event, p);
f2d54481 862
a52c2257
HJYP
863 g_signal_connect (G_OBJECT (p->topgwin), "realize",
864 (GCallback) panel_realize, p);
f2d54481 865
84fc1d55
HJYP
866 g_signal_connect (G_OBJECT (p->topgwin), "style-set",
867 (GCallback)panel_style_set, p);
a52c2257
HJYP
868 gtk_widget_realize(p->topgwin);
869 //gdk_window_set_decorations(p->topgwin->window, 0);
2de71c90 870
4542c20d 871 // main layout manager as a single child of panel
a97d06a6 872 p->box = p->my_box_new(FALSE, 0);
a52c2257 873 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
4542c20d
HJYP
874// gtk_container_add(GTK_CONTAINER(p->bbox), p->box);
875 gtk_container_add(GTK_CONTAINER(p->topgwin), p->box);
a52c2257 876 gtk_widget_show(p->box);
a97d06a6
HJYP
877 if (p->round_corners)
878 make_round_corners(p);
6db11841 879
a52c2257
HJYP
880 p->topxwin = GDK_WINDOW_XWINDOW(GTK_WIDGET(p->topgwin)->window);
881 DBG("topxwin = %x\n", p->topxwin);
882
883 /* the settings that should be done before window is mapped */
884 wmhints.flags = InputHint;
885 wmhints.input = 0;
bee4c26e 886 XSetWMHints (GDK_DISPLAY(), p->topxwin, &wmhints);
24053345 887#define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
a52c2257
HJYP
888 val = WIN_HINTS_SKIP_FOCUS;
889 XChangeProperty(GDK_DISPLAY(), p->topxwin,
890 XInternAtom(GDK_DISPLAY(), "_WIN_HINTS", False), XA_CARDINAL, 32,
891 PropModeReplace, (unsigned char *) &val, 1);
892
bee4c26e 893 panel_set_dock_type(p);
a52c2257
HJYP
894
895 /* window mapping point */
896 gtk_widget_show_all(p->topgwin);
897
898 /* the settings that should be done after window is mapped */
899
900 /* send it to running wm */
901 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
902 /* and assign it ourself just for case when wm is not running */
903 val = 0xFFFFFFFF;
904 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
905 PropModeReplace, (unsigned char *) &val, 1);
906
907 state[0] = a_NET_WM_STATE_SKIP_PAGER;
908 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
909 state[2] = a_NET_WM_STATE_STICKY;
910 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STATE, XA_ATOM,
911 32, PropModeReplace, (unsigned char *) state, 3);
912
a52c2257
HJYP
913 calculate_position(p);
914 gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
bee4c26e 915 panel_set_wm_strut(p);
77886b88 916
a52c2257
HJYP
917 RET();
918}
919
22242ed4 920void panel_set_orientation(Panel *p)
a97d06a6
HJYP
921{
922 GList* l;
923 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
924 ? ORIENT_HORIZ : ORIENT_VERT;
925 if (p->orientation == ORIENT_HORIZ) {
926 p->my_box_new = gtk_hbox_new;
927 p->my_separator_new = gtk_vseparator_new;
928 } else {
929 p->my_box_new = gtk_vbox_new;
930 p->my_separator_new = gtk_hseparator_new;
931 }
932
933 /* recreate the main layout box */
934 if( p->box ) {
5a343ad5
JH
935 GtkBox* newbox = GTK_BOX(recreate_box( GTK_BOX(p->box), p->orientation ));
936 if( GTK_WIDGET(newbox) != p->box ) {
937 p->box = GTK_WIDGET(newbox);
4542c20d 938 gtk_container_add( GTK_CONTAINER(p->topgwin), GTK_WIDGET(newbox) );
a97d06a6
HJYP
939 }
940 }
941 /* NOTE: This loop won't be executed when panel started since
942 plugins are not loaded at that time.
943 This is used when the orientation of the panel is changed
944 from the config dialog, and plugins should be re-layout.
945 */
946 for( l = p->plugins; l; l = l->next ) {
22242ed4 947 Plugin* pl = (Plugin*)l->data;
a97d06a6
HJYP
948 if( pl->class->orientation ) {
949 pl->class->orientation( pl );
950 }
951 }
952}
953
a52c2257 954static int
22242ed4 955panel_parse_global(Panel *p, char **fp)
a52c2257
HJYP
956{
957 line s;
958 s.len = 256;
6db11841 959
3e7b8eb7
HJYP
960 if( G_LIKELY( fp ) )
961 {
962 while (lxpanel_get_line(fp, &s) != LINE_NONE) {
963 if (s.type == LINE_VAR) {
964 if (!g_ascii_strcasecmp(s.t[0], "edge")) {
965 p->edge = str2num(edge_pair, s.t[1], EDGE_NONE);
966 } else if (!g_ascii_strcasecmp(s.t[0], "allign")) {
967 p->allign = str2num(allign_pair, s.t[1], ALLIGN_NONE);
968 } else if (!g_ascii_strcasecmp(s.t[0], "margin")) {
969 p->margin = atoi(s.t[1]);
970 } else if (!g_ascii_strcasecmp(s.t[0], "widthtype")) {
971 p->widthtype = str2num(width_pair, s.t[1], WIDTH_NONE);
972 } else if (!g_ascii_strcasecmp(s.t[0], "width")) {
973 p->width = atoi(s.t[1]);
974 } else if (!g_ascii_strcasecmp(s.t[0], "heighttype")) {
975 p->heighttype = str2num(height_pair, s.t[1], HEIGHT_NONE);
976 } else if (!g_ascii_strcasecmp(s.t[0], "height")) {
977 p->height = atoi(s.t[1]);
978 } else if (!g_ascii_strcasecmp(s.t[0], "spacing")) {
979 p->spacing = atoi(s.t[1]);
980 } else if (!g_ascii_strcasecmp(s.t[0], "SetDockType")) {
981 p->setdocktype = str2num(bool_pair, s.t[1], 0);
982 } else if (!g_ascii_strcasecmp(s.t[0], "SetPartialStrut")) {
983 p->setstrut = str2num(bool_pair, s.t[1], 0);
984 } else if (!g_ascii_strcasecmp(s.t[0], "RoundCorners")) {
985 p->round_corners = str2num(bool_pair, s.t[1], 0);
986 } else if (!g_ascii_strcasecmp(s.t[0], "Transparent")) {
987 p->transparent = str2num(bool_pair, s.t[1], 0);
988 } else if (!g_ascii_strcasecmp(s.t[0], "Alpha")) {
989 p->alpha = atoi(s.t[1]);
990 if (p->alpha > 255)
991 p->alpha = 255;
992 } else if (!g_ascii_strcasecmp(s.t[0], "TintColor")) {
993 if (!gdk_color_parse (s.t[1], &p->gtintcolor))
994 gdk_color_parse ("white", &p->gtintcolor);
995 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
996 DBG("tintcolor=%x\n", p->tintcolor);
997 } else if (!g_ascii_strcasecmp(s.t[0], "useFontColor")) {
998 p->usefontcolor = str2num(bool_pair, s.t[1], 0);
999 } else if (!g_ascii_strcasecmp(s.t[0], "FontColor")) {
1000 if (!gdk_color_parse (s.t[1], &p->gfontcolor))
1001 gdk_color_parse ("black", &p->gfontcolor);
1002 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
1003 DBG("fontcolor=%x\n", p->fontcolor);
1004 } else if (!g_ascii_strcasecmp(s.t[0], "Background")) {
1005 p->background = str2num(bool_pair, s.t[1], 0);
1006 } else if( !g_ascii_strcasecmp(s.t[0], "BackgroundFile") ) {
1007 p->background_file = g_strdup( s.t[1] );
1008 } else {
1009 ERR( "lxpanel: %s - unknown var in Global section\n", s.t[0]);
1010 RET(0);
1011 }
1012 } else if (s.type == LINE_BLOCK_END) {
1013 break;
a52c2257 1014 } else {
3e7b8eb7 1015 ERR( "lxpanel: illegal in this context %s\n", s.str);
a52c2257
HJYP
1016 RET(0);
1017 }
a52c2257
HJYP
1018 }
1019 }
a97d06a6 1020 panel_set_orientation( p );
4542c20d 1021
a52c2257
HJYP
1022 if (p->width < 0)
1023 p->width = 100;
1024 if (p->widthtype == WIDTH_PERCENT && p->width > 100)
1025 p->width = 100;
1026 p->heighttype = HEIGHT_PIXEL;
1027 if (p->heighttype == HEIGHT_PIXEL) {
1028 if (p->height < PANEL_HEIGHT_MIN)
1029 p->height = PANEL_HEIGHT_MIN;
1030 else if (p->height > PANEL_HEIGHT_MAX)
1031 p->height = PANEL_HEIGHT_MAX;
1032 }
2de71c90
FC
1033
1034 if (p->background)
1035 p->transparent = 0;
1036
a52c2257
HJYP
1037 p->curdesk = get_net_current_desktop();
1038 p->desknum = get_net_number_of_desktops();
1039 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
1d9dc649 1040 /* print_wmdata(p); */
239cb032 1041
a52c2257
HJYP
1042 panel_start_gui(p);
1043 RET(1);
1044}
1045
1046static int
22242ed4 1047panel_parse_plugin(Panel *p, char **fp)
a52c2257
HJYP
1048{
1049 line s;
22242ed4 1050 Plugin *plug = NULL;
a52c2257 1051 gchar *type = NULL;
a52c2257 1052 int expand , padding, border;
db449f6e
HJYP
1053 char* pconfig = NULL;
1054
a52c2257
HJYP
1055 ENTER;
1056 s.len = 256;
a52c2257 1057 border = expand = padding = 0;
c69ac68e 1058 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
a52c2257
HJYP
1059 if (s.type == LINE_NONE) {
1060 ERR( "lxpanel: bad line %s\n", s.str);
1061 goto error;
1062 }
1063 if (s.type == LINE_VAR) {
1064 if (!g_ascii_strcasecmp(s.t[0], "type")) {
1065 type = g_strdup(s.t[1]);
1066 DBG("plug %s\n", type);
1067 } else if (!g_ascii_strcasecmp(s.t[0], "expand"))
1068 expand = str2num(bool_pair, s.t[1], 0);
1069 else if (!g_ascii_strcasecmp(s.t[0], "padding"))
1070 padding = atoi(s.t[1]);
1071 else if (!g_ascii_strcasecmp(s.t[0], "border"))
1072 border = atoi(s.t[1]);
1073 else {
1074 ERR( "lxpanel: unknown var %s\n", s.t[0]);
1075 goto error;
1076 }
1077 } else if (s.type == LINE_BLOCK_START) {
1078 if (!g_ascii_strcasecmp(s.t[0], "Config")) {
db449f6e 1079 pconfig = *fp;
a52c2257
HJYP
1080 int pno = 1;
1081 while (pno) {
1082 get_line_as_is(fp, &s);
1083 if (s.type == LINE_NONE) {
1084 ERR( "lxpanel: unexpected eof\n");
1085 goto error;
1086 } else if (s.type == LINE_BLOCK_START) {
1087 pno++;
1088 } else if (s.type == LINE_BLOCK_END) {
1089 pno--;
bee4c26e 1090 }
db449f6e 1091 }
a52c2257
HJYP
1092 } else {
1093 ERR( "lxpanel: unknown block %s\n", s.t[0]);
1094 goto error;
1095 }
1096 } else {
1097 ERR( "lxpanel: illegal in this context %s\n", s.str);
1098 goto error;
1099 }
1100 }
db449f6e 1101
a52c2257
HJYP
1102 if (!type || !(plug = plugin_load(type))) {
1103 ERR( "lxpanel: can't load %s plugin\n", type);
1104 goto error;
1105 }
db449f6e 1106
a52c2257 1107 plug->panel = p;
a52c2257
HJYP
1108 plug->expand = expand;
1109 plug->padding = padding;
1110 plug->border = border;
a52c2257 1111 DBG("starting\n");
db449f6e 1112 if (!plugin_start(plug, pconfig ? &pconfig : NULL)) {
a52c2257
HJYP
1113 ERR( "lxpanel: can't start plugin %s\n", type);
1114 goto error;
1115 }
1116 DBG("plug %s\n", type);
1117 p->plugins = g_list_append(p->plugins, plug);
0dcb6bf5
HJYP
1118
1119 g_free( type );
a52c2257 1120 RET(1);
db449f6e 1121
a52c2257 1122 error:
a52c2257
HJYP
1123 g_free(type);
1124 if (plug)
1125 plugin_put(plug);
1126 RET(0);
a52c2257
HJYP
1127}
1128
3e7b8eb7 1129int panel_start( Panel *p, char **fp )
a52c2257
HJYP
1130{
1131 line s;
db449f6e 1132
a52c2257
HJYP
1133 /* parse global section */
1134 ENTER;
1135 s.len = 256;
8110399f 1136
a52c2257
HJYP
1137 p->allign = ALLIGN_CENTER;
1138 p->edge = EDGE_BOTTOM;
1139 p->widthtype = WIDTH_PERCENT;
1140 p->width = 100;
1141 p->heighttype = HEIGHT_PIXEL;
1142 p->height = PANEL_HEIGHT_DEFAULT;
1143 p->setdocktype = 1;
1144 p->setstrut = 1;
1145 p->round_corners = 0;
1146 p->transparent = 0;
1147 p->alpha = 127;
1148 p->tintcolor = 0xFFFFFFFF;
2de71c90
FC
1149 p->usefontcolor = 0;
1150 p->fontcolor = 0x00000000;
a52c2257 1151 p->spacing = 0;
22242ed4 1152
c69ac68e 1153 if ((lxpanel_get_line(fp, &s) != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Global")) {
a52c2257
HJYP
1154 ERR( "lxpanel: config file must start from Global section\n");
1155 RET(0);
1156 }
1157 if (!panel_parse_global(p, fp))
1158 RET(0);
1159
c69ac68e 1160 while (lxpanel_get_line(fp, &s) != LINE_NONE) {
a52c2257
HJYP
1161 if ((s.type != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Plugin")) {
1162 ERR( "lxpanel: expecting Plugin section\n");
1163 RET(0);
1164 }
9939506e 1165 panel_parse_plugin(p, fp);
a52c2257
HJYP
1166 }
1167 gtk_widget_show_all(p->topgwin);
4542c20d
HJYP
1168
1169 /* update backgrond of panel and all plugins */
1170 panel_update_background( p );
1171
1d9dc649 1172 /* print_wmdata(p); */
a52c2257
HJYP
1173 RET(1);
1174}
1175
1176static void
1177delete_plugin(gpointer data, gpointer udata)
1178{
1179 ENTER;
22242ed4
HJYP
1180 plugin_stop((Plugin *)data);
1181 plugin_put((Plugin *)data);
a52c2257 1182 RET();
a52c2257
HJYP
1183}
1184
8110399f 1185void panel_destroy(Panel *p)
a52c2257
HJYP
1186{
1187 ENTER;
1188
930af9fd
HJYP
1189 if( p->config_changed )
1190 panel_config_save( p );
1191
a52c2257
HJYP
1192 g_list_foreach(p->plugins, delete_plugin, NULL);
1193 g_list_free(p->plugins);
1194 p->plugins = NULL;
8c44345a 1195
5297da29 1196 if( p->system_menus ){
8c44345a 1197 do{
5297da29 1198 } while ( g_source_remove_by_user_data( p->system_menus ) );
8c44345a
HJYP
1199 }
1200
e2957bd2
HJYP
1201 gtk_window_group_remove_window(win_grp, p->topgwin);
1202
4b93d81e
HJYP
1203 if( p->topgwin )
1204 gtk_widget_destroy(p->topgwin);
a52c2257 1205 g_free(p->workarea);
2de71c90 1206 g_free( p->background_file );
5297da29 1207 g_slist_free( p->system_menus );
a52c2257
HJYP
1208 gdk_flush();
1209 XFlush(GDK_DISPLAY());
1210 XSync(GDK_DISPLAY(), True);
8110399f
HJYP
1211
1212 g_free( p->name );
cf701cb7 1213 g_slice_free( Panel, p );
a52c2257
HJYP
1214 RET();
1215}
1216
8110399f
HJYP
1217Panel* panel_new( const char* config_file, const char* config_name )
1218{
1219 char *fp, *pfp; /* point to current position of profile data in memory */
cf701cb7 1220 Panel* panel = NULL;
8110399f 1221 char* ret;
3e7b8eb7 1222 if( G_LIKELY(config_file) )
cf701cb7 1223 {
3e7b8eb7
HJYP
1224 g_file_get_contents( config_file, &fp, NULL, NULL );
1225 if( fp )
1226 {
1227 panel = g_slice_new0( Panel );
1228 panel->name = g_strdup( config_name );
1229 pfp = fp;
1230
1231 if (! panel_start( panel, &pfp )) {
1232 ERR( "lxpanel: can't start panel\n");
1233 panel_destroy( panel );
1234 panel = NULL;
1235 }
cf701cb7 1236
3e7b8eb7 1237 g_free( fp );
cf701cb7 1238 }
cf701cb7
HJYP
1239 }
1240 return panel;
8110399f 1241}
a52c2257 1242
0defe4b9 1243static void
a52c2257
HJYP
1244usage()
1245{
e7cb732b
HJYP
1246 g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
1247 g_print(_("Command line options:\n"));
1248 g_print(_(" --help -- print this help and exit\n"));
1249 g_print(_(" --version -- print version and exit\n"));
1250 g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
1251 g_print(_(" --configure -- launch configuration utility\n"));
1252 g_print(_(" --profile name -- use specified profile\n"));
1253 g_print("\n");
1254 g_print(_(" -h -- same as --help\n"));
1255 g_print(_(" -p -- same as --profile\n"));
1256 g_print(_(" -v -- same as --version\n"));
1257 g_print(_(" -C -- same as --configure\n"));
b37c9aae 1258 g_print(_("\nVisit http://lxde.org/ for detail.\n\n"));
a52c2257
HJYP
1259}
1260
e68b47dc 1261static void
a52c2257
HJYP
1262handle_error(Display * d, XErrorEvent * ev)
1263{
1264 char buf[256];
1265
1266 ENTER;
1267 if (log_level >= LOG_WARN) {
1268 XGetErrorText(GDK_DISPLAY(), ev->error_code, buf, 256);
1269 LOG(LOG_WARN, "lxpanel : X error: %s\n", buf);
1270 }
1271 RET();
1272}
1273
e68b47dc
JH
1274/* Lightweight lock related functions - X clipboard hacks */
1275
1276#define CLIPBOARD_NAME "LXPANEL_SELECTION"
1277
1278/*
1279 * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
1280 */
1281static void
1282clipboard_get_func(
1283 GtkClipboard *clipboard G_GNUC_UNUSED,
1284 GtkSelectionData *selection_data G_GNUC_UNUSED,
1285 guint info G_GNUC_UNUSED,
1286 gpointer user_data_or_owner G_GNUC_UNUSED)
1287{
1288}
1289
1290/*
1291 * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
1292 */
1293static void clipboard_clear_func(
1294 GtkClipboard *clipboard G_GNUC_UNUSED,
1295 gpointer user_data_or_owner G_GNUC_UNUSED)
1296{
1297}
1298
1299/*
1300 * Lightweight version for checking single instance.
1301 * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
1302 *
1303 * Returns TRUE if successfully retrieved and FALSE otherwise.
1304 */
16fb8c2e 1305static gboolean check_main_lock()
e68b47dc
JH
1306{
1307 static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
1308 gboolean retval = FALSE;
1309 GtkClipboard *clipboard;
1310 Atom atom;
1311
1312 atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
1313
1314 XGrabServer(GDK_DISPLAY());
1315
1316 if (XGetSelectionOwner(GDK_DISPLAY(), atom) != None)
1317 goto out;
1318
1319 clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
1320
1321 if (gtk_clipboard_set_with_data(clipboard, targets,
1322 G_N_ELEMENTS (targets),
1323 clipboard_get_func,
1324 clipboard_clear_func, NULL))
1325 retval = TRUE;
1326
1327out:
1328 XUngrabServer (GDK_DISPLAY ());
1329 gdk_flush ();
1330
1331 return retval;
1332}
1333#undef CLIPBOARD_NAME
1334
8110399f
HJYP
1335static gboolean start_all_panels( )
1336{
cf701cb7 1337 gboolean is_global;
4b93d81e 1338 for( is_global = 0; ! all_panels && is_global < 2; ++is_global )
cf701cb7
HJYP
1339 {
1340 char* panel_dir = get_config_file( cprofile, "panels", is_global );
1341 GDir* dir = g_dir_open( panel_dir, 0, NULL );
e3b89f43 1342 const gchar* name;
cf701cb7
HJYP
1343
1344 if( ! dir )
1345 {
1346 g_free( panel_dir );
1347 continue;
1348 }
1349
1350 while( name = g_dir_read_name( dir ) )
1351 {
1352 char* panel_config = g_build_filename( panel_dir, name, NULL );
1353 Panel* panel = panel_new( panel_config, name );
1354 if( panel )
1355 all_panels = g_slist_prepend( all_panels, panel );
1356 g_free( panel_config );
1357 }
1358 g_dir_close( dir );
1359 g_free( panel_dir );
1360 }
1361 return all_panels != NULL;
8110399f
HJYP
1362}
1363
cf701cb7
HJYP
1364void load_global_config();
1365void free_global_config();
1366
8110399f 1367int main(int argc, char *argv[], char *env[])
a52c2257
HJYP
1368{
1369 int i;
95095259 1370 char* session_name;
f277dbb7 1371
a52c2257 1372 setlocale(LC_CTYPE, "");
f277dbb7 1373
a52c2257
HJYP
1374 gtk_init(&argc, &argv);
1375
1376#ifdef ENABLE_NLS
1377 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
1378 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
1379 textdomain ( GETTEXT_PACKAGE );
1380#endif
1381
1382 XSetLocaleModifiers("");
1383 XSetErrorHandler((XErrorHandler) handle_error);
8110399f 1384
a52c2257 1385 resolve_atoms();
8110399f 1386
95095259
HJYP
1387 session_name = g_getenv("DESKTOP_SESSION");
1388 is_in_lxde = session_name && (0 == strcmp(session_name, "LXDE"));
1389
a52c2257
HJYP
1390 for (i = 1; i < argc; i++) {
1391 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
1392 usage();
1393 exit(0);
1394 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
1395 printf("lxpanel %s\n", version);
1396 exit(0);
1397 } else if (!strcmp(argv[i], "--log")) {
1398 i++;
1399 if (i == argc) {
1400 ERR( "lxpanel: missing log level\n");
1401 usage();
1402 exit(1);
1403 } else {
1404 log_level = atoi(argv[i]);
1405 }
1406 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
1407 config = 1;
1408 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
1409 i++;
1410 if (i == argc) {
1411 ERR( "lxpanel: missing profile name\n");
1412 usage();
1413 exit(1);
1414 } else {
1415 cprofile = g_strdup(argv[i]);
1416 }
1417 } else {
1418 printf("lxpanel: unknown option - %s\n", argv[i]);
1419 usage();
1420 exit(1);
1421 }
1422 }
f277dbb7 1423
8110399f 1424 /* Check for duplicated lxpanel instances */
e68b47dc
JH
1425 if (!check_main_lock() && !config) {
1426 printf("There is alreay an instance of LXPanel. Now to exit\n");
1427 exit(1);
1428 }
1429
f277dbb7
HJYP
1430 /* Add our own icons to the search path of icon theme */
1431 gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(),
1432 PACKAGE_DATA_DIR "/lxpanel/images" );
1433
cf701cb7 1434 fbev = fb_ev_new();
e2957bd2 1435 win_grp = gtk_window_group_new();
22242ed4 1436
f7cb330e
HJYP
1437restart:
1438 is_restarting = FALSE;
1439
cf701cb7
HJYP
1440 load_global_config();
1441
1d9dc649
HJYP
1442 /* NOTE: StructureNotifyMask is required by XRandR
1443 * See init_randr_support() in gdkscreen-x11.c of gtk+ for detail.
1444 */
1445 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), StructureNotifyMask|SubstructureNotifyMask|PropertyChangeMask);
cf701cb7 1446 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
8110399f 1447
cf701cb7
HJYP
1448 if( G_UNLIKELY( ! start_all_panels() ) )
1449 g_warning( "Config files are not found.\n" );
8110399f
HJYP
1450/*
1451 * FIXME: configure??
6a6ad54e
HJYP
1452 if (config)
1453 configure();
8110399f 1454*/
6a6ad54e 1455 gtk_main();
8110399f 1456
cf701cb7
HJYP
1457 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), NoEventMask);
1458 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1459
8110399f
HJYP
1460 /* destroy all panels */
1461 g_slist_foreach( all_panels, (GFunc) panel_destroy, NULL );
2a26c0d8
HJYP
1462 g_slist_free( all_panels );
1463 all_panels = NULL;
6a6ad54e 1464 g_free( cfgfile );
5541b8d2 1465
cf701cb7
HJYP
1466 free_global_config();
1467
f7cb330e
HJYP
1468 if( is_restarting )
1469 goto restart;
1470
e2957bd2 1471 g_object_unref(win_grp);
22242ed4
HJYP
1472 g_object_unref(fbev);
1473
5541b8d2 1474 return 0;
a52c2257 1475}