"Fossies" - the Fresh Open Source Software archive

Member "evms-2.5.5/ui/ncurses/menu.c" of archive evms-2.5.5.tar.gz:


/*
 *
 *   (C) Copyright IBM Corp. 2002, 2003
 *
 *   This program is free software;  you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program;  if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <glib.h>
#include <ncurses.h>
#include <panel.h>
#include <frontend.h>

#include "common.h"
#include "window.h"
#include "dlist.h"
#include "menu.h"
#include "dialog.h"
#include "clist.h"
#include "task.h"
#include "create.h"
#include "delete.h"
#include "add.h"
#include "modify.h"
#include "remove.h"
#include "replace.h"
#include "object.h"
#include "plugin.h"
#include "container.h"
#include "options.h"
#include "fsutils.h"
#include "views.h"
#include "create.h"
#include "convert.h"
#include "delete.h"
#include "resize.h"
#include "mount.h"
#include "volume.h"
#include "settings.h"
#include "save.h"
#include "callbacks.h"
#include "logging.h"
#include "activation.h"
#include "backup.h"

static WINDOW *menubar;
static WINDOW *statusbar;

static struct menu_item menubar_item[MENUBAR_ITEM_COUNT];

/**
 *	Since we don't destroy the action menus once created, we keep
 *	track of their popup_menu structures created here so we can
 *	show or hide them as necessary.
 */
static struct popup_menu *actions_menu = NULL;
static struct popup_menu *settings_menu = NULL;
static struct popup_menu *create_menu = NULL;
static struct popup_menu *delete_menu = NULL;
static struct popup_menu *activation_menu = NULL;
static struct popup_menu *expand_menu = NULL;
static struct popup_menu *shrink_menu = NULL;
static struct popup_menu *add_menu = NULL;
static struct popup_menu *remove_menu = NULL;
static struct popup_menu *modify_menu = NULL;
static struct popup_menu *view_menu = NULL;
static struct popup_menu *convert_menu = NULL;
static struct popup_menu *other_menu = NULL;
static struct popup_menu *fsys_menu = NULL;


/**
 *	get_accel_color - return the attribute/color for the accelerator character in a menu
 *	@win: the window that contains the menu
 *
 *	This routine returns the proper color attribute for a menu depending on if the
 *	current color pair is for a selected menu item or the normal menu background.
 */
chtype get_accel_color(WINDOW *win)
{
	short pair;
	attr_t attrs;
	chtype color;

	wattr_get(win, &attrs, &pair, NULL);

	if (pair == MENUSEL_COLOR) {
		color = COLOR_PAIR(SELECTED_ACCEL_COLOR);
	} else {
		color = COLOR_PAIR(ACCEL_COLOR);
	}
	return color;
}

/**
 *	print_menu_item - prints a menu item with accelerator support
 *	@win: the window that is to contain the menu item
 *	@starty: the row to print the menu item at
 *	@startx: the column to print the menu item at
 *	@item: the address of the menu_item struct
 *	
 *	This routine uses the information in the given menu_item struct
 *	in order to display a menu item. The accelerator character
 *	(if any) is displayed brighter than the rest.
 */
void print_menu_item(WINDOW *win, int starty, int startx, struct menu_item *item)
{
	if (MI_IS_VISIBLE(item->flags)) {
		mvwaddstr(win, starty, startx, item->label);

		if (MI_IS_SENSITIVE(item->flags) && item->accel != '\0') {
			char *accel;

			accel = strchr(item->label, item->accel);
			if (accel != NULL) {
				int x;
				chtype ch;

				ch = item->accel | get_accel_color(win);
				x = (accel - item->label) + startx;
				mvwaddch(win, starty, x, ch);
			}
		}
		wmove(win, starty, startx);
	}
}

/**
 *	get_accelerator_char - retrieves the accelerator character from menu label
 *	@label: the label containing the accelerator character
 *
 *	This routine scans the string for the '_' character and then uses the
 *	following character as the accelerator character. '\0' is returned if the
 *	label does not contain an accelerator character.
 */
char get_accelerator_char(char *label)
{
	char ch = '\0';
	char *accel;

	accel = strchr(label, '_');
	if (accel != NULL) {
		ch = accel[1];
	}
	return ch;
}

/**
 *	remove_accel_identifier - makes a duplicate string of the label with the '_'
 *	@label: the label containing the accelerator character and identifier
 *
 *	This routine returns a duplicate of the label string minus the first '_'
 *	character which is used to identify the accelerator character.
 */
char *remove_accel_identifier(char *label)
{
	char *dup, *leader;

	dup = g_strdup(label);
	leader = strchr(dup, '_');
	if (leader != NULL) {
		while (*leader != '\0') {
			*leader = *(leader + 1);
			leader++;
		}
	}
	return dup;
}

/**
 *	create_menu_item - allocates/creates and initializes a menu item
 *	@label: the menu item label
 *	@tip: the optional description to display on status line
 *	@accel: the accelerator character
 *	@is_submenu: whether this is a submenu or a real menu item (leaf)
 *	@activate_cb: function to invoke when item is selected
 *	@user_data: whatever the caller wants to pass to the activate_cb
 *
 *	This routine dynamically allocates a new menu item and initializes it.
 */
struct menu_item *create_menu_item(char *label, char *tip, int accel, int is_submenu,
					menuitem_activate_cb activate_cb, void *user_data)
{
	struct menu_item *item;

	item = g_new0(struct menu_item, 1);

	item->label = g_strdup(label);
	item->label_len = strlen(label);
	item->tip = g_strdup(tip);
	item->accel = accel;
	item->flags = is_submenu ? MI_FLAG_SUBMENU : 0;
	item->flags |= (MI_FLAG_VISIBLE | MI_FLAG_SENSITIVE);
	item->startx = -1;
	item->activate_cb = activate_cb;
	item->delete_cb = NULL;
	item->user_data = user_data;

	return item;
}

/**
 *	delete_menu_item - deletes all resources associated with a menu item
 *	@item: the pointer to the menu_item structure
 *	@menu: the popup menu containing the item
 *
 *	This routine invokes an user supplied delete callback and then proceeds
 *	to free the memory allocated for the menu item fields and the menu item
 *	structure itself.
 */
void delete_menu_item(struct menu_item *item, struct popup_menu *menu)
{
	if (item->delete_cb != NULL) {
		item->delete_cb(item);
	}
	if (item == menu->focus_item->data) {
		if (g_list_next(menu->focus_item) != NULL) {
			menu->focus_item = g_list_next(menu->focus_item);
		} else {
			menu->focus_item = g_list_previous(menu->focus_item);
		}
	}
	g_free(item->label);
	g_free(item->tip);
	g_free(item);
}

/**
 *	set_menu_item_activate_cb - sets the address of the activate callback for a menu item
 *	@item: the menu item
 *	@activate_cb: the function to invoke when a menu item is activated
 *
 *	This routine is used to set the menu item activation callback. This allows a
 *	activation callback to be changed as needed (such as to replace the default).
 */
inline void set_menu_item_activate_cb(struct menu_item *item, menuitem_activate_cb activate_cb)
{
	item->activate_cb = activate_cb;
}

/**
 *	set_menu_item_delete_cb - sets the address of the delete callback for a menu item
 *	@item: the menu item
 *	@delete_cb: the function to invoke when a menu item is deleted
 *
 *	This routine is used to set the menu item deletion callback. Since a deletion
 *	callback is hardly used, it is not provided as a parameter on append_menu_item().
 *	This routine allows the exceptions access to set it when needed.
 */
inline void set_menu_item_delete_cb(struct menu_item *item, menuitem_delete_cb delete_cb)
{
	item->delete_cb = delete_cb;
}

/**
 *	set_menu_item_sensitivity - make a menu item sensitive or not
 *	@item: the menu item
 *	@sensitive: non-zero if the menu item should be sensitive, zero if not
 *
 *	This routine simply enables or disables the flag that identifies
 *	a menu item a sensitive to selection or activation.
 */
inline void set_menu_item_sensitivity(struct menu_item *item, int sensitive)
{
	if (sensitive)
		item->flags |= MI_FLAG_SENSITIVE;
	else
		item->flags &= ~MI_FLAG_SENSITIVE;
}

/**
 *	set_menu_item_visibility - make a menu item visible or hidden
 *	@item: the menu item
 *	@visible: non-zero if the menu item should be visible, zero if hidden
 *
 *	This routine simply enables or disables the flag that identifies
 *	a menu item as visible (capable of being drawn) or not. The caller
 *	must make the appropriate call to redraw the menu and either make
 *	the menu item show up or disappear.
 */
inline void set_menu_item_visibility(struct menu_item *item, int visible)
{
	if (visible)
		item->flags |= MI_FLAG_VISIBLE;
	else
		item->flags &= ~MI_FLAG_VISIBLE;
}

/**
 *	is_menu_item_sensitive - determine if menu item supplied is sensitive to events
 *	@item: the menu item to check
 *
 *	This routine returns TRUE if the menu item is currently not sensitive to
 *	events.
 */
inline gboolean is_menu_item_sensitive(struct menu_item *item)
{
	return (item->flags & MI_FLAG_SENSITIVE ? TRUE : FALSE);
}

/**
 *	is_menu_item_visible - determine if menu item supplied is being drawn when needed
 *	@item: the menu item to check
 *
 *	This routine return TRUE if the menu is currently invisible to draw requests.
 */
inline gboolean is_menu_item_visible(struct menu_item *item)
{
	return (item->flags & MI_FLAG_VISIBLE ? TRUE : FALSE);
}

