view oldXMenu/Activate.c @ 109165:750db9f3e6d8

Replace bcopy, bzero, bcmp by memcpy, memmove, memset, memcmp * alloc.c (overrun_check_malloc, overrun_check_realloc) (overrun_check_free, xstrdup, allocate_string) (allocate_string_data, compact_small_strings, Fmake_string) (make_unibyte_string, make_multibyte_string) (make_string_from_bytes, make_specified_string, make_float) (Fcons, allocate_terminal, allocate_frame, make_pure_string) (Fgarbage_collect): Replace bcopy, safe_bcopy, bzero, bcmp by memcpy, memmove, memset, memcmp. * atimer.c (start_atimer, set_alarm): Likewise. * buffer.c (clone_per_buffer_values, report_overlay_modification) (mmap_realloc, init_buffer_once): Likewise. * callint.c (Fcall_interactively): Likewise. * callproc.c (Fcall_process, Fcall_process_region, child_setup) (getenv_internal_1): Likewise. * casefiddle.c (casify_object): Likewise. * ccl.c (ccl_driver): Likewise. * character.c (str_as_multibyte, str_to_multibyte): Likewise. * charset.c (load_charset_map_from_file) (load_charset_map_from_file, load_charset_map_from_vector) (Fdefine_charset_internal): Likewise. * cm.c (Wcm_clear): Likewise. * coding.c (decode_eol, decode_coding_object) (Fset_coding_system_priority, make_subsidiaries): Likewise. * data.c (Faset): Likewise. * dired.c (directory_files_internal, file_name_completion_stat): Likewise. * dispnew.c (new_glyph_matrix, adjust_glyph_matrix) (clear_glyph_row, copy_row_except_pointers) (copy_glyph_row_contents, new_glyph_pool, realloc_glyph_pool) (save_current_matrix, restore_current_matrix) (build_frame_matrix_from_leaf_window, mirrored_line_dance) (mirror_line_dance, scrolling_window): Likewise. * doc.c (Fsnarf_documentation, Fsubstitute_command_keys): Likewise. * doprnt.c (doprnt): Likewise. * editfns.c (Fuser_full_name, make_buffer_string_both) (Fmessage_box, Fformat, Ftranspose_regions): Likewise. * emacs.c (sort_args): Likewise. * eval.c (Fapply, Ffuncall): Likewise. * fileio.c (Ffile_name_directory, make_temp_name) (Fexpand_file_name, search_embedded_absfilename) (Fsubstitute_in_file_name, Ffile_symlink_p, Finsert_file_contents) (auto_save_error): Likewise. * fns.c (Fstring_equal, Fcopy_sequence, concat) (string_to_multibyte, Fstring_as_unibyte, Fstring_as_multibyte) (internal_equal, Fclear_string, larger_vector, copy_hash_table) (Fmake_hash_table): Likewise. * fringe.c (Fdefine_fringe_bitmap): Likewise. * ftfont.c (ftfont_text_extents): Likewise. * getloadavg.c (getloadavg): Likewise. * image.c (define_image_type, make_image, make_image_cache) (x_create_x_image_and_pixmap, xbm_image_p) (w32_create_pixmap_from_bitmap_data, xbm_load, xpm_lookup_color) (xpm_image_p, x_create_bitmap_from_xpm_data, xpm_load) (init_color_table, x_build_heuristic_mask, pbm_image_p, pbm_load) (png_image_p, png_read_from_memory, png_load, jpeg_image_p) (tiff_image_p, tiff_read_from_memory, gif_image_p) (gif_read_from_memory, gif_load, svg_image_p, gs_image_p): Likewise. * indent.c (scan_for_column, compute_motion): Likewise. * insdel.c (gap_left, gap_right, make_gap_smaller, copy_text) (insert_1_both, insert_from_gap, replace_range_2): Likewise. * intervals.c (reproduce_tree, reproduce_tree_obj): Likewise. * keyboard.c (echo_char, save_getcjmp, restore_getcjmp) (kbd_buffer_store_event_hold, apply_modifiers_uncached) (store_user_signal_events, menu_bar_items, tool_bar_items) (process_tool_bar_item, append_tool_bar_item) (read_char_minibuf_menu_prompt, read_key_sequence) (Fread_key_sequence, Fread_key_sequence_vector, Frecent_keys): Likewise. * keymap.c (current_minor_maps, Fdescribe_buffer_bindings): Likewise. * lisp.h (STRING_COPYIN): Likewise. * lread.c (Fload, read1, oblookup): Likewise. * msdos.c (Frecent_doskeys): Likewise. * nsfns.m (Fx_create_frame): Likewise. * nsfont.m (nsfont_open, nsfont_text_extents, ns_glyph_metrics): Likewise. * nsimage.m (EmacsImage-initFromSkipXBM:width:height:) (EmacsImage-initForXPMWithDepth:width:height:flip:length:): Likewise. * nsmenu.m (ns_update_menubar): Likewise. * nsterm.m (ns_draw_fringe_bitmap, ns_term_init): Likewise. * print.c (print_unwind, printchar, strout, print_string) (print_error_message): Likewise. * process.c (conv_lisp_to_sockaddr, set_socket_option) (Fmake_network_process, Fnetwork_interface_list) (Fnetwork_interface_info, read_process_output, Fprocess_send_eof) (init_process): Likewise. * ralloc.c (resize_bloc, r_alloc_sbrk, r_alloc_init): Likewise. * regex.c (init_syntax_once, regex_compile, re_compile_fastmap): Likewise. * scroll.c (do_scrolling, do_direct_scrolling) (scrolling_max_lines_saved): Likewise. * search.c (search_buffer, wordify, Freplace_match): Likewise. * sound.c (wav_init, au_init, Fplay_sound_internal): Likewise. * syntax.c (skip_chars, skip_syntaxes): Likewise. * sysdep.c (child_setup_tty, sys_subshell, emacs_get_tty) (emacs_set_tty): Likewise. * term.c (encode_terminal_code, calculate_costs) (produce_special_glyphs, create_tty_output, init_tty, delete_tty): Likewise. * termcap.c (tgetst1, gobble_line): Likewise. * termhooks.h (EVENT_INIT): Likewise. * tparam.c (tparam1): Likewise. * unexalpha.c (unexec): Likewise. * unexec.c (write_segment): Likewise. * unexmacosx.c (unexec_write_zero): Likewise. * w32fns.c (w32_wnd_proc, Fx_create_frame, x_create_tip_frame) (Fx_file_dialog, Fsystem_move_file_to_trash): Likewise. * w32font.c (w32font_list_family, w32font_text_extents) (w32font_list_internal, w32font_match_internal) (w32font_open_internal, compute_metrics, Fx_select_font): Likewise. * w32menu.c (set_frame_menubar, add_menu_item) (w32_menu_display_help, w32_free_submenu_strings): Likewise. * w32term.c (XCreateGC, w32_initialize_display_info): Likewise. * w32uniscribe.c (uniscribe_list_family): Likewise. * w32xfns.c (get_next_msg, post_msg, prepend_msg): Likewise. * window.c (make_window, replace_window, set_window_buffer) (Fsplit_window): Likewise. * xdisp.c (init_iterator, RECORD_OVERLAY_STRING, reseat_to_string) (add_to_log, message3, x_consider_frame_title) (append_space_for_newline, extend_face_to_end_of_line) (decode_mode_spec_coding, init_glyph_string): Likewise. * xfaces.c (x_create_gc, get_lface_attributes_no_remap) (Finternal_copy_lisp_face, Finternal_merge_in_global_face) (face_attr_equal_p, make_realized_face, make_face_cache) (free_realized_faces, lookup_named_face, smaller_face) (face_with_height, lookup_derived_face) (x_supports_face_attributes_p, Finternal_set_font_selection_order) (Finternal_set_font_selection_order, realize_default_face) (compute_char_face, face_at_buffer_position) (face_for_overlay_string, face_at_string_position, merge_faces): Likewise. * xfns.c (xic_create_fontsetname, Fx_create_frame) (Fx_window_property, x_create_tip_frame) (Fx_backspace_delete_keys_p): Likewise. * xfont.c (xfont_list, xfont_match, xfont_list_family) (xfont_text_extents): Likewise. * xmenu.c (set_frame_menubar, xmenu_show): Likewise. * xrdb.c (magic_file_p, x_get_resource): Likewise. * xselect.c (x_queue_event, x_get_window_property) (receive_incremental_selection): Likewise. * xsmfns.c (x_session_check_input): Likewise. * xterm.c (x_send_scroll_bar_event, SET_SAVED_MENU_EVENT) (handle_one_xevent, x_check_errors, xim_initialize, x_term_init): Likewise. * character.h (BCOPY_SHORT): Removed. * config.in: Regenerate. * dispnew.c (safe_bcopy): Only define as dummy if PROFILING. * emacs.c (main) [PROFILING]: Don't declare dump_opcode_frequencies. * lisp.h (safe_bcopy): Remove declaration. (memset) [!HAVE_MEMSET]: Declare. (memcpy) [!HAVE_MEMCPY]: Likewise. (memmove) [!HAVE_MEMMOVE]: Likewise. (memcmp) [!HAVE_MEMCMP]: Likewise. * s/ms-w32.h (bzero, bcopy, bcmp, GAP_USE_BCOPY) (BCOPY_UPWARD_SAFE, BCOPY_DOWNWARD_SAFE, HAVE_BCOPY, HAVE_BCMP): Don't define. (HAVE_MEMCMP, HAVE_MEMCPY, HAVE_MEMMOVE, HAVE_MEMSET): Define. * s/msdos.h (GAP_USE_BCOPY, BCOPY_UPWARD_SAFE) (BCOPY_DOWNWARD_SAFE): Don't define. * sysdep.c (memset) [!HAVE_MEMSET]: Define. (memcpy) [!HAVE_MEMCPY]: Define. (memmove) [!HAVE_MEMMOVE]: Define. (memcmp) [!HAVE_MEMCMP]: Define. * config.nt (HAVE_BCOPY, HAVE_BCMP): Remove undefs. (HAVE_MEMCPY, HAVE_MEMMOVE, HAVE_MEMSET, HAVE_MEMCMP): Add undefs. * sed2v2.inp (HAVE_MEMCPY, HAVE_MEMSET): Edit to 1. (HAVE_BZERO): Don't edit. * lwlib.c (lwlib_memset, lwlib_bcopy): Remove. (malloc_widget_value, free_widget_info, allocate_widget_instance) (lw_separator_p): Replace lwlib_memset, lwlib_bcopy, bzero, bcmp by memset, memcpy, memcmp. * lwlib-utils.c (XtApplyToWidgets): Likewise. * xlwmenu.c (XlwMenuInitialize): Likewise. * lwlib.h (lwlib_bcopy): Remove declaration. * ebrowse.c (add_sym, make_namespace): Replace bcopy, bzero by memcpy, memmove, memset. * pop.c (pop_retrieve, socket_connection, pop_getline): Likewise. * CPP-DEFINES (BCOPY_DOWNWARD_SAFE, BCOPY_UPWARD_SAFE) (GAP_USE_BCOPY, HAVE_BCMP, HAVE_BCOPY, bcmp, bcopy, bzero): Remove. * configure.in: Don't check for bcopy, bcmp, bzero. Don't include <strings.h> and don't define bcopy, bzero, BCMP in config.h.
author Andreas Schwab <schwab@linux-m68k.org>
date Thu, 08 Jul 2010 00:18:28 +0200
parents 5cc91198ffb2
children 417b1e4d63cd
line wrap: on
line source

