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