/**
 *	append_menu_item - creates and appends a menu item to a menu
 *	@label: the menu item label
 *	@tip: the optional description to display on status line
 *	@accel: the accelerator character
 *	@is_submenu: whether this is a submenu or a real menu item (leaf)
 *	@activate_cb: function to invoke when item is selected
 *	@user_data: whatever the caller wants to pass to the activate_cb
 *
 *	This routine creates a new menu item and appends it to the linked
 *	list of popup menu items.
 */
struct menu_item *append_menu_item(struct popup_menu *menu, char *label, char *tip, int accel,
				int is_submenu, menuitem_activate_cb activate_cb, void *user_data)
{
	struct menu_item *item;

	item = create_menu_item(label, tip, accel, is_submenu, activate_cb, user_data);
	menu->items = g_list_append(menu->items, item);

	if (menu->focus_item == NULL) {
		menu->focus_item = menu->items;
	}
	return item;
}

/**
 *	display_not_implemented_popup_window - warns when function not implemented
 *	@void
 *
 *	This is a temporary function that indicates a function is not available
 *	for a menu item.
 */
void display_not_implemented_popup_window(void)
{
	show_message_dialog(NULL, _("Operation not yet implemented!"));
}

/**
 *	translate_key - filters keyboard input for a menu
 *	@items: the list containing the menu items
 *	@key: the input key
 *	@focus_item: the address of the focus item tracker
 *
 *	This routine processes keyboard input for a menu and
 *	translates any accelerator keys to the ENTER_KEY and
 *	adjusts the focus_item if appropriate.
 */
int translate_key(GList *items, int key, GList **focus_item)
{
	GList *element;
	struct menu_item *item;

	element = items;
	while (element != NULL) {
		item = element->data;
		if (MI_IS_SENSITIVE(item->flags) &&
				(tolower(item->accel) == tolower(key))) {
			key = KEY_ENTER;
			*focus_item = element;
			break;
		}
		element = g_list_next(element);
	}
	return key;
}

/**
 *	show_about_box - display some information on the application
 *	@item: the item that was activated to invoke this callback
 *
 *	This routine creates a popup window with some application information.
 */
int show_about_box(struct menu_item *item)
{
	int key = 0;
	WINDOW *win;
	PANEL *panel;
	gchar *version;
	struct horizontal_menu *menu;

	panel = create_centered_popup_window(MIN(getmaxy(stdscr) - 2, 14),
					getmaxx(stdscr) - 6,
					WHITE_BKGD);
	win = panel_window(panel);

	version = g_strdup_printf(_("Version %s"), VERSION);

	print_centered(win, 1, _("EVMSN"));
	print_centered(win, 2, _("Enterprise Volume Management System Text Mode Interface"));
	print_centered(win, 4, version);
	print_centered(win, 7, _("(C) Copyright IBM Corp. 2002, 2003"));
	print_centered(win, 9, _("Online documentation can be found at http://evms.sf.net"));

	menu = create_horizontal_menu(win, getmaxx(win) - 4, getmaxy(win) - 2, 1, 1);
	pack_menu_item_at_end(menu, _("[OK]"), get_accelerator_char(_("[_OK]")),
					(menuitem_activate_cb)ok_button_activated,
					NULL);	
	draw_horizontal_menu(menu);
	show_popup_window(panel);

	while (key != KEY_ESCAPE && key != KEY_ENTER) {
		key = panel_getch(panel);
		process_horizontal_menu_events(menu, &key);
	}

	delete_horizontal_menu(menu);	
	delete_popup_window(panel);
	g_free(version);

	return 0;
}

/**
 *	init_menubar_menu_items - initialize the main menubar menu items
 *	@void
 *
 *	This routine initializes the main menubar menu item array.
 */
inline void init_menubar_menu_items(void)
{
	menubar_item[ACTIONS_MENUITEM].label = _("Actions");
	menubar_item[ACTIONS_MENUITEM].label_len = strlen(menubar_item[ACTIONS_MENUITEM].label);
	menubar_item[ACTIONS_MENUITEM].accel = get_accelerator_char(_("_Actions"));
	menubar_item[ACTIONS_MENUITEM].flags = MI_FLAG_SENSITIVE | MI_FLAG_VISIBLE;
	menubar_item[ACTIONS_MENUITEM].activate_cb = (menuitem_activate_cb)actions_menuitem_activated;

	menubar_item[SETTINGS_MENUITEM].label = _("Settings");
	menubar_item[SETTINGS_MENUITEM].label_len = strlen(menubar_item[SETTINGS_MENUITEM].label);
	menubar_item[SETTINGS_MENUITEM].accel = get_accelerator_char(_("_Settings"));
	menubar_item[SETTINGS_MENUITEM].flags = MI_FLAG_SENSITIVE | MI_FLAG_VISIBLE;
	menubar_item[SETTINGS_MENUITEM].activate_cb = (menuitem_activate_cb)settings_menuitem_activated;

	menubar_item[HELP_MENUITEM].label = _("Help");
	menubar_item[HELP_MENUITEM].label_len = strlen(menubar_item[HELP_MENUITEM].label);
	menubar_item[HELP_MENUITEM].accel = get_accelerator_char(_("_Help"));
	menubar_item[HELP_MENUITEM].flags = MI_FLAG_SENSITIVE | MI_FLAG_VISIBLE;
	menubar_item[HELP_MENUITEM].activate_cb = (menuitem_activate_cb)show_about_box;
}

/**
 *	process_menubar_events - process menubar keys and activates menu items
 *	@key: the input character/key
 *
 *	This routine translates a character/key into an event such as activating
 *	a menu item on the menubar.
 */
int process_menubar_events(int key)
{
	int i, rc = 0;

	for (i = 0; i < MENUBAR_ITEM_COUNT; i++) {
		if (tolower(key) == tolower(menubar_item[i].accel)) {
			if (menubar_item[i].activate_cb != NULL) {
				rc = menubar_item[i].activate_cb(&(menubar_item[i]));
			} else {
				display_not_implemented_popup_window();
			}
			break;
		}
	}
	return rc;
}

/**
 *	draw_menubar - draws the main menubar
 *	@void
 *
 *	This routine creates the main window menubar that is used to
 *	access the general dropdown action menus.
 */
void draw_menubar(void)
{
	init_menubar_menu_items();
	menubar = subwin(stdscr, 1, getmaxx(stdscr), 0, 0);
	wbkgd(menubar, WHITE_BKGD);
	print_menu_item(menubar, 0, 1, &(menubar_item[ACTIONS_MENUITEM]));
	print_menu_item(menubar, 0, menubar_item[ACTIONS_MENUITEM].label_len + 4,
			&(menubar_item[SETTINGS_MENUITEM]));
	print_menu_item(menubar, 0, getmaxx(stdscr) - (menubar_item[HELP_MENUITEM].label_len + 1),
			&(menubar_item[HELP_MENUITEM]));
	wrefresh(menubar);
}

/**
 *	draw_statusbar - draws the status bar at the bottom of the screen
 *	@void
 *
 *	This routine draws the status bar line at the bottom of the main window.
 */
void draw_statusbar(void)
{
	statusbar = subwin(stdscr, 1, getmaxx(stdscr), getmaxy(stdscr) - 1, 0);
	wbkgd(statusbar, WHITE_BKGD);
	wrefresh(statusbar);
}

/**
 *	print_statusbar_text - displays given text in statusbar
 *	@text: the text string to display
 *
 *	This routine displays the given text string in the statusbar
 *	window. The previous text in the statusbar window is cleared
 *	before the next text is written.
 */
void print_statusbar_text(char *text)
{
	werase(statusbar);
	mvwaddstr(statusbar, 0, 1, text);
	wrefresh(statusbar);
}

/**
 *	get_statusbar_win - returns the statusbar window id
 *	@void
 *
 *	This routine is a simple getter function for the statusbar window id.
 */
WINDOW *get_statusbar_win(void)
{
	return statusbar;
}

/**
 *	create_popup_menu - allocates the popup menu struct
 *	@void
 *
 *	This routine creates/allocates a popup_menu struct
 *	and initializes the data struct.
 */
struct popup_menu *create_popup_menu(void)
{
	return g_new0(struct popup_menu, 1);
}

/**
 *	delete_popup_menu - frees all resources for a popup menu
 *	@menu: the popup menu
 *
 *	This routine deletes window/panel components of a popup menu
 *	before deallocating the memory for the popup menu structure.
 *	It also deletes all the menu items in the popup menu as well.
 *	It invokes the handler for the delete event registered with
 *	the menu if one exists before actually deleting the popup menu.
 */
void delete_popup_menu(struct popup_menu *menu)
{
	if (menu->delete_cb != NULL) {
		menu->delete_cb(menu);
	}
	delete_all_elements(menu->items, (GFunc)delete_menu_item, menu);
	delete_panel_window(menu->panel);
	g_free(menu);
}

/**
 *	hide_popup_menu - hides a popup menu window
 *	@menu: the popup menu
 *
 *	This routine hides the panel window for the popup menu
 *	and then invokes the handler registered for the menu
 *	hide event if any.
 */
void hide_popup_menu(struct popup_menu *menu)
{
	hide_panel_window(menu->panel);
	if (menu->hide_cb != NULL) {
		menu->hide_cb(menu);
	}
}

/**
 *	print_blank_menu_item - print a line with spaces in a popup menu
 *	@win: the popup menu window
 *	@line: the line in the popup menu to clear
 *
 *	This routine clears a line in a popup window by drawing spaces
 *	into it.
 */
void print_blank_menu_item(WINDOW *win, int line)
{
	char *fill;

	fill = g_strnfill(getmaxx(win) - 2, ' ');
	mvwaddstr(win, line, 1, fill);
	g_free(fill);
}

