2
* Copyright (c) 2006 LxDE Developers, see the file AUTHORS for details.
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.
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.
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.
22
#include <gdk-pixbuf/gdk-pixbuf.h>
24
#include <glib/gi18n.h>
26
#include <menu-cache.h>
28
#include <sys/types.h>
37
#include "menu-policy.h"
41
#define DEFAULT_MENU_ICON PACKAGE_DATA_DIR "/lxpanel/images/my-computer.png"
43
* SuxPanel version 0.1
44
* Copyright (c) 2003 Leandro Pereira <leandro@linuxmag.com.br>
48
* menu style code was taken from suxpanel
52
GtkWidget *menu, *box, *img, *label;
53
char *fname, *caption;
55
int iconsize, paneliconsize;
57
gboolean has_system_menu;
60
char *config_start, *config_end;
62
MenuCache* menu_cache;
63
guint visibility_flags;
64
gpointer reload_notify;
67
static guint idle_loader = 0;
69
GQuark SYS_MENU_ITEM_ID = 0;
71
/* a single-linked list storing all panels */
72
extern GSList* all_panels;
76
menu_destructor(Plugin *p)
78
menup *m = (menup *)p->priv;
80
if( G_UNLIKELY( idle_loader ) )
82
g_source_remove( idle_loader );
86
if( m->has_system_menu )
87
p->panel->system_menus = g_slist_remove( p->panel->system_menus, p );
89
g_signal_handler_disconnect(G_OBJECT(m->img), m->handler_id);
90
gtk_widget_destroy(m->menu);
94
menu_cache_remove_reload_notify(m->menu_cache, m->reload_notify);
95
menu_cache_unref( m->menu_cache );
105
spawn_app(GtkWidget *widget, gpointer data)
107
GError *error = NULL;
111
if (! g_spawn_command_line_async(data, &error) ) {
112
ERR("can't spawn %s\nError is %s\n", (char *)data, error->message);
113
g_error_free (error);
121
run_command(GtkWidget *widget, void (*cmd)(void))
129
menu_pos(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, GtkWidget *widget)
133
#if GTK_CHECK_VERSION(2,18,0)
134
GtkAllocation allocation;
135
gtk_widget_set_allocation(widget, &allocation);
138
p = g_object_get_data(G_OBJECT(widget), "plugin");
139
#if GTK_CHECK_VERSION(2,14,0)
140
gdk_window_get_origin(gtk_widget_get_window(widget), &ox, &oy);
142
gdk_window_get_origin(widget->window, &ox, &oy);
144
#if GTK_CHECK_VERSION(2,20,0)
145
GtkRequisition requisition;
146
gtk_widget_get_requisition(GTK_WIDGET(menu), &requisition);
147
w = requisition.width;
148
h = requisition.height;
151
w = GTK_WIDGET(menu)->requisition.width;
152
h = GTK_WIDGET(menu)->requisition.height;
154
if (p->panel->orientation == ORIENT_HORIZ) {
156
if (*x + w > gdk_screen_width())
157
#if GTK_CHECK_VERSION(2,18,0)
158
*x = ox + allocation.width - w;
160
*x = ox + widget->allocation.width - w;
164
#if GTK_CHECK_VERSION(2,18,0)
165
*y = oy + allocation.height;
167
*y = oy + widget->allocation.height;
170
#if GTK_CHECK_VERSION(2,18,0)
171
*x = ox + allocation.width;
173
*x = ox + widget->allocation.width;
175
if (*x > gdk_screen_width())
178
if (*y + h > gdk_screen_height())
179
#if GTK_CHECK_VERSION(2,18,0)
180
*y = oy + allocation.height - h;
182
*y = oy + widget->allocation.height - h;
185
DBG("widget: x,y=%d,%d w,h=%d,%d\n", ox, oy,
186
#if GTK_CHECK_VERSION(2,18,0)
187
allocation.width, allocation.height );
189
widget->allocation.width, widget->allocation.height );
191
DBG("w-h %d %d\n", w, h);
196
static void on_menu_item( GtkMenuItem* mi, MenuCacheItem* item )
198
lxpanel_launch_app( menu_cache_app_get_exec(MENU_CACHE_APP(item)),
199
NULL, menu_cache_app_get_use_terminal(MENU_CACHE_APP(item)));
202
/* load icon when mapping the menu item to speed up */
203
static void on_menu_item_map(GtkWidget* mi, MenuCacheItem* item)
205
GtkImage* img = GTK_IMAGE(gtk_image_menu_item_get_image(GTK_IMAGE_MENU_ITEM(mi)));
208
if( gtk_image_get_storage_type(img) == GTK_IMAGE_EMPTY )
212
/* FIXME: this is inefficient */
213
gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &w, &h);
214
item = g_object_get_qdata(G_OBJECT(mi), SYS_MENU_ITEM_ID);
215
icon = lxpanel_load_icon(menu_cache_item_get_icon(item), w, h, TRUE);
218
gtk_image_set_from_pixbuf(img, icon);
219
g_object_unref(icon);
225
static void on_menu_item_style_set(GtkWidget* mi, GtkStyle* prev, MenuCacheItem* item)
228
on_menu_item_map(mi, item);
231
static void on_add_menu_item_to_desktop(GtkMenuItem* item, MenuCacheApp* app)
235
const char* desktop = g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP);
236
int dir_len = strlen(desktop);
237
int basename_len = strlen(menu_cache_item_get_id(MENU_CACHE_ITEM(app)));
240
dest = g_malloc( dir_len + basename_len + 6 + 1 + 1 );
241
memcpy(dest, desktop, dir_len);
243
memcpy(dest + dir_len + 1, menu_cache_item_get_id(MENU_CACHE_ITEM(app)), basename_len + 1);
245
/* if the destination file already exists, make a unique name. */
246
if( g_file_test( dest, G_FILE_TEST_EXISTS ) )
248
memcpy( dest + dir_len + 1 + basename_len - 8 /* .desktop */, "XXXXXX.desktop", 15 );
249
dest_fd = g_mkstemp(dest);
255
dest_fd = creat(dest, 0600);
262
src = menu_cache_item_get_file_path(MENU_CACHE_ITEM(app));
263
if( g_file_get_contents(src, &data, &len, NULL) )
265
write( dest_fd, data, len );
274
/* TODO: add menu item to panel */
276
static void on_add_menu_item_to_panel(GtkMenuItem* item, MenuCacheApp* app)
278
/* Find a penel containing launchbar applet.
279
* The launchbar with most buttons will be choosen if
280
* there are several launchbar applets loaded.
286
for(l = all_panels; !lb && l; l = l->next)
288
Panel* panel = (Panel*)l->data;
290
for(pl=panel->plugins; pl; pl = pl->next)
292
Plugin* plugin = (Plugin*)pl;
293
if( strcmp(plugin->class->type, "launchbar") == 0 )
295
/* FIXME: should we let the users choose which launcherbar to add the btn? */
298
int n = launchbar_get_n_btns(plugin);
309
if( ! lb ) /* launchbar is not currently in use */
311
/* FIXME: add a launchbar plugin to the panel which has a menu, too. */
321
static void on_menu_item_properties(GtkMenuItem* item, MenuCacheApp* app)
323
/* FIXME: if the source desktop is in AppDir other then default
324
* applications dirs, where should we store the user-specific file?
326
char* ifile = menu_cache_item_get_file_path(MENU_CACHE_ITEM(app));
327
char* ofile = g_build_filename(g_get_user_data_dir(), "applications",
328
menu_cache_item_get_file_basename(MENU_CACHE_ITEM(app)), NULL);
338
g_spawn_async( NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL );
343
/* This following function restore_grabs is taken from menu.c of
346
/*most of this function stolen from the real gtk_menu_popup*/
347
static void restore_grabs(GtkWidget *w, gpointer data)
349
GtkWidget *menu_item = data;
350
GtkMenu *menu = GTK_MENU(gtk_widget_get_parent(menu_item));
351
GtkWidget *xgrab_shell;
354
/* Find the last viewable ancestor, and make an X grab on it
356
parent = GTK_WIDGET (menu);
360
gboolean viewable = TRUE;
361
GtkWidget *tmp = parent;
365
if (!GTK_WIDGET_MAPPED (tmp))
370
tmp = gtk_widget_get_parent(tmp);
374
xgrab_shell = parent;
376
parent = gtk_widget_get_parent(parent);
379
/*only grab if this HAD a grab before*/
380
#if GTK_CHECK_VERSION(2,18,0)
381
if (xgrab_shell && (gtk_widget_has_focus(xgrab_shell)))
383
if (xgrab_shell && (GTK_MENU_SHELL (xgrab_shell)->have_xgrab))
386
#if GTK_CHECK_VERSION(2,14,0)
387
if (gdk_pointer_grab (gtk_widget_get_window(xgrab_shell), TRUE,
389
if (gdk_pointer_grab (xgrab_shell->window, TRUE,
391
GDK_BUTTON_PRESS_MASK |
392
GDK_BUTTON_RELEASE_MASK |
393
GDK_ENTER_NOTIFY_MASK |
394
GDK_LEAVE_NOTIFY_MASK,
397
#if GTK_CHECK_VERSION(2,14,0)
398
if (gdk_keyboard_grab (gtk_widget_get_window(xgrab_shell), TRUE,
400
if (gdk_keyboard_grab (xgrab_shell->window, TRUE,
402
GDK_CURRENT_TIME) == 0)
403
#if GTK_CHECK_VERSION(2,18,0)
404
gtk_widget_grab_focus (xgrab_shell);
406
GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
409
gdk_pointer_ungrab (GDK_CURRENT_TIME);
412
gtk_grab_add (GTK_WIDGET (menu));
415
static gboolean on_menu_button_press(GtkWidget* mi, GdkEventButton* evt, MenuCacheItem* data)
417
if( evt->button == 3 ) /* right */
421
GtkMenu* p = GTK_MENU(gtk_menu_new());
423
item = gtk_menu_item_new_with_label(_("Add to desktop"));
424
g_signal_connect(item, "activate", G_CALLBACK(on_add_menu_item_to_desktop), data);
425
gtk_menu_shell_append(GTK_MENU_SHELL(p), item);
427
tmp = g_find_program_in_path("lxshortcut");
430
item = gtk_separator_menu_item_new();
431
gtk_menu_shell_append(GTK_MENU_SHELL(p), item);
433
item = gtk_menu_item_new_with_label(_("Properties"));
434
g_signal_connect(item, "activate", G_CALLBACK(on_menu_item_properties), data);
435
gtk_menu_shell_append(GTK_MENU_SHELL(p), item);
438
g_signal_connect(p, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL);
439
g_signal_connect(p, "deactivate", G_CALLBACK(restore_grabs), mi);
441
gtk_widget_show_all(GTK_WIDGET(p));
442
gtk_menu_popup(p, NULL, NULL, NULL, NULL, 0, evt->time);
448
static GtkWidget* create_item( MenuCacheItem* item )
451
if( menu_cache_item_get_type(item) == MENU_CACHE_TYPE_SEP )
452
mi = gtk_separator_menu_item_new();
456
mi = gtk_image_menu_item_new_with_label( menu_cache_item_get_name(item) );
457
img = gtk_image_new();
458
gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(mi), img );
459
if( menu_cache_item_get_type(item) == MENU_CACHE_TYPE_APP )
461
gtk_widget_set_tooltip_text( mi, menu_cache_item_get_comment(item) );
462
g_signal_connect( mi, "activate", G_CALLBACK(on_menu_item), item );
464
g_signal_connect(mi, "map", G_CALLBACK(on_menu_item_map), item);
465
g_signal_connect(mi, "style-set", G_CALLBACK(on_menu_item_style_set), item);
466
g_signal_connect(mi, "button-press-event", G_CALLBACK(on_menu_button_press), item);
468
gtk_widget_show( mi );
469
g_object_set_qdata_full( G_OBJECT(mi), SYS_MENU_ITEM_ID, menu_cache_item_ref(item), (GDestroyNotify) menu_cache_item_unref );
473
static int load_menu(menup* m, MenuCacheDir* dir, GtkWidget* menu, int pos )
476
/* number of visible entries */
478
for( l = menu_cache_dir_get_children(dir); l; l = l->next )
480
MenuCacheItem* item = MENU_CACHE_ITEM(l->data);
482
gboolean is_visible = ((menu_cache_item_get_type(item) != MENU_CACHE_TYPE_APP) ||
483
(panel_menu_item_evaluate_visibility(item, m->visibility_flags)));
487
GtkWidget * mi = create_item(item);
490
gtk_menu_shell_insert( (GtkMenuShell*)menu, mi, pos );
493
/* process subentries */
494
if (menu_cache_item_get_type(item) == MENU_CACHE_TYPE_DIR)
496
GtkWidget* sub = gtk_menu_new();
497
/* always pass -1 for position */
498
gint s_count = load_menu( m, MENU_CACHE_DIR(item), sub, -1 );
500
gtk_menu_item_set_submenu( GTK_MENU_ITEM(mi), sub );
503
/* don't keep empty submenus */
504
gtk_widget_destroy( sub );
505
gtk_widget_destroy( mi );
517
static gboolean sys_menu_item_has_data( GtkMenuItem* item )
519
return (g_object_get_qdata( G_OBJECT(item), SYS_MENU_ITEM_ID ) != NULL);
522
static void unload_old_icons(GtkMenu* menu, GtkIconTheme* theme)
524
GList *children, *child;
526
GtkWidget* sub_menu=NULL;
528
children = gtk_container_get_children( GTK_CONTAINER(menu) );
529
for( child = children; child; child = child->next )
531
item = GTK_MENU_ITEM( child->data );
532
if( sys_menu_item_has_data( item ) )
535
item = GTK_MENU_ITEM( child->data );
536
if( GTK_IS_IMAGE_MENU_ITEM(item) )
538
img = GTK_IMAGE(gtk_image_menu_item_get_image(GTK_IMAGE_MENU_ITEM(item)));
539
gtk_image_clear(img);
540
if( GTK_WIDGET_MAPPED(img) )
541
on_menu_item_map(GTK_WIDGET(item),
542
(MenuCacheItem*)g_object_get_qdata(G_OBJECT(item), SYS_MENU_ITEM_ID) );
545
else if( ( sub_menu = gtk_menu_item_get_submenu( item ) ) )
547
unload_old_icons( GTK_MENU(sub_menu), theme );
550
g_list_free( children );
553
static void remove_change_handler(gpointer id, GObject* menu)
555
g_signal_handler_disconnect(gtk_icon_theme_get_default(), GPOINTER_TO_INT(id));
559
* Insert application menus into specified menu
560
* menu: The parent menu to which the items should be inserted
561
* pisition: Position to insert items.
562
Passing -1 in this parameter means append all items
565
static void sys_menu_insert_items( menup* m, GtkMenu* menu, int position )
568
guint change_handler;
570
if( G_UNLIKELY( SYS_MENU_ITEM_ID == 0 ) )
571
SYS_MENU_ITEM_ID = g_quark_from_static_string( "SysMenuItem" );
573
dir = menu_cache_get_root_dir( m->menu_cache );
575
load_menu( m, dir, GTK_WIDGET(menu), position );
576
else /* menu content is empty */
578
/* add a place holder */
579
GtkWidget* mi = gtk_menu_item_new();
580
g_object_set_qdata( G_OBJECT(mi), SYS_MENU_ITEM_ID, GINT_TO_POINTER(1) );
581
gtk_menu_shell_insert(menu, mi, position);
584
change_handler = g_signal_connect_swapped( gtk_icon_theme_get_default(), "changed", G_CALLBACK(unload_old_icons), menu );
585
g_object_weak_ref( G_OBJECT(menu), remove_change_handler, GINT_TO_POINTER(change_handler) );
590
reload_system_menu( menup* m, GtkMenu* menu )
592
GList *children, *child;
596
gboolean found = FALSE;
598
children = gtk_container_get_children( GTK_CONTAINER(menu) );
599
for( child = children, idx = 0; child; child = child->next, ++idx )
601
item = GTK_MENU_ITEM( child->data );
602
if( sys_menu_item_has_data( item ) )
606
item = GTK_MENU_ITEM( child->data );
608
gtk_widget_destroy( GTK_WIDGET(item) );
609
}while( child && sys_menu_item_has_data( child->data ) );
610
sys_menu_insert_items( m, menu, idx );
615
else if( ( sub_menu = gtk_menu_item_get_submenu( item ) ) )
617
reload_system_menu( m, GTK_MENU(sub_menu) );
620
g_list_free( children );
623
static void show_menu( GtkWidget* widget, Plugin* p, int btn, guint32 time )
625
menup* m = (menup*)p->priv;
626
gtk_menu_popup(GTK_MENU(m->menu),
628
(GtkMenuPositionFunc)menu_pos, widget,
633
my_button_pressed(GtkWidget *widget, GdkEventButton *event, Plugin* plugin)
636
#if GTK_CHECK_VERSION(2,18,0)
637
GtkAllocation allocation;
638
gtk_widget_get_allocation(widget, &allocation);
641
/* Standard right-click handling. */
642
if (plugin_button_press_event(widget, event, plugin))
645
if ((event->type == GDK_BUTTON_PRESS)
646
#if GTK_CHECK_VERSION(2,18,0)
647
&& (event->x >=0 && event->x < allocation.width)
648
&& (event->y >=0 && event->y < allocation.height)) {
650
&& (event->x >=0 && event->x < widget->allocation.width)
651
&& (event->y >=0 && event->y < widget->allocation.height)) {
653
show_menu( widget, plugin, event->button, event->time );
658
gboolean show_system_menu( gpointer system_menu )
660
Plugin* p = (Plugin*)system_menu;
661
menup* m = (menup*)p->priv;
662
show_menu( m->img, p, 0, GDK_CURRENT_TIME );
667
make_button(Plugin *p, gchar *fname, gchar *name, GdkColor* tint, GtkWidget *menu)
673
m = (menup *)p->priv;
678
/* load the name from *.directory file if needed */
679
if( g_str_has_suffix( name, ".directory" ) )
681
GKeyFile* kf = g_key_file_new();
682
char* dir_file = g_build_filename( "desktop-directories", name, NULL );
683
if( g_key_file_load_from_data_dirs( kf, dir_file, NULL, 0, NULL ) )
685
title = g_key_file_get_locale_string( kf, "Desktop Entry", "Name", NULL, NULL );
688
g_key_file_free( kf );
693
m->img = fb_button_new_from_file_with_label(fname, -1, p->panel->icon_size, gcolor2rgb24(tint), TRUE, p->panel, title);
700
m->img = fb_button_new_from_file(fname, -1, p->panel->icon_size, gcolor2rgb24(tint), TRUE);
703
gtk_widget_show(m->img);
704
gtk_box_pack_start(GTK_BOX(m->box), m->img, FALSE, FALSE, 0);
706
m->handler_id = g_signal_connect (G_OBJECT (m->img), "button-press-event",
707
G_CALLBACK (my_button_pressed), p);
708
g_object_set_data(G_OBJECT(m->img), "plugin", p);
715
read_item(Plugin *p, char** fp)
718
gchar *name, *fname, *action;
720
menup *m = (menup *)p->priv;
721
Command *cmd_entry = NULL;
725
name = fname = action = NULL;
729
while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
730
if (s.type == LINE_VAR) {
731
if (!g_ascii_strcasecmp(s.t[0], "image"))
732
fname = expand_tilda(s.t[1]);
733
else if (!g_ascii_strcasecmp(s.t[0], "name"))
734
name = g_strdup(s.t[1]);
735
else if (!g_ascii_strcasecmp(s.t[0], "action"))
736
action = g_strdup(s.t[1]);
737
else if (!g_ascii_strcasecmp(s.t[0], "command")) {
740
for (tmp = commands; tmp->name; tmp++) {
741
if (!g_ascii_strcasecmp(s.t[1], tmp->name)) {
747
ERR( "menu/item: unknown var %s\n", s.t[0]);
754
if( cmd_entry ) /* built-in commands */
756
item = gtk_image_menu_item_new_with_label( _(cmd_entry->disp_name) );
757
g_signal_connect(G_OBJECT(item), "activate", (GCallback)run_command, cmd_entry->cmd);
761
item = gtk_image_menu_item_new_with_label(name ? name : "");
763
g_signal_connect(G_OBJECT(item), "activate", (GCallback)spawn_app, action);
766
gtk_container_set_border_width(GTK_CONTAINER(item), 0);
771
img = _gtk_image_new_from_file_scaled(fname, m->iconsize, m->iconsize, TRUE);
772
gtk_widget_show(img);
773
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
786
read_separator(Plugin *p, char **fp)
794
while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
795
ERR("menu: error - separator can not have paramteres\n");
799
RET(gtk_separator_menu_item_new());
802
static void on_reload_menu( MenuCache* cache, menup* m )
804
/* g_debug("reload system menu!!"); */
805
reload_system_menu( m, GTK_MENU(m->menu) );
809
read_system_menu(GtkMenu* menu, Plugin *p, char** fp)
812
menup *m = (menup *)p->priv;
814
if (m->menu_cache == NULL)
817
m->menu_cache = panel_menu_cache_new(&flags);
818
if (m->menu_cache == NULL)
820
ERR("error loading applications menu");
823
m->visibility_flags = flags;
824
m->reload_notify = menu_cache_add_reload_notify(m->menu_cache, (GFunc) on_reload_menu, m);
830
while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
831
ERR("menu: error - system can not have paramteres\n");
836
sys_menu_insert_items( m, menu, -1 );
837
m->has_system_menu = TRUE;
839
p->panel->system_menus = g_slist_append( p->panel->system_menus, p );
843
read_include(Plugin *p, char **fp)
849
menup *m = (menup *)p->priv;
850
/* FIXME: this is disabled */
856
while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
857
if (s.type == LINE_VAR) {
858
if (!g_ascii_strcasecmp(s.t[0], "name"))
859
name = expand_tilda(s.t[1]);
861
ERR( "menu/include: unknown var %s\n", s.t[0]);
867
if ((fp = fopen(name, "r"))) {
868
LOG(LOG_INFO, "Including %s\n", name);
869
m->files = g_slist_prepend(m->files, fp);
872
ERR("Can't include %s\n", name);
874
if (name) g_free(name);
880
read_submenu(Plugin *p, char** fp, gboolean as_item)
883
GtkWidget *mi, *menu;
885
menup *m = (menup *)p->priv;
886
GdkColor color={0, 0, 36 * 0xffff / 0xff, 96 * 0xffff / 0xff};
891
menu = gtk_menu_new ();
892
gtk_container_set_border_width(GTK_CONTAINER(menu), 0);
896
while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
897
if (s.type == LINE_BLOCK_START) {
899
if (!g_ascii_strcasecmp(s.t[0], "item")) {
900
mi = read_item(p, fp);
901
} else if (!g_ascii_strcasecmp(s.t[0], "separator")) {
902
mi = read_separator(p, fp);
903
} else if (!g_ascii_strcasecmp(s.t[0], "system")) {
904
read_system_menu(GTK_MENU(menu), p, fp); /* add system menu items */
906
} else if (!g_ascii_strcasecmp(s.t[0], "menu")) {
907
mi = read_submenu(p, fp, TRUE);
908
} else if (!g_ascii_strcasecmp(s.t[0], "include")) {
912
ERR("menu: unknown block %s\n", s.t[0]);
916
ERR("menu: can't create menu item\n");
920
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
921
} else if (s.type == LINE_VAR) {
922
m->config_start = *fp;
923
if (!g_ascii_strcasecmp(s.t[0], "image"))
924
fname = expand_tilda(s.t[1]);
925
else if (!g_ascii_strcasecmp(s.t[0], "name"))
926
name = g_strdup(s.t[1]);
927
/* FIXME: tintcolor will not be saved. */
928
else if (!g_ascii_strcasecmp(s.t[0], "tintcolor"))
929
gdk_color_parse( s.t[1], &color);
931
ERR("menu: unknown var %s\n", s.t[0]);
933
} else if (s.type == LINE_NONE) {
937
p->fp = m->files->data;
939
m->files = g_slist_delete_link(m->files, m->files);
942
ERR("menu: illegal in this context %s\n", s.str);
947
mi = gtk_image_menu_item_new_with_label(name);
950
img = _gtk_image_new_from_file_scaled(fname, m->iconsize, m->iconsize, TRUE);
951
gtk_widget_show(img);
952
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
954
gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), menu);
956
m->fname = fname ? g_strdup(fname) : g_strdup( DEFAULT_MENU_ICON );
957
m->caption = name ? g_strdup(name) : NULL;
958
mi = make_button(p, fname, name, &color, menu);
967
// FIXME: we need to recursivly destroy all child menus and their items
968
gtk_widget_destroy(menu);
975
menu_constructor(Plugin *p, char **fp)
979
static char default_config[] =
990
"image=gnome-logout\n"
993
"image=" DEFAULT_MENU_ICON "\n"
995
char *config_default = default_config;
998
m = g_new0(menup, 1);
999
g_return_val_if_fail(m != NULL, 0);
1005
gtk_icon_size_lookup( GTK_ICON_SIZE_MENU, &iw, &ih );
1006
m->iconsize = MAX(iw, ih);
1008
m->box = gtk_hbox_new(FALSE, 0);
1009
gtk_container_set_border_width(GTK_CONTAINER(m->box), 0);
1012
fp = &config_default;
1014
m->config_start = start = *fp;
1015
if (!read_submenu(p, fp, FALSE)) {
1016
ERR("menu: plugin init failed\n");
1019
m->config_end = *fp - 1;
1020
while( *m->config_end != '}' && m->config_end > m->config_start ) {
1023
if( *m->config_end == '}' )
1026
m->config_data = g_strndup( start, (m->config_end - start) );
1034
static void save_config( Plugin* p, FILE* fp )
1036
menup* menu = (menup*)p->priv;
1038
lxpanel_put_str( fp, "name", menu->caption );
1039
lxpanel_put_str( fp, "image", menu->fname );
1040
if( menu->config_data ) {
1041
char** lines = g_strsplit( menu->config_data, "\n", 0 );
1043
for( line = lines; *line; ++line ) {
1044
g_strstrip( *line );
1049
/* skip image and caption since we already save these two items */
1050
if( g_str_has_prefix(*line, "image") || g_str_has_prefix(*line, "caption") )
1053
g_strchomp(*line); /* remove trailing spaces */
1054
if( g_str_has_suffix( *line, "{" ) )
1056
else if( g_str_has_suffix( *line, "}" ) )
1058
lxpanel_put_line( fp, *line );
1061
g_strfreev( lines );
1065
static void apply_config(Plugin* p)
1067
menup* m = (menup*)p->priv;
1069
fb_button_set_from_file( m->img, m->fname, -1, p->panel->icon_size, TRUE );
1072
static void menu_config( Plugin *p, GtkWindow* parent )
1075
menup* menu = (menup*)p->priv;
1076
dlg = create_generic_config_dlg( _(p->class->name),
1078
(GSourceFunc) apply_config, (gpointer) p,
1079
_("Icon"), &menu->fname, CONF_TYPE_FILE_ENTRY,
1080
/* _("Caption"), &menu->caption, CONF_TYPE_STR, */
1082
gtk_window_present( GTK_WINDOW(dlg) );
1085
/* Callback when panel configuration changes. */
1086
static void menu_panel_configuration_changed(Plugin * p)
1091
PluginClass menu_plugin_class = {
1093
PLUGINCLASS_VERSIONING,
1098
description : N_("Application Menu"),
1100
constructor : menu_constructor,
1101
destructor : menu_destructor,
1102
config : menu_config,
1104
panel_configuration_changed : menu_panel_configuration_changed