/* Copyright    Massachusetts Institute of Technology    1985	*/

#include "copyright.h"

/*
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
  Free Software Foundation, Inc.

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 3 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, see <http://www.gnu.org/licenses/>.  */

/*
 * XMenu:	MIT Project Athena, X Window system menu package
 *
 *	XMenuActivate -	Maps a given menu to the display and activates
 *			the menu for user selection.  The user is allowed to
 *			specify which pane and selection will be current,
 *			the X and Y location of the menu (relative to the
 *			parent window) and the mouse button event mask that
 *			will be used to identify a selection request.
 *
 *			A menu selection is shown to be current by placing
 *			a highlight box around the selection as the mouse
 *			cursor enters its active region.  Inactive selections
 *			will not be highlighted.  As the mouse cursor moved
 *			from one menu pane to another menu pane the pane being
 *			entered is raised and made current and the pane being
 *			left is lowered.
 *
 *			Anytime XMenuActivate returns, the p_num and
 *			s_num are left at their last known values (i.e.,
 *			the last known current pane and selection indices).
 *			The following are the defined return states:
 *
 *			1)	If at any time an error occurs the data
 *				pointer is left untouched and XM_FAILURE
 *				is returned.
 *
 *			2)	When a selection request is received (i.e.,
 *				when the specified mouse event occurs) the
 *				data pointer will be set to the data
 *				associated with the particular selection
 *				current at the time of the selection request
 *				and XM_SUCCESS is returned.
 *
 *			3)	If no selection was current at the time a
 *				selection request is made the data pointer
 *				will be left untouched and XM_NO_SELECT will
 *				be returned.
 *
 *			4)	If the selection that was current at the time
 *				a selection request is made is not an active
 *				selection the data pointer will be left
 *				untouched and XM_IA_SELECT will be returned.
 *
 *			Since X processes events in an asynchronous manner
 *			it is likely that XMenuActivate will encounter
 *			a "foreign event" while it is executing.  Foreign
 *			events are handled in one of three ways:
 *
 *			1)	The event is discarded.  This is the default
 *				mode and requires no action on the part of the
 *				application.
 *
 *			2)	The application has identified an asynchronous
 *				event handler that will be called and the
 *				foreign event handed off to it.  Note:
 *				AEQ mode disables this mode temporarily.
 *
 *			3)	The application has enabled asynchronous event
 *				queuing mode.  In this mode all foreign events
 *				will be	queued up untill XMenuActivate
 *				terminates; at which time they will be
 *				returned to the	X event queue.  As long as
 *				AEQ mode is enabled any asynchronous event
 *				handler as temporarily disabled.
 *
 *			Any events encountered while taking down the menu
 *			(i.e., exposure events from occluded windows) will
 *			automatically be returned to the X event queue after
 *			XMenuActivate has cleaned the queue of any of its own
 *			events that are no longer needed.
 *
 *	Author:		Tony Della Fera, DEC
 *			March 12, 1986
 *
 */