/**
 *	draw_menu_item - displays a single menu item in a popup menu
 *	@element: the address of the linked list item we are in
 *	@index: an index to identify us in a loop
 *	@menu: the address of the popup_menu structure we are in
 *
 *	This routine is meant to be invoked through a for_n_elements()
 *	call. For each iteration we use the index as the row to update.
 */
void draw_menu_item(GList *element, int index, struct popup_menu *menu)
{
	if (element != NULL && element->data != NULL) {
		index++;
		print_blank_menu_item(menu->win, index);
		print_menu_item(menu->win, index, 1, element->data);
	}
}

/**
 *	draw_menu_items - draws the menu items in a popup menu
 *	@menu: the popup menu to draw
 *
 *	This routine draws/updates the menu items in the menu window.
 */
inline void draw_menu_items(struct popup_menu *menu)
{
	for_n_elements(menu->items, getmaxy(menu->win),
			(iterate_func)draw_menu_item, menu);
}

/**
 *	get_max_label_width - returns the length of the longest menu item label
 *	@element: the first element of the linked list of menu items
 *
 *	This routine scans all the menu item labels in the menu item list in
 *	order to determine the length of the longest label for all menu items.
 */
int get_max_label_width(GList *element)
{
	int len = 0;
	struct menu_item *item;

	while (element != NULL) {
		item = element->data;
		if (item->label_len > len) {
			len = item->label_len;
		}
		element = g_list_next(element);
	}
	return len;
}

/**
 *	create_menu_panel - creates a panel window with menu items
 *	@menu: the address of the menu we need the panel for
 *	@starty: the starting line to place the window
 *	@startx: the starting column to place the window
 *
 *	This routine creates a panel window sized to the width of the
 *	longest label in the linked list of menu items. The panel of the
 *	created menu is then set in the popup_menu struct.
 */
inline void create_menu_panel(struct popup_menu *menu, int starty, int startx)
{
	int width, height;

	width = get_max_label_width(menu->items) + 2;
	height = g_list_length(menu->items) + 2;
	menu->panel = create_panel_window(height, width, starty, startx, TRUE, WHITE_BKGD);
	menu->win = panel_window(menu->panel);
	draw_menu_items(menu);
}

/**
 *	cascade_menu - place a submenu slightly overlapping parent menu
 *	@submenu: the menu id of the submenu
 *	@parent: the menu id of the parent menu
 *	@starty: the row/line to place the submenu relative to parent starty
 *
 *	This routine determines the width and starting row and column of a
 *	parent window and then places the submenu relative to the parent
 *	window and slightly overlapping it.
 */
inline void cascade_menu(struct popup_menu *submenu, struct popup_menu *parent, int starty)
{
	move_panel(submenu->panel, getbegy(parent->win) + starty, getmaxx(parent->win) - 1);
	submenu->parent = parent;
}

/**
 *	highlight_current_menuitem - sets visual focus on current menu item
 *	@menu: the popup menu
 *	@width: the width of the menuitem area
 *
 *	This routine draws a bar across the current menu item so the user
 *	can see which menu item has focus.
 */
void highlight_current_menuitem(struct popup_menu *menu, int width)
{
	int focus_index;
	struct menu_item *item;

	wbkgdset(menu->win, WHITE_BKGD);
	draw_menu_items(menu);
	item = menu->focus_item->data;
	wbkgdset(menu->win, MENUSEL_FGND);
	focus_index = g_list_position(menu->items, menu->focus_item);
	draw_menu_item(menu->focus_item, focus_index, menu);
	wbkgdset(menu->win, WHITE_BKGD);
	if (item->tip != NULL) {
		print_statusbar_text(item->tip);
	}
	wrefresh(menu->win);
}

/**
 *	hide_parent_menus - hides the menu and all its parent menus
 *	@menu: the initial menu to hide
 *
 *	This routine hides the given menu and if its a submenu, hides
 *	any parent menu as well.
 */
inline void hide_parent_menus(struct popup_menu *menu)
{
	struct popup_menu *curr_menu;

	curr_menu = menu;
	while (curr_menu != NULL) {
		hide_panel_window(curr_menu->panel);
		curr_menu = curr_menu->parent;
	}
}

/**
 *	process_menu_events - handles keyboard movement and selection
 *	@menu: the menu to process
 *
 *	This routine handles navigation through a menu of menu items.
 *	It provides for invoking an activation callback for a menu item
 *	upon selection of the menu item (through ENTER_KEY or the accelerator
 *	character). This function returns either id ESCAPE_KEY is detected
 *	or after a selection's activation callback has returned.
 */
int process_menu_events(struct popup_menu *menu)
{
	int rc = 0, width, key, process_key;
	struct menu_item *curr_item = NULL;

	process_key = TRUE;
	width = getmaxx(menu->win) - 2;
	menu->focus_item = g_list_first(menu->items);

	while (process_key == TRUE) {
		highlight_current_menuitem(menu, width);
		key = panel_getch(menu->panel);
		key = translate_key(menu->items, key, &(menu->focus_item));

		switch (key) {
		case KEY_DOWN:
			if (g_list_next(menu->focus_item) != NULL) {
				menu->focus_item = g_list_next(menu->focus_item);
			} else {
				menu->focus_item = g_list_first(menu->items);
			}
			break;
		case KEY_UP:
			if (g_list_previous(menu->focus_item) != NULL) {
				menu->focus_item = g_list_previous(menu->focus_item);
			} else {
				menu->focus_item = g_list_last(menu->items);
			}
			break;
		case KEY_HOME:
			menu->focus_item = g_list_first(menu->items);
			break;
		case KEY_END:
			menu->focus_item = g_list_last(menu->items);
			break;
		case KEY_ENTER:
			curr_item = menu->focus_item->data;
			if (MI_IS_SENSITIVE(curr_item->flags)) {
				if (MI_IS_SUBMENU(curr_item->flags)) {
					highlight_current_menuitem(menu, width);
				} else {
					print_statusbar_text("");
					hide_parent_menus(menu);
				}
				if (curr_item->activate_cb != NULL) {
					rc = curr_item->activate_cb(curr_item);
					if (rc != ELOOP) {
						hide_popup_menu(menu);
						process_key = FALSE;
					}
				} else {
					display_not_implemented_popup_window();
					process_key = FALSE;
				}
			}
			break;
		case KEY_ESCAPE:
			print_statusbar_text("");
			hide_popup_menu(menu);
			process_key = FALSE;
			rc = ELOOP;
			break;
		}
	}
	return rc;
}

/**
 *	calculate_menu_item_offsets_from_start - calculate the offsets for items in a horiz menu from start
 *	@menu: the horizontal menu
 *
 *	This routine calculates the starting offsets for each menu item label in a
 *	horizontal menu. We expect that the first item in the list was just added and
 *	the we set it's offset to 0 and ensure that the next item over and on are at
 *	least menu->spacing from each other. Otherwise, we make the necessary adjustments.
 *
 *	At the moment, if ever an item is deleted, we don't shift offsets to close up the
 *	holes but I suppose it wouldn't be that the difficult to do. Currently, it is not
 *	a requirement and should also keep this routine a bit simpler.
 */
inline void calculate_menu_item_offsets_from_start(struct horizontal_menu *menu)
{
	GList *element;

	element = g_list_first(menu->items);

	if (element != NULL) {
		struct menu_item *curr_item, *prev_item;

		curr_item = prev_item = element->data;
		curr_item->startx = 0;

		element = g_list_next(element);

		while (element != NULL) {
			int offset;

			prev_item = curr_item;
			curr_item = element->data;
			offset = prev_item->startx + menu->spacing + prev_item->label_len;

			if (offset > curr_item->startx) {
				curr_item->startx = offset;
				element = g_list_next(element);
			} else {
				/*
				 * There is sufficient spacing between current
				 * and previous menu item so stop processing
				 */
				element = NULL;
			}
		}
	}
}

/**
 *	calculate_menu_item_offsets_from_end - calculate the offsets for items in a horiz menu from end
 *	@menu: the horizontal menu
 *
 *	This routine calculates the starting offsets for each menu item label in a
 *	horizontal menu. It places the last element in the list of menu items at an offset
 *	where it is to rightmost of the menu.
 *
 *	At the moment, if ever an item is deleted, we don't shift offsets to close up the
 *	holes but I suppose it wouldn't be that the difficult to do. Currently, it is not
 *	a requirement and should also keep this routine a bit simpler.
 */
inline void calculate_menu_item_offsets_from_end(struct horizontal_menu *menu)
{
	GList *element;

	element = g_list_last(menu->items);

	if (element != NULL) {
		struct menu_item *curr_item, *prev_item;

		curr_item = prev_item = element->data;
		curr_item->startx = getmaxx(menu->win) - curr_item->label_len;

		element = g_list_previous(element);

		while (element != NULL) {
			int offset;

			prev_item = curr_item;
			curr_item = element->data;
			offset = prev_item->startx - menu->spacing - curr_item->label_len;

			if (curr_item->startx > offset) {
				curr_item->startx = offset;
				element = g_list_previous(element);
			} else {
				/*
				 * There is sufficient spacing between current
				 * and previous menu item so stop processing
				 */
				element = NULL;
			}
		}
	}
}

/**
 *	pack_menu_item_at_end - places a menu item at the end (far right) of horizontal menu
 *	@menu: the horizontal menu to put the menu item in
 *	@label: the menu item label
 *	@accel: the accelerator character
 *	@activate_cb: the callback to invoke when the menu item is activated
 *	@user_data: whatever the caller wants accessible in the activate callback
 *
 *	This routine creates a menu item for a horizontal menu and places the menu item
 *	label at the far right of the menu. It adjusts the startx values for previous
 *	end packed entries to allow them to shift to left to make room for the new
 *	item.
 */
