4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2003, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* appmenu.c - handles application-specific menus read from XMLwrapper.xml */
32 #include <libxml/parser.h>
37 #include "gui_support.h"
51 /* Static prototypes */
52 static void apprun_menu(GtkWidget
*item
, gpointer data
);
53 static GtkWidget
*create_menu_item(xmlNode
*node
);
54 static void show_app_help(GtkWidget
*item
, gpointer data
);
55 static void build_mount_menu(const char *mnt_dir
, DirItem
*app_item
);
56 static void build_app_menu(const char *app_dir
, DirItem
*app_item
);
58 /* There can only be one menu open at a time... we store: */
59 static GtkWidget
*current_menu
= NULL
; /* The GtkMenu */
60 static guchar
*current_app_path
= NULL
; /* The path of the application */
61 static GList
*current_items
= NULL
; /* The GtkMenuItems we added directly
62 * to it --- not submenu items.
64 static Option o_mount_free
; /* Command to run to show free space */
65 static Option o_mount_format
; /* Command to run to format device */
67 /****************************************************************
68 * EXTERNAL INTERFACE *
69 ****************************************************************/
71 void appmenu_init(void)
73 option_add_string(&o_mount_free
, "mount_free", "");
74 option_add_string(&o_mount_format
, "mount_format", "");
77 /* Removes all appmenu menu items */
78 void appmenu_remove(void)
85 for (next
= current_items
; next
; next
= next
->next
)
86 gtk_widget_destroy((GtkWidget
*) next
->data
);
88 null_g_free(¤t_app_path
);
91 g_list_free(current_items
);
95 /* Add AppMenu entries to 'menu', if appropriate.
96 * This function modifies the menu stored in "menu".
97 * 'app_dir' is the pathname of the application directory, and 'item'
98 * is the corresponding DirItem.
99 * Call appmenu_remove() to undo the effect.
101 void appmenu_add(const gchar
*app_dir
, DirItem
*app_item
, GtkWidget
*menu
)
106 g_return_if_fail(menu
!= NULL
);
108 /* Should have called appmenu_remove() already... */
109 g_return_if_fail(current_menu
== NULL
);
110 g_return_if_fail(current_items
== NULL
);
112 if (app_item
->flags
& ITEM_FLAG_MOUNT_POINT
)
113 build_mount_menu(app_dir
, app_item
);
115 build_app_menu(app_dir
, app_item
);
119 sep
= gtk_menu_item_new();
120 current_items
= g_list_prepend(current_items
, sep
);
121 gtk_widget_show(sep
);
124 for (next
= current_items
; next
; next
= next
->next
)
125 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu
),
126 GTK_WIDGET(next
->data
));
129 current_app_path
= g_strdup(app_dir
);
133 /****************************************************************
134 * INTERNAL FUNCTIONS *
135 ****************************************************************/
137 /* Create a new menu and return it */
138 static GtkWidget
*appmenu_add_submenu(xmlNode
*subm_node
)
143 /* Create the new submenu */
144 sub_menu
= gtk_menu_new();
146 /* Add the menu entries */
147 for (node
= subm_node
->xmlChildrenNode
; node
; node
= node
->next
)
151 item
= create_menu_item(node
);
153 gtk_menu_shell_append(GTK_MENU_SHELL(sub_menu
), item
);
159 /* Create and return a menu item */
160 static GtkWidget
*create_menu_item(xmlNode
*node
)
164 guchar
*label
, *option
= NULL
;
167 if (node
->type
!= XML_ELEMENT_NODE
)
170 if (strcmp(node
->name
, "Item") == 0)
173 option
= xmlGetProp(node
, "option");
175 else if (strcmp(node
->name
, "AppMenu") == 0)
180 /* Create the item */
181 label_node
= get_subnode(node
, NULL
, "Label");
184 label
= xmlNodeListGetString(label_node
->doc
,
185 label_node
->xmlChildrenNode
, 1);
189 label
= xmlGetProp(node
, "label");
191 label
= g_strdup(_("<missing label>"));
193 item
= gtk_menu_item_new_with_label(label
);
195 gtk_widget_set_accel_path(item
, NULL
, NULL
); /* XXX */
201 /* Add submenu items */
203 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item
),
204 appmenu_add_submenu(node
));
208 /* Set up callback */
212 g_object_set_data_full(G_OBJECT(item
), "option",
218 g_signal_connect(item
, "activate", G_CALLBACK(apprun_menu
),
222 gtk_widget_show(item
);
227 /* Function called to execute an AppMenu item */
228 static void apprun_menu(GtkWidget
*item
, gpointer data
)
233 g_return_if_fail(current_app_path
!= NULL
);
235 option
= g_object_get_data(G_OBJECT(item
), "option");
237 argv
[0] = g_strconcat(current_app_path
, "/AppRun", NULL
);
238 argv
[1] = option
; /* (may be NULL) */
241 rox_spawn(NULL
, (const gchar
**) argv
);
246 static void show_app_help(GtkWidget
*item
, gpointer data
)
248 g_return_if_fail(current_app_path
!= NULL
);
250 show_help_files(current_app_path
);
253 static void mnt_eject(GtkWidget
*item
, gpointer data
)
257 g_return_if_fail(current_app_path
!= NULL
);
258 dirs
= g_list_prepend(NULL
, current_app_path
);
263 static void mnt_free(GtkWidget
*item
, gpointer data
)
265 char *argv
[4]={"sh", "-c", NULL
, NULL
};
269 g_return_if_fail(current_app_path
!= NULL
);
271 if(o_mount_free
.value
[0]) {
272 fmt
=o_mount_free
.value
;
274 /* We do our own searching so we can handle AppDir's */
275 const gchar
*path
=g_getenv("PATH");
276 gchar
**dirs
=g_strsplit(path
, ":", 100);
278 gchar
**words
=g_strsplit(fmt
, " ", 2);
280 for(i
=0; dirs
[i
]; i
++) {
281 gchar
*target
=g_build_filename(dirs
[i
],
284 if(file_exists(target
)) {
286 di
=diritem_new(words
[0]);
287 diritem_restat(target
, di
, NULL
);
289 if(di
->flags
& ITEM_FLAG_APPDIR
) {
290 tmp
=g_strconcat(target
,
310 fmt
="xterm -hold -e df -k %s";
313 argv
[2]=g_strdup_printf(fmt
, current_app_path
);
314 rox_spawn(current_app_path
, (const gchar
**) argv
);
321 static void mnt_format(GtkWidget
*item
, gpointer data
)
323 char *argv
[4]={"sh", "-c", NULL
, NULL
};
325 g_return_if_fail(current_app_path
!= NULL
);
327 if(!o_mount_format
.value
[0]) {
328 delayed_error(_("No program has been given to format a device"));
332 argv
[2]=g_strdup_printf(o_mount_format
.value
, current_app_path
);
333 rox_spawn(current_app_path
, (const gchar
**) argv
);
338 static void build_mount_menu(const char *mnt_dir
, DirItem
*app_item
)
341 gboolean mounted
=(app_item
->flags
& ITEM_FLAG_MOUNTED
);
343 item
= gtk_menu_item_new_with_label(_("Eject"));
344 gtk_widget_show(item
);
345 current_items
= g_list_prepend(current_items
, item
);
346 g_signal_connect(item
, "activate", G_CALLBACK(mnt_eject
), NULL
);
348 item
= gtk_menu_item_new_with_label(_("Format"));
349 gtk_widget_show(item
);
350 current_items
= g_list_prepend(current_items
, item
);
351 g_signal_connect(item
, "activate", G_CALLBACK(mnt_format
), NULL
);
353 gtk_widget_set_sensitive(item
, FALSE
);
355 item
= gtk_menu_item_new_with_label(_("Free Space"));
356 gtk_widget_show(item
);
357 current_items
= g_list_prepend(current_items
, item
);
358 g_signal_connect(item
, "activate", G_CALLBACK(mnt_free
), NULL
);
360 gtk_widget_set_sensitive(item
, FALSE
);
364 /* Adds to current_items */
365 static void build_app_menu(const char *app_dir
, DirItem
*app_item
)
367 XMLwrapper
*ai
= NULL
;
371 ai
= appinfo_get(app_dir
, app_item
);
374 node
= xml_get_section(ai
, NULL
, "AppMenu");
376 node
= node
->xmlChildrenNode
;
380 if (app_item
->flags
& ITEM_FLAG_APPDIR
)
383 return; /* Not an application AND no AppInfo */
386 /* Add the menu entries */
387 for (; node
; node
= node
->next
)
389 item
= create_menu_item(node
);
392 current_items
= g_list_prepend(current_items
, item
);
395 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_HELP
, NULL
);
396 gtk_widget_show(item
);
397 current_items
= g_list_prepend(current_items
, item
);
398 g_signal_connect(item
, "activate", G_CALLBACK(show_app_help
), NULL
);
399 gtk_label_set_text(GTK_LABEL(GTK_BIN(item
)->child
), _("Help"));
406 * Persuade [X]Emacs to use the right indenting