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