struct menu_item *pack_menu_item_at_end(struct horizontal_menu *menu, char *label, int accel,
					menuitem_activate_cb activate_cb, void *user_data)
{
	struct menu_item *item;

	item = create_menu_item(label, NULL, accel, FALSE, activate_cb, user_data);
	menu->items = g_list_append(menu->items, item);

	if (menu->focus_item == NULL) {
		menu->focus_item = menu->items;
	}
	calculate_menu_item_offsets_from_end(menu);
	return item;
}

/**
 *	pack_menu_item_at_end - places a menu item at the end (far right) of horizontal menu
 *	@menu: the horizontal menu to put the menu item in
 *	@label: the menu item label
 *	@accel: the accelerator character
 *	@activate_cb: the callback to invoke when the menu item is activated
 *	@user_data: whatever the caller wants accessible in the activate callback
 *
 *	This routine creates a menu item for a horizontal menu and places the menu item
 *	label at the far left of the menu. It adjusts the startx values for subsequent
 *	start packed entries to allow them to shift to right to make room for the new
 *	item.
 */
struct menu_item *pack_menu_item_at_start(struct horizontal_menu *menu, char *label, int accel,
					menuitem_activate_cb activate_cb, void *user_data)
{
	struct menu_item *item;

	item = create_menu_item(label, NULL, accel, FALSE, activate_cb, user_data);
	menu->items = g_list_prepend(menu->items, item);

	if (menu->focus_item == NULL) {
		menu->focus_item = menu->items;
	}
	calculate_menu_item_offsets_from_start(menu);
	return item;
}

/**
 *	set_horizontal_menu_focus - identify the menu item to focus in a horizontal menu
 *	@menu: the horizontal menu
 *	@item: the item to set focus on
 *
 *	This routine sets the focus menu item in a horizontal menu.
 */
inline void set_horizontal_menu_focus(struct horizontal_menu *menu, struct menu_item *item)
{
	GList *element;

	element = g_list_find(menu->items, item);
	if (element != NULL)
		menu->focus_item = element;
}

/**
 *	create_horizontal_menu - creates a menu with the menu items on the same line
 *	@parent_win: the parent window
 *	@width: the width of the menu
 *	@starty: the row to place the menu at within the parent window
 *	@startx: the column to place the menu at within the parent window
 *	@spacing: the number of spaces to keep between adjacent (packed) menu items
 *
 *	This routine creates a menu with the menu items on the same. The menu items
 *	are navigated with the left or right arrow key, cycled with the TAB key or
 *	activated with an ENTER or accelerator key. Items are either packed at the
 *	end or the start of the menu row.
 */
struct horizontal_menu *create_horizontal_menu(WINDOW *parent_win, int width, int starty,
						int startx, int spacing)
{
	struct horizontal_menu *menu;

	menu = g_new0(struct horizontal_menu, 1);

	menu->win = derwin(parent_win, 1, width, starty, startx);
	menu->spacing = spacing;

	return menu;
}

/**
 *	delete_horizontal_menu - frees all resources for a horizontal menu
 *	@menu: the horizontal menu
 *
 *	This routine deletes window components of a horizontal menu
 *	before deallocating the memory for the horizontal menu structure.
 *	It also deletes all the menu items in the horizontal menu as well.
 */
void delete_horizontal_menu(struct horizontal_menu *menu)
{
	delete_all_elements(menu->items, (GFunc)delete_menu_item, menu);
	delete_window(menu->win);
	g_free(menu);
}

/**
 *	draw_horizontal_menu_item - draws one menu item in a horizontal menu
 *	@item: the menu item to draw
 *	@win: the window for the horizontal menu
 *
 *	This routine draws one menu item in a horizontal menu.
 */
void draw_horizontal_menu_item(struct menu_item *item, WINDOW *win)
{
	print_menu_item(win, 0, item->startx, item);
}

/**
 *	move_focus_to_prev_item - move focus to previous visible/sensitive menu item
 *	@menu: the menu containing the menu items
 *
 *	This routine changes the focus (if possible) from the current focus item
 *	to a previous item in the list that is both visible and sensitive.
 */
inline void move_focus_to_prev_item(struct horizontal_menu *menu)
{
	GList *element;

	if (g_list_previous(menu->focus_item) != NULL) {
		element = g_list_previous(menu->focus_item);
	} else {
		element = g_list_last(menu->items);
	}

	while (element != menu->focus_item) {
		struct menu_item *item;

		item = element->data;
		if (MI_IS_SENSITIVE(item->flags) && MI_IS_VISIBLE(item->flags)) {
			menu->focus_item = element;
		} else if (g_list_previous(element) != NULL) {
			element = g_list_previous(element);
		} else {
			element = g_list_last(menu->items);
		}
	}
}

/**
 *	move_focus_to_next_item - move focus to next visible/sensitive menu item
 *	@menu: the menu containing the menu items
 *
 *	This routine changes the focus (if possible) from the current focus item
 *	to the next item in the list that is both visible and sensitive.
 */
inline void move_focus_to_next_item(struct horizontal_menu *menu)
{
	GList *element;

	if (g_list_next(menu->focus_item) != NULL) {
		element = g_list_next(menu->focus_item);
	} else {
		element = g_list_first(menu->items);
	}

	while (element != menu->focus_item) {
		struct menu_item *item;

		item = element->data;
		if (MI_IS_SENSITIVE(item->flags) && MI_IS_VISIBLE(item->flags)) {
			menu->focus_item = element;
		} else if (g_list_next(element) != NULL) {
			element = g_list_next(element);
		} else {
			element = g_list_first(menu->items);
		}
	}
}

/**
 *	verify_focus_item - ensure that we have a focus item that is visible and sensitive
 *	@menu: the horizontal menu
 *
 *	This routine checks to see if the current focus item is visible and sensitive. If
 *	not, we adjust the focus to some item before it that is.
 */
inline void verify_focus_item(struct horizontal_menu *menu)
{
	struct menu_item *item = menu->focus_item->data;

	if (!MI_IS_SENSITIVE(item->flags) || !MI_IS_VISIBLE(item->flags))
		move_focus_to_prev_item(menu);
}

/**
 *	draw_horizontal_menu - draws the menu items in a horizontal menu
 *	@menu: the horizontal menu to draw
 *
 *	This routine draws the menu items in a horizontal menu. The menu item
 *	with the current focus is highlighted as well.
 */
void draw_horizontal_menu(struct horizontal_menu *menu)
{
	struct menu_item *focus_item;

	g_return_if_fail(menu->items != NULL);
	g_return_if_fail(menu->focus_item != NULL);

	verify_focus_item(menu);
	focus_item = menu->focus_item->data;

	werase(menu->win);
	g_list_foreach(menu->items, (GFunc)draw_horizontal_menu_item, menu->win);
	wbkgdset(menu->win, MENUSEL_FGND);
	print_menu_item(menu->win, 0, focus_item->startx, focus_item);
	wbkgdset(menu->win, WHITE_BKGD);
	touchwin(menu->win);
	wrefresh(menu->win);
}

/**
 *	process_horizontal_menu_events - processes input for a horizontal menu
 *	@menu: the address of the horizontal menu data
 *	@key: the key to convert to a menu event to process
 *
 *	This routine processes the events for a horizontal menu. It receives
 *	a key and converts this to a corresponding event. It returns TRUE if
 *	an event/key was handled.
 */
int process_horizontal_menu_events(struct horizontal_menu *menu, int *key)
{
	int event_handled = TRUE;
	struct menu_item *curr_item = NULL;

	*key = translate_key(menu->items, *key, &(menu->focus_item));

	switch (*key) {
	case KEY_LEFT:
		move_focus_to_prev_item(menu);
		break;
	case KEY_RIGHT:
	case KEY_TAB:
		move_focus_to_next_item(menu);
		break;
	case KEY_ENTER:
		curr_item = menu->focus_item->data;
		draw_horizontal_menu(menu);

		if (curr_item->activate_cb != NULL) {
			curr_item->activate_cb(curr_item);
		} else {
			display_not_implemented_popup_window();
		}
		break;
	default:
		event_handled = FALSE;
		break;
	}
	if (event_handled == TRUE) {
		draw_horizontal_menu(menu);
	}

	return event_handled;
}

/**
 *	append_create_menu_items - appends the "Create" menu items
 *	@void
 *
 *	This routine appends the menu items for the "Create" menu.
 */
inline void append_create_menu_items(void)
{
	append_menu_item(create_menu, _("EVMS Volume..."),
				_("Create an EVMS native volume"),
				get_accelerator_char(_("_EVMS Volume...")), FALSE,
				(menuitem_activate_cb)actions_create_evms_vol_menuitem_activated, NULL);

	append_menu_item(create_menu, _("Compatibility Volume..."),
				_("Create a volume compatible with other volume management packages"),
				get_accelerator_char(_("Compatibility _Volume...")), FALSE,
				(menuitem_activate_cb)actions_create_vol_menuitem_activated, NULL);

	append_menu_item(create_menu, _("Feature Object..."),
				_("Create a native EVMS Feature Object"),
				get_accelerator_char(_("_Feature Object...")), FALSE,
				(menuitem_activate_cb)create_feature_menuitem_activated, NULL);

	append_menu_item(create_menu, _("Region..."), _("Create a Storage Region"),
				get_accelerator_char(_("_Region...")), FALSE,
				(menuitem_activate_cb)create_region_menuitem_activated, NULL);

	append_menu_item(create_menu, _("Container..."), _("Create a Storage Container"),
					get_accelerator_char(_("_Container...")), FALSE,
					(menuitem_activate_cb)create_container_menuitem_activated, NULL);

	append_menu_item(create_menu, _("Segment..."), _("Create a Disk Segment"),
					get_accelerator_char(_("_Segment...")), FALSE,
					(menuitem_activate_cb)create_segment_menuitem_activated, NULL);
}