#include <config.h>
#include "XMenuInt.h"
#include <X11/keysym.h>

/* For debug, set this to 0 to not grab the keyboard on menu popup */
int x_menu_grab_keyboard = 1;

static Wait_func wait_func;
static void* wait_data;

void
XMenuActivateSetWaitFunction (Wait_func func, void *data)
{
  wait_func = func;
  wait_data = data;
}

int
XMenuActivate(
    register Display *display,		/* Display to put menu on. */
    register XMenu *menu,		/* Menu to activate. */
    int *p_num,				/* Pane number selected. */
    int *s_num,				/* Selection number selected. */
    int x_pos,				/* X coordinate of menu position. */
    int y_pos,				/* Y coordinate of menu position. */
    unsigned int event_mask,		/* Mouse button event mask. */
    char **data,			/* Pointer to return data value. */
    void (* help_callback) (char *, int, int)) /* Help callback.  */
{
    int status;				/* X routine call status. */
    int orig_x;				/* Upper left menu origin X coord. */
    int orig_y;				/* Upper left menu origin Y coord. */
    int ret_val;			/* Return value. */

    register XMPane *p_ptr;		/* Current XMPane. */
    register XMPane *event_xmp;		/* Event XMPane pointer. */
    register XMPane *cur_p;		/* Current pane. */
    register XMSelect *cur_s;		/* Current selection. */
    XMWindow *event_xmw;		/* Event XMWindow pointer. */
    XEvent event;			/* X input event. */
    XEvent peek_event;			/* X input peek ahead event. */

    Bool selection = False;		/* Selection has been made. */
    Bool forward = True;		/* Moving forward in the pane list. */

    Window root, child;
    int root_x, root_y, win_x, win_y;
    unsigned int mask;
    KeySym keysym;

    /*
     * Define and allocate a foreign event queue to hold events
     * that don't belong to XMenu.  These events are later restored
     * to the X event queue.
     */
    typedef struct _xmeventque {
	XEvent event;
	struct _xmeventque *next;
    } XMEventQue;

    XMEventQue *feq = NULL;    		/* Foreign event queue. */
    XMEventQue *feq_tmp;		/* Foreign event queue temporary. */

    /*
     * If there are no panes in the menu then return failure
     * because the menu is not initialized.
     */
    if (menu->p_count == 0) {
	_XMErrorCode = XME_NOT_INIT;
	return(XM_FAILURE);
    }

    /*
     * Find the desired current pane.
     */
    cur_p = _XMGetPanePtr(menu, *p_num);
    if (cur_p == NULL) {
	return(XM_FAILURE);
    }
    cur_p->activated = cur_p->active;

    /*
     * Find the desired current selection.
     * If the current selection index is out of range a null current selection
     * will be assumed and the cursor will be placed in the current pane
     * header.
     */
    cur_s = _XMGetSelectionPtr(cur_p, *s_num);

    /*
     * Compute origin of menu so that cursor is in
     * Correct pane and selection.
     */
    _XMTransToOrigin(display,
		     menu,
		     cur_p, cur_s,
		     x_pos, y_pos,
		     &orig_x, &orig_y);
    menu->x_pos = orig_x;	/* Store X and Y coords of menu. */
    menu->y_pos = orig_y;

    if (XMenuRecompute(display, menu) == XM_FAILURE) {
	return(XM_FAILURE);
    }

    /*
     * Flush the window creation queue.
     * This batches all window creates since lazy evaluation
     * is more efficient than individual evaluation.
     * This routine also does an XFlush().
     */
    if (_XMWinQueFlush(display, menu, cur_p, cur_s) == _FAILURE) {
	return(XM_FAILURE);
    }

    /*
     * Make sure windows are in correct order (in case we were passed
     * an already created menu in incorrect order.)
     */
    for(p_ptr = menu->p_list->next; p_ptr != cur_p; p_ptr = p_ptr->next)
	XRaiseWindow(display, p_ptr->window);
    for(p_ptr = menu->p_list->prev; p_ptr != cur_p->prev; p_ptr = p_ptr->prev)
	XRaiseWindow(display, p_ptr->window);

    /*
     * Make sure all selection windows are mapped.
     */
    for (
	p_ptr = menu->p_list->next;
	p_ptr != menu->p_list;
	p_ptr = p_ptr->next
    ){
	XMapSubwindows(display, p_ptr->window);
    }

    /*
     * Synchronize the X buffers and the event queue.
     * From here on, all events in the queue that don't belong to
     * XMenu are sent back to the application via an application
     * provided event handler or discarded if the application has
     * not provided an event handler.
     */
    XSync(display, 0);

    /*
     * Grab the mouse for menu input.
     */

    status = XGrabPointer(
			  display,
			  menu->parent,
			  True,
			  event_mask,
			  GrabModeAsync,
			  GrabModeAsync,
			  None,
			  menu->mouse_cursor,
			  CurrentTime
			  );
    if (status == Success && x_menu_grab_keyboard)
      {
        status = XGrabKeyboard (display,
                                menu->parent,
                                False,
                                GrabModeAsync,
                                GrabModeAsync,
                                CurrentTime);
        if (status != Success)
          XUngrabPointer(display, CurrentTime);
      }

    if (status == _X_FAILURE) {
	_XMErrorCode = XME_GRAB_MOUSE;
	return(XM_FAILURE);
    }

    /*
     * Map the menu panes.
     */
    XMapWindow(display, cur_p->window);
    for (p_ptr = menu->p_list->next;
	 p_ptr != cur_p;
	 p_ptr = p_ptr->next)
      XMapWindow(display, p_ptr->window);
    for (p_ptr = cur_p->next;
	 p_ptr != menu->p_list;
	 p_ptr = p_ptr->next)
      XMapWindow(display, p_ptr->window);

    XRaiseWindow(display, cur_p->window);	/* Make sure current */
						/* pane is on top. */

    cur_s = NULL;			/* Clear current selection. */

    /*
     * Begin event processing loop.
     */
    while (1) {
        if (wait_func) (*wait_func) (wait_data);
	XNextEvent(display, &event);	/* Get next event. */
	switch (event.type) {		/* Dispatch on the event type. */
    case Expose:
	    event_xmp = (XMPane *)XLookUpAssoc(display,
					       menu->assoc_tab,
					       event.xexpose.window);
	    if (event_xmp == NULL) {
		/*
		 * If AEQ mode is enabled then queue the event.
		 */
		if (menu->aeq) {
		    feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue));
		    if (feq_tmp == NULL) {
			_XMErrorCode = XME_CALLOC;
			return(XM_FAILURE);
		    }
		    feq_tmp->event = event;
		    feq_tmp->next = feq;
		    feq = feq_tmp;
		}
		else if (_XMEventHandler) (*_XMEventHandler)(&event);
		break;
	    }
	    if (event_xmp->activated) {
		XSetWindowBackground(display,
				     event_xmp->window,
				     menu->bkgnd_color);
	    }
	    else {
		XSetWindowBackgroundPixmap(display,
					   event_xmp->window,
					   menu->inact_pixmap);
	    }
	    _XMRefreshPane(display, menu, event_xmp);
	    break;
    case EnterNotify:
	    /*
	     * First wait a small period of time, and see
	     * if another EnterNotify event follows hard on the
	     * heels of this one. i.e., the user is simply
	     * "passing through". If so, ignore this one.
	     */

	    event_xmw = (XMWindow *)XLookUpAssoc(display,
						 menu->assoc_tab,
						 event.xcrossing.window);
	    if (event_xmw == NULL) break;
	    if (event_xmw->type == SELECTION) {
		/*
		 * We have entered a selection.
		 */
		/* if (XPending(display) == 0) usleep(150000); */
		if (XPending(display) != 0) {
		    XPeekEvent(display, &peek_event);
		    if(peek_event.type == LeaveNotify) {
			break;
		    }
		}
		cur_s = (XMSelect *)event_xmw;
		help_callback (cur_s->help_string,
			       cur_p->serial, cur_s->serial);

		/*
		 * If the pane we are in is active and the
		 * selection entered is active then activate
		 * the selection.
		 */
		if (cur_p->active && cur_s->active > 0) {
		    cur_s->activated = 1;
		    _XMRefreshSelection(display, menu, cur_s);
		}
	    }
	    else {
		/*
		 * We have entered a pane.
		 */
		/* if (XPending(display) == 0) usleep(150000); */
		if (XPending(display) != 0) {
		    XPeekEvent(display, &peek_event);
		    if (peek_event.type == EnterNotify) break;
		}
		XQueryPointer(display,
			      menu->parent,
			      &root, &child,
			      &root_x, &root_y,
			      &win_x, &win_y,
			      &mask);
		event_xmp = (XMPane *)XLookUpAssoc(display,
						   menu->assoc_tab,
						   child);
		if (event_xmp == NULL) break;
		if (event_xmp == cur_p) break;
		if (event_xmp->serial > cur_p->serial) forward = True;
		else forward = False;
		p_ptr = cur_p;
		while (p_ptr != event_xmp) {
		    if (forward) p_ptr = p_ptr->next;
		    else p_ptr = p_ptr->prev;
		    XRaiseWindow(display, p_ptr->window);
		}
		if (cur_p->activated) {
		    cur_p->activated = False;
		    XSetWindowBackgroundPixmap(display,
					       cur_p->window,
					       menu->inact_pixmap);
		    _XMRefreshPane(display, menu, cur_p);
		}
		if (event_xmp->active) event_xmp->activated = True;
#if 1
		/*
		 * i suspect the we don't get an EXPOSE event when backing
		 * store is enabled; the menu windows content is probably
		 * not drawn in when it should be in that case.
		 * in that case, this is probably an ugly fix!
		 * i hope someone more familiar with this code would
		 * take it from here.  -- caveh@eng.sun.com.
		 */
		XSetWindowBackground(display,
				     event_xmp->window,
				     menu->bkgnd_color);
		_XMRefreshPane(display, menu, event_xmp);
#endif
		cur_p = event_xmp;
	    }
	    break;
    case LeaveNotify:
	    event_xmw = (XMWindow *)XLookUpAssoc(
						 display,
						 menu->assoc_tab,
						 event.xcrossing.window
						 );
	    if (event_xmw == NULL) break;
	    if(cur_s == NULL) break;

	    /*
	     * If the current selection was activated then
	     * deactivate it.
	     */
	    if (cur_s->activated) {
		cur_s->activated = False;
		_XMRefreshSelection(display, menu, cur_s);
	    }
	    cur_s = NULL;
	    break;

    case ButtonPress:
    case ButtonRelease:
		*p_num = cur_p->serial;
		/*
		 * Check to see if there is a current selection.
		 */
		if (cur_s != NULL) {
		    /*
		     * Set the selection number to the current selection.
		     */
		    *s_num = cur_s->serial;
		    /*
		     * If the current selection was activated then
		     * we have a valid selection otherwise we have
		     * an inactive selection.
		     */
		    if (cur_s->activated) {
			*data = cur_s->data;
			ret_val = XM_SUCCESS;
		    }
		    else {
			ret_val = XM_IA_SELECT;
		    }
		}
		else {
		    /*
		     * No selection was current.
		     */
		    ret_val = XM_NO_SELECT;
		}
		selection = True;
		break;
        case KeyPress:
        case KeyRelease:
                keysym = XLookupKeysym (&event.xkey, 0);

                /* Pop down on C-g and Escape.  */
                if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
                    || keysym == XK_Escape) /* Any escape, ignore modifiers.  */
                  {
                    ret_val = XM_NO_SELECT;
                    selection = True;
                  }
               break;
	    default:
		/*
		 * If AEQ mode is enabled then queue the event.
		 */
		if (menu->aeq) {
		    feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue));
		    if (feq_tmp == NULL) {
			_XMErrorCode = XME_CALLOC;
			return(XM_FAILURE);
		    }
		    feq_tmp->event = event;
		    feq_tmp->next = feq;
		    feq = feq_tmp;
		}
		else if (_XMEventHandler) (*_XMEventHandler)(&event);
	}
	/*
	 * If a selection has been made, break out of the event loop.
	 */
	if (selection == True) break;
    }

    /*
     * Unmap the menu.
     */
    for ( p_ptr = menu->p_list->next;
	 p_ptr != menu->p_list;
	 p_ptr = p_ptr->next)
      {
	  XUnmapWindow(display, p_ptr->window);
      }

    /*
     * Ungrab the mouse.
     */
    XUngrabPointer(display, CurrentTime);
    XUngrabKeyboard(display, CurrentTime);

    /*
     * Restore bits under where the menu was if we managed
     * to save them and free the pixmap.
     */

    /*
     * If there is a current selection deactivate it.
     */
    if (cur_s != NULL) cur_s->activated = 0;

    /*
     * Deactivate the current pane.
     */
    cur_p->activated = 0;
    XSetWindowBackgroundPixmap(display, cur_p->window, menu->inact_pixmap);

    /*
     * Synchronize the X buffers and the X event queue.
     */
    XSync(display, 0);

    /*
     * Dispatch any events remaining on the queue.
     */
    while (QLength(display)) {
	/*
	 * Fetch the next event.
	 */
	XNextEvent(display, &event);

	/*
	 * Discard any events left on the queue that belong to XMenu.
	 * All others are held and then returned to the event queue.
	 */
	switch (event.type) {
	    case Expose:
	    case EnterNotify:
	    case LeaveNotify:
	    case ButtonPress:
	    case ButtonRelease:
		/*
		 * Does this event belong to one of XMenu's windows?
		 * If so, discard it and process the next event.
		 * If not fall through and treat it as a foreign event.
		 */
		event_xmp = (XMPane *)XLookUpAssoc(
						   display,
						   menu->assoc_tab,
						   event.xbutton.window
						   );
		if (event_xmp != NULL) continue;
	    default:
		/*
		 * This is a foreign event.
		 * Queue it for later return to the X event queue.
		 */
		feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue));
		if (feq_tmp == NULL) {
		    _XMErrorCode = XME_CALLOC;
		    return(XM_FAILURE);
		}
		feq_tmp->event = event;
		feq_tmp->next = feq;
		feq = feq_tmp;
	    }
    }
    /*
     * Return any foreign events that were queued to the X event queue.
     */
    while (feq != NULL) {
	feq_tmp = feq;
	XPutBackEvent(display, &feq_tmp->event);
	feq = feq_tmp->next;
	free((char *)feq_tmp);
    }

    wait_func = 0;

    /*
     * Return successfully.
     */
    _XMErrorCode = XME_NO_ERROR;
    return(ret_val);

}

/* arch-tag: 6b90b578-ecea-4328-b460-a0c96963f872
   (do not change this comment) */