11.15 Initial and Default Menu Selections
Two special menu items are the default item (MENU_DEFAULT_ITEM) and the selected item
(MENU_SELECTED_ITEM). The default item defaults to the first item in the menu, and the
selected item is the selected item (or items for MENU_TOGGLE_MENU menus).
Although the default menu item may be set by using xv_set(), the user may interactively
change the default menu item by holding down the CONTROL key while also selecting a
menu item with the MENU button. Therefore, if the user selects a menu item that has a
pullright menu, but the pullright menu is not activated,* when your notify procedure is
called, you may choose to descend into the pullright menu and find the default menu item and
call that item’s callback routine.
11.16 Unpinned Command Frame Dismissal
XView normally handles unpinned command frame dismissal for you when a user action
within the command frame completes successfully. If a menu is brought up from a Menu
Button in the command frame, and the user makes a selection from the menu, the command
frame is dismissed if the pushpin (if visible) is out. By default, the attribute
MENU_NOTIFY_STATUS is set to XV_OK, which indicates that the command frame should be
dismissed if the pushpin is out, and the callback returns successfully. However, if the user-
specified action does not complete successfully, you may not want the command frame to be
dismissed. In this case, within the menu’s notify procedure or within the menu item’s notify
procedure, you should set the value of MENU_NOTIFY_STATUS to XV_ERROR. This indicates
that the user selection was invalid or failed, and prevents the command frame from being
dismissed.
11.17 Destroying Menus
Destruction of menus is an important task because menus are frequently used and, if their
resources are not freed adequately, you could find the size of your application growing rap-
idly until your system runs out of available memory. Therefore, proper cleanup of menu
destruction is imperative. Menus are destroyed using xv_destroy(). In the case of static
menus, nothing more is required than calling xv_destroy(). This is because the internals
of XView automatically set attributes discussed in this section.
Be aware of several situations, such as when you:
Allocate your own strings or server images as menu item labels.
Create your own menu items using
xv_create(NULL, MENUITEM, . . . ).
Generate your own pullright menus.
*This might happen if the user did not drag the mouse far enough to the right.
298 XView Programming Manual
The destruction phase walks down each menu item in the menu and tests each menu item to
see if it has the MENU_RELEASE attribute set. This is not a Boolean attribute—it has no value
associated with it at all. If you specify the attribute, the attribute is set. If you do not specify
it, then the attribute is not set. As noted, menu items that have been created in-line have
MENU_RELEASE set already.
Menu items that you create yourself do not have MENU_RELEASE set by default. You also
may or may not want it set. If you plan to reuse menu itemsa need that is commonthen
you do not want to set this attribute. However, you must maintain a handle to the menu item
or it is lost. If the attribute is set, then the menu item is freed, but no other data associated
with the menu item is destroyed. Only the item itself is. If you have any allocated data asso-
ciated with the menu item, then you either need to free it yourself or give a hint to XView to
free it for you.
The following subsections discuss other data allocated for menu items. Remember that free-
ing menus and menu items is not done automatically; this only happens as a result of your
calling xv_destroy(). So, if you decide to free menus or menu items, you should be sure
to free pullright menus and/or client data yourself beforehand.
There are cases when xv_destroy() will not remove a menu. In order to free the memory
associated with a menu using xv_destroy(), you need to be certain that no objects refer-
ence the menu. For example, if you attach a menu to a panel button item using the attribute
PANEL_ITEM_MENU, you need to be sure to clear the PANEL_ITEM_MENU attribute before you
try to destroy the menu. In this example, the following calls would be required to clear the
panel button item’s attached menu, and to destroy the menu. For more information on this
topic, refer to the description of XV_REF_COUNT in Chapter 7, Panels.
xv_set(panel_item, PANEL_ITEM_MENU, NULL, NULL);
xv_destroy(menu);
11.17.1 Freeing Allocated Strings
If you create a menu item with allocated data, you should not use them in a MENU_STRINGS
list. Instead, you should create the menu items individually, as shown in Example 11-4.
Example 11-4. Creating individual menu items
char *str1;
if (str1 = malloc(strlen(buf)+1))
strcpy(str1, buf);
menu = xv_create(NULL, MENU,
MENU_ITEM,
MENU_STRING, str1,
MENU_RELEASE_IMAGE,
NULL,
NULL);
The code in Example 11-4 shows a menu item that is created in-line because it is created
using the MENU_ITEM attribute. However, because the string used as the menu item’s label is
allocated, we need to provide XView with a hint to release this data.
Menus
Menus 299
Similarly, if we used xv_create() to create a Server_image as the menu item’s label,
the MENU_RELEASE_IMAGE attribute suffices to free that data as well.
11.17.2 Freeing Pullright Menus
Even though a menu item has MENU_RELEASE set, if a pullright menu is associated with it, the
menu will not be freed. In many cases, this is acceptable because many menu items may
share the same pullright menu. If you are sure you do not need the menu anymore, then you
should free it. Note that freeing the menu will attempt to free the menu items within it.
This is most commonly done in menu-generating routines installed as the MENU_GEN_
PULLRIGHT
attribute.
11.17.3 Menu Client Data
If a menu item is freed, you should be sure to free any client data that is associated with it.
Client data may have been attached to the menu item using
XV_KEY_DATA or MENU_
CLIENT_DATA
.
If you created menus for panel buttons, and you destroy the
MENU button (or the panel asso-
ciated with that button), then you are responsible for destroying the menu you created. The
panel does not handle this for you. Destroying the menu attached to menu buttons is done the
same way as it is for menus.
11.18 Example Program
The following brief descriptions are introductory notes about the programs menu_dir.c (listed
in Example 11-5) and menu_dir2.c (listed in Appendix F, Example Programs). The com-
ments in the programs as well as the code itself should be read for full details.
menu_dir.c demonstrates many of the features of the MENU package presented in this chapter.
It displays a menu that contains all the files from the current directory. If a pathname is given
on the command line, that directory is used. The entire menu hierarchy is built initially at
start-up time, so directories that do not have extremely long paths should be specified.*
For each directory found, a new menu is created and the directory is descended building
items for the new menu. menu_dir2.c also builds cascading menus for directories, but instead
of descending into the directory tree, a menu-generating routine is called only if the user tries
to go into a pullright.
Example 11-5. The menu_dir.c program
/*
*Don’t even think of specifying /.
300 XView Programming Manual
Example 11-5. The menu_dir.c program (continued)
* menu_dir.c -
* Demonstrate the use of an XView menu in a canvas subwindow.
* A menu is brought up with the MENU mouse button and displays
* menu choices representing the files in the directory. If a
* directory entry is found, a new pullright item is created with
* that subdir as the pullright menus contents. This implementation
* creates the entire directory tree initially. Do not attempt to
* build a tree from /. You will most likely run out of resources.
*
* argv[1] indicates which directory to start from.
*/
#include <xview/xview.h>
#include <xview/canvas.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <X11/Xos.h>
#ifndef MAXPATHLEN
#include <sys/param.h> /* probably sun/BSD specific */
#endif /* MAXPATHLEN */
Frame frame;
/*
* main -
* Create a frame, canvas and menu.
* A canvas receives input in its canvas_paint_window().
* Its callback procedure calls menu_show().
*/
main(argc,argv)
int argc;
char *argv[ ];
{
Canvas canvas;
extern void exit();
void my_event_proc();
Menu menu;
Menu_item mi, add_path_to_menu();
xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);
frame = (Frame)xv_create(NULL, FRAME,
FRAME_LABEL, argv[1]? argv[1] : "cwd",
FRAME_SHOW_FOOTER, TRUE,
NULL);
canvas = (Canvas)xv_create(frame, CANVAS,
FRAME_LABEL, argv[0 ],
XV_WIDTH, 400,
XV_HEIGHT, 100,
NULL);
mi = add_path_to_menu(argc > 1? argv[1 ] : ".");
menu = (Menu)xv_get(mi, MENU_PULLRIGHT);
/* associate the menu to the canvas win for easy retrieval */
xv_set(canvas_paint_window(canvas),
WIN_CONSUME_EVENTS, WIN_MOUSE_BUTTONS, NULL,
Menus
Menus 301
Example 11-5. The menu_dir.c program (continued)
WIN_EVENT_PROC, my_event_proc,
WIN_CLIENT_DATA, menu,
NULL);
window_fit(frame);
window_main_loop(frame);
}
/*
* my_action_proc - display the selected item in the frame footer.
*/
void
my_action_proc(menu, menu_item)
Menu menu;
Menu_item menu_item;
{
xv_set(frame,
FRAME_LEFT_FOOTER, xv_get(menu_item, MENU_STRING),
NULL);
}
/*
* Call menu_show() to display menu on right mouse button push.
*/
void
my_event_proc(canvas, event)
Canvas canvas;
Event *event;
{
if ((event_id(event) == MS_RIGHT) && event_is_down(event)) {
Menu menu = (Menu)xv_get(canvas, WIN_CLIENT_DATA);
menu_show(menu, canvas, event, NULL);
}
}
/*
* return an allocated char * that points to the last item in a path.
*/
char *
getfilename(path)
char *path;
{
char *p;
if (p = rindex(path, /))
p++;
else
p = path;
return strcpy(malloc(strlen(p)+1), p);
}
/*
* The path passed in is scanned via readdir(). For each file in the
* path, a menu item is created and inserted into a new menu. That
* new menu is made the PULLRIGHT_MENU of a newly created panel item
* for the path item originally passed it. Since this routine is
302 XView Programming Manual

Get Volume 7A: XView Programming Manual now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.