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