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