/**
 *	draw_create_menu - draws the "Create" submenu
 *	@void
 *
 *	This routine displays the "Create" pulldown submenu. It gets
 *	placed next to the main "Actions" pulldown menu.
 */
void draw_create_menu(void)
{
	if (create_menu == NULL) {
		create_menu = create_popup_menu();
		append_create_menu_items();
		create_menu_panel(create_menu, 0, 0);
		cascade_menu(create_menu, actions_menu, CREATE_MENUITEM);
	}
	show_panel_window(create_menu->panel, TRUE);
}

/**
 *	create_menuitem_activated - function invoked when create menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "Create" menu item
 *	in the "Actions" menu is selected. It draws the "Create" pulldown submenu
 *	and processes menu events.
 */
int create_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_create_menu();
	rc = process_menu_events(create_menu);
	return rc;
}

/**
 *	append_delete_menu_items - appends the "Delete" menu items
 *	@void
 *
 *	This routine appends the menu items for the "Delete" menu.
 */
inline void append_delete_menu_items(void)
{
	append_menu_item(delete_menu, _("Volume..."), _("Delete a Logical Volume"),
				get_accelerator_char(_("_Volume...")), FALSE,
				(menuitem_activate_cb)actions_delete_menuitem_activated,
				GUINT_TO_POINTER(VOLUME));

	append_menu_item(delete_menu, _("Storage Object..."), _("Delete a Storage Object"),
				get_accelerator_char(_("_Storage Object...")), FALSE,
				(menuitem_activate_cb)actions_delete_menuitem_activated,
				GUINT_TO_POINTER(EVMS_OBJECT));

	append_menu_item(delete_menu, _("Container..."), _("Delete a Storage Container"),
				get_accelerator_char(_("_Container...")), FALSE,
				(menuitem_activate_cb)actions_delete_menuitem_activated,
				GUINT_TO_POINTER(CONTAINER));
}

/**
 *	draw_delete_menu - draws the "Delete" submenu
 *	@void
 *
 *	This routine displays the "Delete" pulldown submenu. It gets
 *	placed next to the main "Actions" pulldown menu.
 */
void draw_delete_menu(void)
{
	if (delete_menu == NULL) {
		delete_menu = create_popup_menu();
		append_delete_menu_items();
		create_menu_panel(delete_menu, 0, 0);
		cascade_menu(delete_menu, actions_menu, DELETE_MENUITEM);
	}
	show_panel_window(delete_menu->panel, TRUE);
}

/**
 *	delete_menuitem_activated - function invoked when "Delete" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "Delete" menu item
 *	in the "Actions" menu is selected. It draws the "Delete" pulldown submenu
 *	and processes menu events.
 */
int delete_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_delete_menu();
	rc = process_menu_events(delete_menu);
	return rc;
}

/**
 *	append_activation_menu_items - appends the "Activation" menu items
 *	@void
 *
 *	This routine appends the menu items for the "Activation" menu.
 */
inline void append_activation_menu_items(void)
{
	append_menu_item(activation_menu, _("Activate..."), _("Activate a Logical Volume or Storage Object"),
				get_accelerator_char(_("_Activate...")), FALSE,
				(menuitem_activate_cb)actions_activate_menuitem_activated,
				NULL);

	append_menu_item(activation_menu, _("Deactivate..."), _("Deactivate a Logical Volume or Storage Object"),
				get_accelerator_char(_("_Deactivate...")), FALSE,
				(menuitem_activate_cb)actions_deactivate_menuitem_activated,
				NULL);
}

/**
 *	draw_activation_menu - draws the "Activation" submenu
 *	@void
 *
 *	This routine displays the "Activation" pulldown submenu. It gets
 *	placed next to the main "Actions" pulldown menu.
 */
void draw_activation_menu(void)
{
	if (activation_menu == NULL) {
		activation_menu = create_popup_menu();
		append_activation_menu_items();
		create_menu_panel(activation_menu, 0, 0);
		cascade_menu(activation_menu, actions_menu, ACTIVATION_MENUITEM);
	}
	show_panel_window(activation_menu->panel, TRUE);
}

/**
 *	activation_menuitem_activated - function invoked when "Activation" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "Activation" menu item
 *	in the "Actions" menu is selected. It draws the "Activation" pulldown submenu
 *	and processes menu events.
 */
int activation_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_activation_menu();
	rc = process_menu_events(activation_menu);
	return rc;
}

/**
 *	append_expand_menu_items - appends the "Expand" menu items
 *	@void
 *
 *	This routine appends the menu items for the "Expand" menu.
 */
inline void append_expand_menu_items(void)
{
	append_menu_item(expand_menu, _("Volume..."), _("Increase the storage size of Logical Volume"),
				get_accelerator_char(_("_Volume...")), FALSE,
				(menuitem_activate_cb)actions_expand_volume_menuitem_activated, NULL);

	append_menu_item(expand_menu, _("Storage Object..."), _("Increase the storage size of Storage Object"),
				get_accelerator_char(_("_Storage Object...")), FALSE,
				(menuitem_activate_cb)actions_expand_object_menuitem_activated, NULL);

	append_menu_item(expand_menu, _("Container..."), _("Increase the size of a Storage Container"),
				get_accelerator_char(_("_Container...")), FALSE,
				(menuitem_activate_cb)actions_expand_container_menuitem_activated, NULL);
}

/**
 *	draw_expand_menu - draws the "Expand" submenu
 *	@void
 *
 *	This routine displays the "Expand" pulldown submenu. It gets
 *	placed next to the main "Actions" pulldown menu.
 */
void draw_expand_menu(void)
{
	if (expand_menu == NULL) {
		expand_menu = create_popup_menu();
		append_expand_menu_items();
		create_menu_panel(expand_menu, 0, 0);
		cascade_menu(expand_menu, actions_menu, EXPAND_MENUITEM);
	}
	show_panel_window(expand_menu->panel, TRUE);
}

/**
 *	expand_menuitem_activated - function invoked when "Expand" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "Expand" menu item
 *	in the "Actions" menu is selected. It draws the "Expand" pulldown submenu
 *	and processes menu events.
 */
int expand_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_expand_menu();
	rc = process_menu_events(expand_menu);
	return rc;
}

/**
 *	append_shrink_menu_items - appends the "Shrink" menu items
 *	@void
 *
 *	This routine appends the menu items for the "Shrink" menu.
 */
inline void append_shrink_menu_items(void)
{
	append_menu_item(shrink_menu, _("Volume..."),
				_("Reduce the storage size of a Logical Volume"),
				get_accelerator_char(_("_Volume...")), FALSE,
				(menuitem_activate_cb)actions_shrink_volume_menuitem_activated, NULL);

	append_menu_item(shrink_menu, _("Storage Object..."),
				_("Reduce the size of a Storage Object"),
				get_accelerator_char(_("_Storage Object...")), FALSE,
				(menuitem_activate_cb)actions_shrink_object_menuitem_activated, NULL);

	append_menu_item(shrink_menu, _("Container..."),
				_("Reduce the storage consumed by a Storage Container"),
				get_accelerator_char(_("_Container...")), FALSE,
				(menuitem_activate_cb)actions_shrink_container_menuitem_activated, NULL);
}

/**
 *	draw_shrink_menu - draws the "Shrink" submenu
 *	@void
 *
 *	This routine displays the "Shrink" pulldown submenu. It gets
 *	placed next to the main "Actions" pulldown menu.
 */
void draw_shrink_menu(void)
{
	if (shrink_menu == NULL) {
		shrink_menu = create_popup_menu();
		append_shrink_menu_items();
		create_menu_panel(shrink_menu, 0, 0);
		cascade_menu(shrink_menu, actions_menu, SHRINK_MENUITEM);
	}
	show_panel_window(shrink_menu->panel, TRUE);
}

/**
 *	shrink_menuitem_activated - function invoked when "Shrink" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "Shrink" menu item
 *	in the "Actions" menu is selected. It draws the "Shrink" pulldown submenu
 *	and processes menu events.
 */
int shrink_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_shrink_menu();
	rc = process_menu_events(shrink_menu);
	return rc;
}

/**
 *	append_add_menu_items - append the "Add" menu items
 *	@void
 *
 *	This routine appends the menu items for the "Add" menu.
 */
inline void append_add_menu_items(void)
{
	append_menu_item(add_menu, _("Feature to Volume..."),
				_("Add a EVMS Feature to an EVMS Volume"),
				get_accelerator_char(_("_Feature to Volume...")), FALSE,
				(menuitem_activate_cb)actions_add_feature_menuitem_activated, NULL);

	append_menu_item(add_menu, _("Segment Manager to Storage Object..."),
				_("Add a Segment Manager to a Storage Object"),
				get_accelerator_char(_("_Segment Manager to Storage Object...")),
				FALSE,
				(menuitem_activate_cb)add_segment_manager_menuitem_activated, NULL);
}

/**
 *	draw_add_menu - draws the "Add" submenu
 *	@void
 *
 *	This routine displays the "Add" pulldown submenu. It gets
 *	placed next to the main "Actions" pulldown menu.
 */
