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