From 165e1749b20e7caf149c725db3737a275c3d3170 Mon Sep 17 00:00:00 2001 From: Fred Pierresteguy Date: Fri, 11 Mar 1994 18:01:00 +0000 Subject: [PATCH] (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. --- src/xmenu.c | 337 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 337 insertions(+) diff --git a/src/xmenu.c b/src/xmenu.c index eb9122b2d0..43811e751b 100644 --- a/src/xmenu.c +++ b/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); } -- 2.20.1