void draw_add_menu(void)
{
	if (add_menu == NULL) {
		add_menu = create_popup_menu();
		append_add_menu_items();
		create_menu_panel(add_menu, 0, 0);
		cascade_menu(add_menu, actions_menu, ADD_MENUITEM);
	}
	show_panel_window(add_menu->panel, TRUE);
}

/**
 *	add_menuitem_activated - function invoked when "Add" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "Add" menu item
 *	in the "Actions" menu is selected. It draws the "Add" pulldown submenu
 *	and processes menu events.
 */
int add_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_add_menu();
	rc = process_menu_events(add_menu);
	return rc;
}

/**
 *	append_remove_menu_items - appends the "Remove" menu items
 *	@void
 *
 *	This routine appends the menu items for the "Remove" menu.
 */
inline void append_remove_menu_items(void)
{
	append_menu_item(remove_menu, _("Storage Object from Container..."),
				_("Remove a Storage Object from Container"),
				get_accelerator_char(_("Storage _Object from Container...")),
				FALSE,
				(menuitem_activate_cb)actions_remove_consumed_object_menuitem_activated,
				NULL);

	append_menu_item(remove_menu, _("Segment Manager from Storage Object..."),
				_("Remove a Segment Manager from Storage Object"),
				get_accelerator_char(_("_Segment Manager from Storage Object...")),
				FALSE,
				(menuitem_activate_cb)context_remove_segment_manager_menuitem_activated,
				NULL);
}

/**
 *	draw_remove_menu - draws the "Remove" submenu
 *	@void
 *
 *	This routine displays the "Remove" pulldown submenu. It gets
 *	placed next to the main "Actions" pulldown menu.
 */
void draw_remove_menu(void)
{
	if (remove_menu == NULL) {
		remove_menu = create_popup_menu();
		append_remove_menu_items();
		create_menu_panel(remove_menu, 0, 0);
		cascade_menu(remove_menu, actions_menu, REMOVE_MENUITEM);
	}
	show_panel_window(remove_menu->panel, TRUE);
}

/**
 *	remove_menuitem_activated - function invoked when "Remove" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "Remove" menu item
 *	in the "Actions" menu is selected. It draws the "Remove" pulldown submenu
 *	and processes menu events.
 */
int remove_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_remove_menu();
	rc = process_menu_events(remove_menu);
	return rc;
}

/**
 *	append_modify_menu_items - appends the "Modify" menu items
 *	@void
 *
 *	This routine appends the menu items for the "Modify" menu.
 */
inline void append_modify_menu_items(void)
{
	append_menu_item(modify_menu, _("Volume..."), _("Modify Logical Volume properties"),
				get_accelerator_char(_("_Volume...")), FALSE,
				(menuitem_activate_cb)actions_modify_vol_menuitem_activated,
				NULL);

	append_menu_item(modify_menu, _("Storage Object..."), _("Modify Storage Object properties"),
				get_accelerator_char(_("_Storage Object...")), FALSE,
				(menuitem_activate_cb)actions_modify_object_menuitem_activated,
				NULL);

	append_menu_item(modify_menu, _("Container..."), _("Modify Storage Container properties"),
				get_accelerator_char(_("_Container...")), FALSE,
				(menuitem_activate_cb)actions_modify_container_menuitem_activated,
				NULL);
}

/**
 *	draw_modify_menu - draws the "Modify" submenu
 *	@void
 *
 *	This routine displays the "Modify" pulldown submenu. It gets
 *	placed next to the main "Actions" pulldown menu.
 */
void draw_modify_menu(void)
{
	if (modify_menu == NULL) {
		modify_menu = create_popup_menu();
		append_modify_menu_items();
		create_menu_panel(modify_menu, 0, 0);
		cascade_menu(modify_menu, actions_menu, MODIFY_MENUITEM);
	}
	show_panel_window(modify_menu->panel, TRUE);
}

/**
 *	modify_menuitem_activated - function invoked when "Modify" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "Modify" menu item
 *	in the "Actions" menu is selected. It draws the "Modify" pulldown submenu
 *	and processes menu events.
 */
int modify_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_modify_menu();
	rc = process_menu_events(modify_menu);
	return rc;
}

/**
 *	append_view_menu_items - appends the "View" menu items
 *	@void
 *
 *	This routine appends the menu items for the "View" menu.
 */
inline void append_view_menu_items(void)
{
	append_menu_item(view_menu, _("Messages..."), _("Display informational messages window"),
				get_accelerator_char(_("_Messages...")), FALSE,
				(menuitem_activate_cb)on_view_messages_menuitem_activated,
				NULL);
}

/**
 *	draw_view_menu - draws the "View" submenu
 *	@void
 *
 *	This routine displays the "View" pulldown submenu. It gets
 *	placed next to the main "Actions" pulldown menu.
 */
void draw_view_menu(void)
{
	if (view_menu == NULL) {
		view_menu = create_popup_menu();
		append_view_menu_items();
		create_menu_panel(view_menu, 0, 0);
		cascade_menu(view_menu, actions_menu, VIEW_MENUITEM);
	}
	show_panel_window(view_menu->panel, TRUE);
}

/**
 *	modify_menuitem_activated - function invoked when "View" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "View" menu item
 *	in the "Actions" menu is selected. It draws the "View" pulldown submenu
 *	and processes menu events.
 */
int view_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_view_menu();
	rc = process_menu_events(view_menu);
	return rc;
}

/**
 *	append_convert_menu_items - appends the "Convert" menu items
 *	@void
 *
 *	This routine appends the menu items for the "Convert" menu.
 */
inline void append_convert_menu_items(void)
{
	append_menu_item(convert_menu, _("Compatibility Volume to EVMS Volume..."),
				_("Convert a Compatibility Volume to a EVMS Volume"),
				get_accelerator_char(_("_Compatibility Volume to EVMS Volume...")),
				FALSE,
				(menuitem_activate_cb)actions_convert_vol_menuitem_activated,
				NULL);

	append_menu_item(convert_menu, _("EVMS Volume to Compatibility Volume..."),
				_("Convert a EVMS Volume to a Compatibility Volume"),
				get_accelerator_char(_("_EVMS Volume to Compatibility Volume...")),
				FALSE,
				(menuitem_activate_cb)actions_convert_evms_vol_menuitem_activated,
				NULL);
}

/**
 *	draw_convert_menu - draws the "Convert" submenu
 *	@void
 *
 *	This routine displays the "Convert" pulldown submenu. It gets
 *	placed next to the main "Actions" pulldown menu.
 */
void draw_convert_menu(void)
{
	if (convert_menu == NULL) {
		convert_menu = create_popup_menu();
		append_convert_menu_items();
		create_menu_panel(convert_menu, 0, 0);
		cascade_menu(convert_menu, actions_menu, CONVERT_MENUITEM);
	}
	show_panel_window(convert_menu->panel, TRUE);
}

/**
 *	convert_menuitem_activated - function invoked when "Convert" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "Convert" menu item
 *	in the "Actions" menu is selected. It draws the "Convert" pulldown submenu
 *	and processes menu events.
 */
int convert_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_convert_menu();
	rc = process_menu_events(convert_menu);
	return rc;
}

/**
 *	append_other_menu_items - appends the "Other" menu items
 *	@void
 *
 *	This routine appends the menu items for the "Other" menu.
 */
inline void append_other_menu_items(void)
{
	append_menu_item(other_menu, _("Volume Tasks..."),
				_("Perform plug-in specific operations for a Logical Volume"),
				get_accelerator_char(_("_Volume Tasks...")), FALSE,
				(menuitem_activate_cb)actions_show_things_with_plugin_funcs_menuitem_activated,
				GUINT_TO_POINTER(VOLUME));

	append_menu_item(other_menu, _("Storage Object Tasks..."),
				_("Perform plug-in specific operations for a Storage Object"),
				get_accelerator_char(_("_Storage Object Tasks...")), FALSE,
				(menuitem_activate_cb)actions_show_things_with_plugin_funcs_menuitem_activated,
				GUINT_TO_POINTER(EVMS_OBJECT));

	append_menu_item(other_menu, _("Container Tasks..."),
				_("Perform plug-in specific operations for a Storage Container"),
				get_accelerator_char(_("_Container Tasks...")), FALSE,
				(menuitem_activate_cb)actions_show_things_with_plugin_funcs_menuitem_activated,
				GUINT_TO_POINTER(CONTAINER));

	append_menu_item(other_menu, _("Plugin Tasks..."),
				_("Perform general plug-in specific operations"),
				get_accelerator_char(_("_Plugin Tasks...")), FALSE,
				(menuitem_activate_cb)actions_show_things_with_plugin_funcs_menuitem_activated,
				GUINT_TO_POINTER(PLUGIN));
}

/**
 *	draw_convert_menu - draws the "Other" submenu
 *	@void
 *
 *	This routine displays the "Other" pulldown submenu. It gets
 *	placed next to the main "Actions" pulldown menu.
 */
void draw_other_menu(void)
{
	if (other_menu == NULL) {
		other_menu = create_popup_menu();
		append_other_menu_items();
		create_menu_panel(other_menu, 0, 0);
		cascade_menu(other_menu, actions_menu, OTHER_MENUITEM);
	}
	show_panel_window(other_menu->panel, TRUE);
}

/**
 *	other_menuitem_activated - function invoked when "Other" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "Other" menu item
 *	in the "Actions" menu is selected. It draws the "Other" pulldown submenu
 *	and processes menu events.
 */
int other_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_other_menu();
	rc = process_menu_events(other_menu);
	return rc;
}

