mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-02-05 20:43:08 +00:00
(xdialog_show): New function to handle the display of dialog boxes.
(Fx_popup_dialog): New function. (dialog_selection_callback): New function. (xmenu_show) [USE_X_TOOLKIT]: Don't call lw_destroy_all_widgets at the end. Do the work of construct_mouse_click in the ButtonRelease case.
This commit is contained in:
parent
ce5a08a1b4
commit
165e1749b2
337
src/xmenu.c
337
src/xmenu.c
@ -94,6 +94,7 @@ extern void process_expose_from_menu ();
|
||||
extern XtAppContext Xt_app_con;
|
||||
|
||||
static int string_width ();
|
||||
static Lisp_Object xdialog_show ();
|
||||
#endif
|
||||
|
||||
static Lisp_Object xmenu_show ();
|
||||
@ -826,6 +827,133 @@ cached information about equivalent key sequences.")
|
||||
if (error_name) error (error_name);
|
||||
return selection;
|
||||
}
|
||||
|
||||
DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 1, 2, 0,
|
||||
"Pop up a dialog box and return user's selection.\n\
|
||||
POSITION is a position specification. This is either a mouse button event\n\
|
||||
or a list ((XOFFSET YOFFSET) WINDOW)\n\
|
||||
where XOFFSET and YOFFSET are positions in characters from the top left\n\
|
||||
corner of WINDOW's frame. (WINDOW may be a frame object instead of a window.)\n\
|
||||
This controls the position of the center of the first line\n\
|
||||
in the first pane of the menu, not the top left of the menu as a whole.\n\
|
||||
If POSITION is t, it means to use the current mouse position.\n\
|
||||
\n\
|
||||
MENU is a specifier for a menu. For the simplest case, MENU is a keymap.\n\
|
||||
The menu items come from key bindings that have a menu string as well as\n\
|
||||
a definition; actually, the \"definition\" in such a key binding looks like\n\
|
||||
\(STRING . REAL-DEFINITION). To give the menu a title, put a string into\n\
|
||||
the keymap as a top-level element.\n\n\
|
||||
You can also use a list of keymaps as MENU.\n\
|
||||
Then each keymap makes a separate pane.\n\
|
||||
When MENU is a keymap or a list of keymaps, the return value\n\
|
||||
is a list of events.\n\n\
|
||||
Alternatively, you can specify a menu of multiple panes\n\
|
||||
with a list of the form (TITLE PANE1 PANE2...),\n\
|
||||
where each pane is a list of form (TITLE ITEM1 ITEM2...).\n\
|
||||
Each ITEM is normally a cons cell (STRING . VALUE);\n\
|
||||
but a string can appear as an item--that makes a nonselectable line\n\
|
||||
in the menu.\n\
|
||||
With this form of menu, the return value is VALUE from the chosen item.\n\
|
||||
\n\
|
||||
If POSITION is nil, don't display the menu at all, just precalculate the\n\
|
||||
cached information about equivalent key sequences.")
|
||||
(position, menu)
|
||||
Lisp_Object position, menu;
|
||||
{
|
||||
int number_of_panes, panes;
|
||||
Lisp_Object keymap, tem;
|
||||
int xpos, ypos;
|
||||
Lisp_Object title;
|
||||
char *error_name;
|
||||
Lisp_Object selection;
|
||||
int i, j;
|
||||
FRAME_PTR f;
|
||||
Lisp_Object x, y, window;
|
||||
int keymaps = 0;
|
||||
int menubarp = 0;
|
||||
struct gcpro gcpro1;
|
||||
|
||||
check_x ();
|
||||
|
||||
if (! NILP (position))
|
||||
{
|
||||
/* Decode the first argument: find the window and the coordinates. */
|
||||
if (EQ (position, Qt))
|
||||
{
|
||||
/* Use the mouse's current position. */
|
||||
FRAME_PTR new_f;
|
||||
Lisp_Object bar_window;
|
||||
int part;
|
||||
unsigned long time;
|
||||
|
||||
(*mouse_position_hook) (&new_f, &bar_window, &part, &x, &y, &time);
|
||||
XSET (window, Lisp_Frame, new_f);
|
||||
}
|
||||
|
||||
CHECK_NUMBER (x, 0);
|
||||
CHECK_NUMBER (y, 0);
|
||||
|
||||
/* Decode where to put the menu. */
|
||||
|
||||
if (XTYPE (window) == Lisp_Frame)
|
||||
{
|
||||
f = XFRAME (window);
|
||||
|
||||
xpos = 0;
|
||||
ypos = 0;
|
||||
}
|
||||
else if (XTYPE (window) == Lisp_Window)
|
||||
{
|
||||
CHECK_LIVE_WINDOW (window, 0);
|
||||
f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
|
||||
|
||||
xpos = (FONT_WIDTH (f->display.x->font) * XWINDOW (window)->left);
|
||||
ypos = (FONT_HEIGHT (f->display.x->font) * XWINDOW (window)->top);
|
||||
}
|
||||
else
|
||||
/* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
|
||||
but I don't want to make one now. */
|
||||
CHECK_WINDOW (window, 0);
|
||||
|
||||
xpos += XINT (x);
|
||||
ypos += XINT (y);
|
||||
}
|
||||
|
||||
title = Qnil;
|
||||
GCPRO1 (title);
|
||||
|
||||
/* Decode the dialog items from what was specified. */
|
||||
{
|
||||
/* We were given an old-fashioned menu. */
|
||||
title = Fcar (menu);
|
||||
CHECK_STRING (title, 1);
|
||||
|
||||
list_of_panes (Fcdr (menu));
|
||||
|
||||
keymaps = 0;
|
||||
}
|
||||
|
||||
if (NILP (position))
|
||||
{
|
||||
discard_menu_items ();
|
||||
UNGCPRO;
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/* Display them in a dialog box. */
|
||||
BLOCK_INPUT;
|
||||
|
||||
selection = xdialog_show (f, xpos, ypos, menubarp,
|
||||
keymaps, title, &error_name);
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
discard_menu_items ();
|
||||
|
||||
UNGCPRO;
|
||||
|
||||
if (error_name) error (error_name);
|
||||
return selection;
|
||||
}
|
||||
|
||||
#ifdef USE_X_TOOLKIT
|
||||
|
||||
@ -939,6 +1067,19 @@ popup_down_callback (widget, id, client_data)
|
||||
UNBLOCK_INPUT;
|
||||
}
|
||||
|
||||
static void
|
||||
dialog_selection_callback (widget, id, client_data)
|
||||
Widget widget;
|
||||
LWLIB_ID id;
|
||||
XtPointer client_data;
|
||||
{
|
||||
if ((int)client_data != -1)
|
||||
menu_item_selection = (Lisp_Object *) client_data;
|
||||
BLOCK_INPUT;
|
||||
lw_destroy_all_widgets (id);
|
||||
UNBLOCK_INPUT;
|
||||
}
|
||||
|
||||
/* This recursively calls free_widget_value() on the tree of widgets.
|
||||
It must free all data that was malloc'ed for these widget_values.
|
||||
In Emacs, many slots are pointers into the data of Lisp_Strings, and
|
||||
@ -1186,6 +1327,9 @@ check_mouse_other_menu_bar (f)
|
||||
|
||||
#ifdef USE_X_TOOLKIT
|
||||
|
||||
extern unsigned int x_mouse_grabbed;
|
||||
extern Lisp_Object Vmouse_depressed;
|
||||
|
||||
static Lisp_Object
|
||||
xmenu_show (f, x, y, menubarp, keymaps, title, error)
|
||||
FRAME_PTR f;
|
||||
@ -1426,6 +1570,16 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
|
||||
if (event.type == ButtonRelease)
|
||||
{
|
||||
XtDispatchEvent (&event);
|
||||
if (! menubarp)
|
||||
{
|
||||
/* Do the work of construct_mouse_click since it can't
|
||||
be called. Initially, the popup menu has been called
|
||||
from a ButtonPress in the edit_widget. Then the mouse
|
||||
has been set to grabbed. Reset it now. */
|
||||
x_mouse_grabbed &= ~(1 << event.xbutton.button);
|
||||
if (!x_mouse_grabbed)
|
||||
Vmouse_depressed = Qnil;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (event.type == Expose)
|
||||
@ -1481,8 +1635,10 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
|
||||
dispatch_dummy_expose (f->display.x->menubar_widget, x, y);
|
||||
}
|
||||
|
||||
#if 0 /* No need to do that. The menu has disappeared. */
|
||||
/* Make sure the menu disappears. */
|
||||
lw_destroy_all_widgets (menu_id);
|
||||
#endif
|
||||
|
||||
/* Unread any events that we got but did not handle. */
|
||||
while (queue != NULL)
|
||||
@ -1548,6 +1704,186 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static char * button_names [] = {
|
||||
"button1", "button2", "button3", "button4", "button5",
|
||||
"button6", "button7", "button8", "button9", "button10" };
|
||||
|
||||
static Lisp_Object
|
||||
xdialog_show (f, x, y, menubarp, keymaps, title, error)
|
||||
FRAME_PTR f;
|
||||
int x;
|
||||
int y;
|
||||
int menubarp;
|
||||
int keymaps;
|
||||
Lisp_Object title;
|
||||
char **error;
|
||||
{
|
||||
int i, nb_buttons=0;
|
||||
int dialog_id;
|
||||
Widget menu;
|
||||
XlwMenuWidget menubar = (XlwMenuWidget) f->display.x->menubar_widget;
|
||||
|
||||
/* This is the menu bar item (if any) that led to this menu. */
|
||||
widget_value *menubar_item = 0;
|
||||
|
||||
widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
|
||||
|
||||
/* Define a queue to save up for later unreading
|
||||
all X events that don't pertain to the menu. */
|
||||
struct event_queue
|
||||
{
|
||||
XEvent event;
|
||||
struct event_queue *next;
|
||||
};
|
||||
|
||||
struct event_queue *queue = NULL;
|
||||
struct event_queue *queue_tmp;
|
||||
|
||||
*error = NULL;
|
||||
|
||||
/* Create a tree of widget_value objects
|
||||
representing the text label and buttons. */
|
||||
{
|
||||
Lisp_Object pane_name, prefix;
|
||||
char *pane_string;
|
||||
pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
|
||||
prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
|
||||
pane_string = (NILP (pane_name)
|
||||
? "" : (char *) XSTRING (pane_name)->data);
|
||||
prev_wv = malloc_widget_value ();
|
||||
prev_wv->value = pane_string;
|
||||
if (keymaps && !NILP (prefix))
|
||||
prev_wv->name++;
|
||||
prev_wv->enabled = 1;
|
||||
prev_wv->name = "message";
|
||||
first_wv = prev_wv;
|
||||
|
||||
/* Loop over all panes and items, filling in the tree. */
|
||||
i = MENU_ITEMS_PANE_LENGTH;
|
||||
while (i < menu_items_used)
|
||||
{
|
||||
|
||||
/* Create a new item within current pane. */
|
||||
Lisp_Object item_name, enable, descrip;
|
||||
item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
|
||||
enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
|
||||
descrip
|
||||
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
|
||||
|
||||
wv = malloc_widget_value ();
|
||||
prev_wv->next = wv;
|
||||
wv->name = (char *) button_names [nb_buttons];
|
||||
if (!NILP (descrip))
|
||||
wv->key = XSTRING (descrip)->data;
|
||||
wv->value = XSTRING (item_name)->data;
|
||||
wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
|
||||
wv->enabled = !NILP (enable);
|
||||
prev_wv = wv;
|
||||
|
||||
nb_buttons++;
|
||||
i += MENU_ITEMS_ITEM_LENGTH;
|
||||
}
|
||||
|
||||
wv = malloc_widget_value ();
|
||||
wv->name = "Q2BR1";
|
||||
wv->contents = first_wv;
|
||||
first_wv = wv;
|
||||
|
||||
}
|
||||
|
||||
/* Actually create the dialog. */
|
||||
dialog_id = ++popup_id_tick;
|
||||
menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
|
||||
f->display.x->widget, 1, 0,
|
||||
dialog_selection_callback, 0);
|
||||
lw_modify_all_widgets (dialog_id, first_wv, True);
|
||||
lw_modify_all_widgets (dialog_id, first_wv->contents, True);
|
||||
/* Free the widget_value objects we used to specify the contents. */
|
||||
free_menubar_widget_value_tree (first_wv);
|
||||
|
||||
/* No selection has been chosen yet. */
|
||||
menu_item_selection = 0;
|
||||
|
||||
|
||||
/* Display the menu. */
|
||||
lw_pop_up_all_widgets (dialog_id);
|
||||
|
||||
/* Process events that apply to the menu. */
|
||||
while (1)
|
||||
{
|
||||
XEvent event;
|
||||
|
||||
XtAppNextEvent (Xt_app_con, &event);
|
||||
if (event.type == ButtonRelease)
|
||||
{
|
||||
XtDispatchEvent (&event);
|
||||
break;
|
||||
}
|
||||
else if (event.type == Expose)
|
||||
process_expose_from_menu (event);
|
||||
XtDispatchEvent (&event);
|
||||
if (XtWindowToWidget(XDISPLAY event.xany.window) != menu)
|
||||
{
|
||||
queue_tmp = (struct event_queue *) malloc (sizeof (struct event_queue));
|
||||
|
||||
if (queue_tmp != NULL)
|
||||
{
|
||||
queue_tmp->event = event;
|
||||
queue_tmp->next = queue;
|
||||
queue = queue_tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
pop_down:
|
||||
|
||||
/* Unread any events that we got but did not handle. */
|
||||
while (queue != NULL)
|
||||
{
|
||||
queue_tmp = queue;
|
||||
XPutBackEvent (XDISPLAY &queue_tmp->event);
|
||||
queue = queue_tmp->next;
|
||||
free ((char *)queue_tmp);
|
||||
}
|
||||
|
||||
/* Find the selected item, and its pane, to return
|
||||
the proper value. */
|
||||
if (menu_item_selection != 0)
|
||||
{
|
||||
Lisp_Object prefix;
|
||||
|
||||
prefix = Qnil;
|
||||
i = 0;
|
||||
while (i < menu_items_used)
|
||||
{
|
||||
Lisp_Object entry;
|
||||
|
||||
if (EQ (XVECTOR (menu_items)->contents[i], Qt))
|
||||
{
|
||||
prefix
|
||||
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
|
||||
i += MENU_ITEMS_PANE_LENGTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry
|
||||
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
|
||||
if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
|
||||
{
|
||||
if (keymaps != 0)
|
||||
{
|
||||
entry = Fcons (entry, Qnil);
|
||||
if (!NILP (prefix))
|
||||
entry = Fcons (prefix, entry);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
i += MENU_ITEMS_ITEM_LENGTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
#else /* not USE_X_TOOLKIT */
|
||||
|
||||
static Lisp_Object
|
||||
@ -1761,4 +2097,5 @@ syms_of_xmenu ()
|
||||
|
||||
popup_id_tick = (1<<16);
|
||||
defsubr (&Sx_popup_menu);
|
||||
defsubr (&Sx_popup_dialog);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user