/**
 *	append_fsys_menu_items - appends the "File System" menu items
 *	@void
 *
 *	This routine appends the menu items for the "File System" menu.
 */
inline void append_fsys_menu_items(void)
{
	append_menu_item(fsys_menu, _("Make..."), _("Create a File System"),
				get_accelerator_char(_("_Make...")), FALSE,
				(menuitem_activate_cb)actions_mkfs_menuitem_activated, NULL);

	append_menu_item(fsys_menu, _("Check/Repair..."), _("Check or Repair a File System"),
				get_accelerator_char(_("_Check/Repair...")), FALSE,
				(menuitem_activate_cb)actions_fsck_menuitem_activated, NULL);

	append_menu_item(fsys_menu, _("Remove..."), _("Remove a File System"),
				get_accelerator_char(_("_Remove...")), FALSE,
				(menuitem_activate_cb)actions_unmkfs_menuitem_activated, NULL);
				
	append_menu_item(fsys_menu, _("Mount..."), _("Mount a File System"),
				get_accelerator_char(_("M_ount...")), FALSE,
				(menuitem_activate_cb)actions_mount_filesystem_menuitem_activated, NULL);

	append_menu_item(fsys_menu, _("Unmount..."), _("Unmount a File System"),
				get_accelerator_char(_("_Unmount...")), FALSE,
				(menuitem_activate_cb)actions_unmount_filesystem_menuitem_activated, NULL);
}

/**
 *	draw_fsys_menu - draws the "File System" submenu
 *	@void
 *
 *	This routine displays the "File System" pulldown submenu. It gets
 *	placed next to the main "Actions" pulldown menu.
 */
void draw_fsys_menu(void)
{
	if (fsys_menu == NULL) {
		fsys_menu = create_popup_menu();
		append_fsys_menu_items();
		create_menu_panel(fsys_menu, 0, 0);
		cascade_menu(fsys_menu, actions_menu, FSYS_MENUITEM);
	}
	show_panel_window(fsys_menu->panel, TRUE);
}

/**
 *	fsys_menuitem_activated - function invoked when "File System" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "File System" menu item
 *	in the "Actions" menu is selected. It draws the "File System" pulldown submenu
 *	and processes menu events.
 */
int fsys_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_fsys_menu();
	rc = process_menu_events(fsys_menu);
	return rc;
}

/**
 *	append_actions_menu_items - appends the "Actions" menu items
 *	@void
 *
 *	This routine appends the menu items for the "Actions" drop down menu.
 */
inline void append_actions_menu_items(void)
{
	append_menu_item(actions_menu, _("Create"), NULL, get_accelerator_char(_("_Create")),
				TRUE, (menuitem_activate_cb)create_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Delete"), NULL, get_accelerator_char(_("_Delete")),
				TRUE, (menuitem_activate_cb)delete_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Activation"), NULL, get_accelerator_char(_("Act_ivation")),
				TRUE, (menuitem_activate_cb)activation_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Expand"), NULL, get_accelerator_char(_("_Expand")),
				TRUE, (menuitem_activate_cb)expand_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Shrink"), NULL, get_accelerator_char(_("S_hrink")),
				TRUE, (menuitem_activate_cb)shrink_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Add"), NULL, get_accelerator_char(_("_Add")),
				TRUE, (menuitem_activate_cb)add_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Remove"), NULL, get_accelerator_char(_("_Remove")),
				TRUE, (menuitem_activate_cb)remove_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Modify"), NULL, get_accelerator_char(_("_Modify")),
				TRUE, (menuitem_activate_cb)modify_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("View"), NULL, get_accelerator_char(_("_View")),
				TRUE, (menuitem_activate_cb)view_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Convert"), NULL, get_accelerator_char(_("C_onvert")),
				TRUE, (menuitem_activate_cb)convert_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Replace..."), NULL, get_accelerator_char(_("Re_place...")),
				FALSE, (menuitem_activate_cb)actions_replace_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Other"), NULL, get_accelerator_char(_("O_ther")),
				TRUE, (menuitem_activate_cb)other_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("File System"), NULL, get_accelerator_char(_("_File System")),
				TRUE, (menuitem_activate_cb)fsys_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Save..."), NULL, get_accelerator_char(_("_Save...")),
				FALSE, (menuitem_activate_cb)on_save_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Backup..."), NULL, get_accelerator_char(_("_Backup...")),
				FALSE, (menuitem_activate_cb)on_backup_menuitem_activated, NULL);

	append_menu_item(actions_menu, _("Quit"), NULL, get_accelerator_char(_("_Quit")),
				FALSE, (menuitem_activate_cb)on_quit_menuitem_activated, NULL);
}

/**
 *	draw_actions_menu - draws the actions menu pulldown
 *	@void
 *
 * 	This routine displays the "Actions" menu. If the menu
 * 	already existing, it is simply redisplayed. Otherwise,
 * 	the panel window is created and the menu items are
 * 	initialized and displayed.
 */
void draw_actions_menu(void)
{
	if (actions_menu == NULL) {
		actions_menu = create_popup_menu();
		append_actions_menu_items();
		create_menu_panel(actions_menu, 1, 0);
	}
	show_panel_window(actions_menu->panel, TRUE);
}

/**
 *	actions_menuitem_activated - function invoked when "Actions" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "Actions" menu item
 *	in the main menubar is selected. It draws the actions pulldown menu and
 *	processes menu events.
 */
int actions_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_actions_menu();
	rc = process_menu_events(actions_menu);
	return rc;
}

/**
 *	append_settings_menu_items - appends the "Settings" menu items
 *	@void
 *
 *	This routine appends the menu items for the "Settings" drop down menu.
 */
inline void append_settings_menu_items(void)
{
	struct menu_item *new_item;

	append_menu_item(settings_menu, _("Log Level..."), NULL,
				get_accelerator_char(_("_Log Level...")),
				FALSE, (menuitem_activate_cb)show_log_level_dialog_menuitem_activated,
				NULL);

	new_item = append_menu_item(settings_menu, _("Node Administered..."), NULL,
				get_accelerator_char(_("_Node Administered...")),
				FALSE, (menuitem_activate_cb)show_nodes_dialog_menuitem_activated,
				NULL);

	if (get_number_of_nodes() <= 1) {
		set_menu_item_sensitivity(new_item, 0);
	}
}

/**
 *	draw_settings_menu - draws the settings menu pulldown
 *	@void
 *
 * 	This routine displays the "Settings" menu. If the menu
 * 	already existing, it is simply redisplayed. Otherwise,
 * 	the panel window is created and the menu items are
 * 	initialized and displayed.
 */
void draw_settings_menu(void)
{
	if (settings_menu == NULL) {
		settings_menu = create_popup_menu();
		append_settings_menu_items();
		create_menu_panel(settings_menu, 1, strlen(_("Actions")) + 3);
	}
	show_panel_window(settings_menu->panel, TRUE);
}

/**
 *	settings_menuitem_activated - function invoked when "Settings" menu item activated
 *	@item: the menu item that caused this function to get invoked
 *
 *	This routine is a callback routine invoked when the "Settings" menu item
 *	in the main menubar is selected. It draws the Settings pulldown menu and
 *	processes menu events.
 */
int settings_menuitem_activated(struct menu_item *item)
{
	int rc;

	draw_settings_menu();
	rc = process_menu_events(settings_menu);
	return rc;
}

/**
 *	append_navigation_menu_items - append menu items to allow jumping to parent, etc.
 *	@menu: the popup menu
 *	@handle: the object handle
 *
 *	This routine appends menu items that allows the user to jump or go to a
 *	a storage objects parent, consuming container or producing container.
 */
void append_navigation_menu_items(struct popup_menu *menu, object_handle_t handle)
{
	object_handle_t parent;
	object_handle_t consuming_container;
	object_handle_t producing_container;

	get_object_handles(handle, &parent, &producing_container, &consuming_container);

	if (parent != 0) {
		append_menu_item(menu, _("Go to parent object"), NULL, 0, FALSE,
					(menuitem_activate_cb)jump_to_view_by_handle,
					GUINT_TO_POINTER(parent));
	}

	if (producing_container != 0) {
		append_menu_item(menu, _("Go to producing container"), NULL, 0, FALSE,
					(menuitem_activate_cb)jump_to_view_by_handle,
					GUINT_TO_POINTER(producing_container));
	}

	if (consuming_container != 0) {
		append_menu_item(menu, _("Go to consuming container"), NULL, 0, FALSE,
					(menuitem_activate_cb)jump_to_view_by_handle,
					GUINT_TO_POINTER(consuming_container));
	}
}

/**
 *	append_object_menu_items - append menu items for actions pertaining to storage objects
 *	@menu: the popup menu
 *	@handle: the object handle
 *	@type: the object type
 *
 *	This routine appends menu items of allowed storage object actions for the
 *	given storage object handle.
 */
void append_object_menu_items(struct popup_menu *menu, object_handle_t handle, object_type_t type)
{
	void *handle_data;

	handle_data = GUINT_TO_POINTER(handle);

	append_menu_item(menu, _("Display Object Tree..."), NULL, 0, FALSE,
			(menuitem_activate_cb)display_object_tree_menuitem_activated,
			handle_data);

	if (evms_can_activate(handle) == 0) {
		append_menu_item(menu, _("Activate..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_activate_menuitem_activated,
					handle_data);
	}

	if (evms_can_deactivate(handle) == 0) {
		append_menu_item(menu, _("Deactivate..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_deactivate_menuitem_activated,
					handle_data);
	}

	if (can_create_from_freespace_object(handle) == TRUE) {
		if (type == REGION) {
			append_menu_item(menu, _("Create Region..."), NULL, 0, FALSE,
					(menuitem_activate_cb)create_region_menuitem_activated,
					handle_data);
		} else if (type == SEGMENT) {
			append_menu_item(menu, _("Create Segment..."), NULL, 0, FALSE,
					(menuitem_activate_cb)create_segment_menuitem_activated,
					handle_data);
		}
	}

	if (can_create_feature_object(handle) == TRUE) {
		append_menu_item(menu, _("Create Feature Object..."), NULL, 0, FALSE,
					(menuitem_activate_cb)create_feature_menuitem_activated,
					handle_data);
	}

	if (evms_can_create_volume(handle) == 0) {
		append_menu_item(menu, _("Create EVMS Volume..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_create_evms_vol_menuitem_activated,
					handle_data);
	}

	if (evms_can_create_compatibility_volume(handle) == 0) {
		append_menu_item(menu, _("Create Compatibility Volume..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_create_vol_menuitem_activated,
					handle_data);
	}

	if (evms_can_set_info(handle) == 0) {
		append_menu_item(menu, _("Modify Properties..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_modify_object_menuitem_activated,
					handle_data);		
	}

	if (evms_can_delete(handle) == 0) {
		append_menu_item(menu, _("Delete..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_delete_menuitem_activated,
					handle_data);
	}

	if (evms_can_expand(handle) == 0) {
		append_menu_item(menu, _("Expand..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_expand_object_menuitem_activated,
					handle_data);
	}

	if (evms_can_shrink(handle) == 0) {
		append_menu_item(menu, _("Shrink..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_shrink_object_menuitem_activated,
					handle_data);
	}

	if (can_replace_object(handle) == 0) {
		append_menu_item(menu, _("Replace..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_replace_menuitem_activated,
					handle_data);
	}

	if (can_remove_from_container(handle) == 0) {
		append_menu_item(menu, _("Remove from Container..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_remove_consumed_object_menuitem_activated,
					handle_data);
	}

	if (evms_can_unassign(handle) == 0) {
		gchar *text;
		
		text = g_strdup_printf(_("Remove %s from Object..."),
					get_parent_plugin_type_string(handle, TRUE));
		append_menu_item(menu, text, NULL, 0, FALSE,
					(menuitem_activate_cb)context_remove_segment_manager_menuitem_activated,
					handle_data);
		g_free(text);
	}
}

/**
 *	append_volume_menu_items - append menu items for actions pertaining to volumes
 *	@menu: the popup menu
 *	@handle: the object handle
 *
 *	This routine appends menu items of allowed logical volume actions for the
 *	given logical volume handle.
 */
void append_volume_menu_items(struct popup_menu *menu, object_handle_t handle)
{
	void *handle_data;
	handle_object_info_t *volume;

	handle_data = GUINT_TO_POINTER(handle);

	if (evms_get_info(handle, &volume) == 0) {
		append_menu_item(menu, _("Display Object Tree..."), NULL, 0, FALSE,
					(menuitem_activate_cb)display_object_tree_menuitem_activated,
					GUINT_TO_POINTER(volume->info.volume.object));
		evms_free(volume);
	}

	if (evms_can_activate(handle) == 0) {
		append_menu_item(menu, _("Activate..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_activate_menuitem_activated,
					handle_data);
	}

	if (evms_can_deactivate(handle) == 0) {
		append_menu_item(menu, _("Deactivate..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_deactivate_menuitem_activated,
					handle_data);
	}

	if (can_volume_accept_new_feature(handle) == TRUE) {
		append_menu_item(menu, _("Add Feature..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_add_feature_menuitem_activated,
					handle_data);
	}

	if (evms_can_convert_to_evms_volume(handle) == 0) {
		append_menu_item(menu, _("Convert to EVMS Volume..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_convert_vol_menuitem_activated,
					handle_data);
	}

	if (evms_can_convert_to_compatibility_volume(handle) == 0) {
		append_menu_item(menu, _("Convert to Compatibility Volume..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_convert_evms_vol_menuitem_activated,
					handle_data);
	}

	if (evms_can_set_volume_name(handle) == 0) {
		append_menu_item(menu, _("Change Volume Name..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_modify_vol_menuitem_activated,
					handle_data);
	}

	if (evms_can_delete(handle) == 0) {
		append_menu_item(menu, _("Delete..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_delete_menuitem_activated,
					handle_data);
	}

	if (evms_can_expand(handle) == 0) {
		append_menu_item(menu, _("Expand..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_expand_volume_menuitem_activated,
					handle_data);
	}

	if (evms_can_shrink(handle) == 0) {
		append_menu_item(menu, _("Shrink..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_shrink_volume_menuitem_activated,
					handle_data);
	}
}

/**
 *	append_filesys_menu_items - append menu items for filesystem actions on a volume
 *	@menu: the popup menu
 *	@handle: the object handle
 *
 *	This routine appends menu items of allowed filesystem actions for the
 *	given logical volume handle.
 */
void append_filesys_menu_items(struct popup_menu *menu, object_handle_t handle)
{
	void *handle_data;

	handle_data = GUINT_TO_POINTER(handle);

	if (evms_can_mount(handle) == 0) {
		append_menu_item(menu, _("Mount..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_mount_filesystem_menuitem_activated,
					handle_data);
	}
	
	if (evms_can_unmount(handle) == 0) {
		append_menu_item(menu, _("Unmount..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_unmount_filesystem_menuitem_activated,
					handle_data);
	}

	if (volume_has_fsim(handle) == TRUE) {
		if (evms_can_fsck(handle) == 0) {
			append_menu_item(menu, _("Check/Repair File System..."), NULL, 0,
						FALSE,
						(menuitem_activate_cb)context_fsck_menuitem_activated,
						handle_data);
		}

		if (evms_can_unmkfs(handle) == 0) {
			append_menu_item(menu, _("Remove File System..."), NULL, 0,
						FALSE,
						(menuitem_activate_cb)context_unmkfs_menuitem_activated,
						handle_data);
		}
	}
	if (can_volume_be_formatted(handle) == TRUE) {
		append_menu_item(menu, _("Make File System..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_mkfs_menuitem_activated,
					handle_data);
	}
}

/**
 *	append_container_menu_items - append menu items for actions pertaining to storage containers
 *	@menu: the popup menu
 *	@handle: the object handle
 *
 *	This routine appends menu items of allowed storage container actions for the
 *	given storage container handle.
 */
void append_container_menu_items(struct popup_menu *menu, object_handle_t handle)
{
	void *handle_data;

	handle_data = GUINT_TO_POINTER(handle);

	if (evms_can_set_info(handle) == 0) {
		append_menu_item(menu, _("Modify Properties..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_modify_container_menuitem_activated,
					handle_data);		
	}

	if (evms_can_delete(handle) == 0) {
		append_menu_item(menu, _("Delete..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_delete_menuitem_activated,
					handle_data);
	}

	if (evms_can_expand(handle) == 0) {
		append_menu_item(menu, _("Expand..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_expand_container_menuitem_activated,
					handle_data);
	}

	if (evms_can_shrink(handle) == 0) {
		append_menu_item(menu, _("Shrink..."), NULL, 0, FALSE,
					(menuitem_activate_cb)context_shrink_container_menuitem_activated,
					handle_data);
	}
}

/**
 *	append_common_menu_items - append menu items for actions pertaining to all types
 *	@menu: the popup menu
 *	@handle: the object handle
 *
 *	This routine appends menu items that apply to all object types without requiring
 *	a check.
 */
void append_common_menu_items(struct popup_menu *menu, object_handle_t handle)
{
	void *handle_data;

	handle_data = GUINT_TO_POINTER(handle);

	append_menu_item(menu, _("Display details..."), NULL, 0, FALSE,
				(menuitem_activate_cb)display_details_menuitem_activated,
				handle_data);
}

/**
 *	append_context_menu_items - appends actions available for the given handle
 *	@menu: the popup menu
 *	@handle: the object handle
 *
 *	This routine appends menu items to the context popup menu for actions available
 *	on the given object handle.
 */
void append_context_menu_items(struct popup_menu *menu, object_handle_t handle)
{
	object_type_t type;

	g_return_if_fail(evms_get_handle_object_type(handle, &type) == 0);

	switch (type) {
	case EVMS_OBJECT:
	case REGION:
	case SEGMENT:
	case DISK:
		append_navigation_menu_items(menu, handle);
		append_common_menu_items(menu, handle);
		append_object_menu_items(menu, handle, type);
		break;
	case VOLUME:
		append_common_menu_items(menu, handle);
		append_volume_menu_items(menu, handle);
		append_filesys_menu_items(menu, handle);
		break;
	case CONTAINER:
		append_common_menu_items(menu, handle);
		append_container_menu_items(menu, handle);
		break;
	case PLUGIN:
		append_common_menu_items(menu, handle);
		break;
	default:
		log_warning("%s: Unknown type %d encountered.\n", __FUNCTION__, type);
		break;
	}
	append_plugin_function_menu_items(menu, handle);
}

/**
 *	popup_context_menu - display and process a context popup menu for a handle
 *	@handle: the object handle
 *	@starty: where to position the menu on the screen
 *	@startx: where to position the menu on the screen
 *
 *	This routine creates a context popup menu for a given object handle. It
 *	populates the menu with selections only valid for this object. The context
 *	popup is a modal window.
 */
void popup_context_menu(object_handle_t handle, int starty, int startx)
{
	struct popup_menu *menu;

	menu = create_popup_menu();
	append_context_menu_items(menu, handle);
	create_menu_panel(menu, starty, startx);
	process_menu_events(menu);
	delete_popup_menu(menu);
}