Mercurial > emacs
changeset 5673:7035bc81858b
Find lwlib.h and xlwmenuP.h in ../lwlib.
Reshuffle functions; put new ones in #ifdef USE_X_TOOLKIT.
(Fx_popup_menu): Add USE_X_TOOLKIT conditional around new decls.
(string_width): New function.
(event_is_in_menu_item, map_event_to_object): Likewise.
(set_menu_items, free_menu_items, popup_selection_callback): Likewise.
(popup_down_callback, free_menubar_widget_value_tree): Likewise.
(update_one_frame_psheets, set_frame_menubar): Likewise.
(Fx_popup_menu, xmenu_show): Handle USE_X_TOOLKIT.
(dispatch_dummy_expose): New function.
(XMenu_xpos, XMenu_ypos): Change the values of the constant assignment.
(xmenu_show): Change the way to make the menubar to redraw itself by
generating a dummy expose event.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Wed, 26 Jan 1994 07:20:15 +0000 |
parents | cbc4229c1f90 |
children | bb8bfab97970 |
files | src/xmenu.c |
diffstat | 1 files changed, 656 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/src/xmenu.c Wed Jan 26 05:25:06 1994 +0000 +++ b/src/xmenu.c Wed Jan 26 07:20:15 1994 +0000 @@ -24,14 +24,16 @@ * */ -#ifdef XDEBUG +/* Modified by Fred Pierresteguy on December 93 + to make the popup menus and menubar use the Xt. */ + #include <stdio.h> -#endif /* On 4.3 this loses if it comes after xterm.h. */ #include <signal.h> #include <config.h> #include "lisp.h" +#include "termhooks.h" #include "frame.h" #include "window.h" #include "keyboard.h" @@ -55,6 +57,16 @@ #include <X/XMenu.h> #endif +#ifdef USE_X_TOOLKIT +#include <X11/Xlib.h> +#include <X11/IntrinsicP.h> +#include <X11/CoreP.h> +#include <X11/StringDefs.h> +#include <X11/Xaw/Paned.h> +#include "../lwlib/lwlib.h" +#include "../lwlib/xlwmenuP.h" +#endif /* USE_X_TOOLKIT */ + #define min(x,y) (((x) < (y)) ? (x) : (y)) #define max(x,y) (((x) > (y)) ? (x) : (y)) @@ -72,8 +84,17 @@ #endif /* not HAVE_X11 */ extern Lisp_Object Qmenu_enable; +extern Lisp_Object Qmenu_bar; Lisp_Object xmenu_show (); extern int x_error_handler (); +#ifdef USE_X_TOOLKIT +static widget_value *set_menu_items (); +static int string_width (); +static void free_menu_items (); +#endif + +/* we need a unique id for each popup menu and dialog box */ +unsigned int popup_id_tick; /*************************************************************/ @@ -85,6 +106,7 @@ } #endif + DEFUN ("x-popup-menu",Fx_popup_menu, Sx_popup_menu, 1, 2, 0, "Pop up a deck-of-cards menu and return user's selection.\n\ POSITION is a position specification. This is either a mouse button event\n\ @@ -113,7 +135,7 @@ (position, menu) Lisp_Object position, menu; { - int number_of_panes; + int number_of_panes, panes; Lisp_Object XMenu_return, keymap, tem; int XMenu_xpos, XMenu_ypos; char **menus; @@ -125,9 +147,12 @@ char *title; char *error_name; Lisp_Object ltitle, selection; - int i, j; + int i, j, menubarp = 0; FRAME_PTR f; Lisp_Object x, y, window; +#ifdef USE_X_TOOLKIT + widget_value *val, *vw = 0; +#endif /* USE_X_TOOLKIT */ /* Decode the first argument: find the window and the coordinates. */ tem = Fcar (position); @@ -151,7 +176,7 @@ if (XTYPE (window) == Lisp_Frame) { f = XFRAME (window); - + XMenu_xpos = 0; XMenu_ypos = 0; } @@ -159,15 +184,78 @@ { CHECK_LIVE_WINDOW (window, 0); f = XFRAME (WINDOW_FRAME (XWINDOW (window))); - - XMenu_xpos = FONT_WIDTH (f->display.x->font) * XWINDOW (window)->left; - XMenu_ypos = FONT_HEIGHT (f->display.x->font) * XWINDOW (window)->top; + + XMenu_xpos = FONT_WIDTH (f->display.x->font) + * XWINDOW (window)->left; + XMenu_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); +#ifdef USE_X_TOOLKIT + tem = Fcar (Fcdr (Fcar (Fcdr (position)))); + if (XTYPE (Fcar (position)) != Lisp_Cons + && CONSP (tem) + && EQ (Fcar (tem), Qmenu_bar)) + { + /* We are in the menubar */ + XlwMenuWidget mw; + int w1 = 0, w2; + + mw = (XlwMenuWidget)f->display.x->menubar_widget; + menubarp = 1; + for (vw = mw->menu.old_stack [0]->contents; vw; vw = vw->next) + { + w2 = w1; + w1 += string_width (mw, vw->name) + + 2 * (mw->menu.horizontal_spacing + + mw->menu.shadow_thickness); + if (XINT (x) < w1) + { + XMenu_xpos = w2 + 4; + XMenu_ypos = 0; + break; + } + } + } + else + { + XMenu_xpos += FONT_WIDTH (f->display.x->font) * XINT (x); + XMenu_ypos += FONT_HEIGHT (f->display.x->font) * XINT (y); + } + + BLOCK_INPUT; + XMenu_xpos += (f->display.x->widget->core.x + + f->display.x->widget->core.border_width); + XMenu_ypos += (f->display.x->widget->core.y + + f->display.x->widget->core.border_width + + f->display.x->menubar_widget->core.height); + UNBLOCK_INPUT; + + val = set_menu_items (menu, &prefixes, &panes, &names, + &enables, &menus, &items, &number_of_panes, &obj_list, + &title, &error_name); + selection = xmenu_show (f, val, XMenu_xpos, XMenu_ypos, + menubarp, vw); + + free_menu_items (names, enables, menus, items, number_of_panes, obj_list, + title, error_name); + + if (selection != NUL) + { /* selected something */ + XMenu_return = selection; + } + else + { /* nothing selected */ + XMenu_return = Qnil; + } + + return XMenu_return; + +#else /* not USE_X_TOOLKIT */ #ifdef HAVE_X11 { Window child; @@ -194,7 +282,7 @@ XMenu_ypos += win_y; } } -#endif +#endif /* HAVE_X11 */ XMenu_xpos += FONT_WIDTH (f->display.x->font) * XINT (x); XMenu_ypos += FONT_HEIGHT (f->display.x->font) * XINT (y); @@ -202,6 +290,7 @@ XMenu_xpos += f->display.x->left_pos; XMenu_ypos += f->display.x->top_pos; + keymap = Fkeymapp (menu); tem = Qnil; if (XTYPE (menu) == Lisp_Cons) @@ -275,6 +364,7 @@ fprintf (stderr, " Item %d %s\n", j, names[i][j]); } #endif + BLOCK_INPUT; { Window root; @@ -296,7 +386,6 @@ &dummy_window)) /* But XGetGeometry said root was the root window of f's screen! */ abort (); - selection = xmenu_show (root, XMenu_xpos, XMenu_ypos, names, enables, menus, prefixes, items, number_of_panes, obj_list, title, &error_name); @@ -326,14 +415,566 @@ /* free (title); */ if (error_name) error (error_name); return XMenu_return; +#endif /* not USE_X_TOOLKIT */ +} + +#ifdef USE_X_TOOLKIT + +static void +dispatch_dummy_expose (w, x, y) + Widget w; + int x; + int y; +{ + XExposeEvent dummy; + + dummy.type = Expose; + dummy.window = XtWindow (w); + dummy.count = 0; + dummy.serial = 0; + dummy.send_event = 0; + dummy.display = XtDisplay (w); + dummy.x = x; + dummy.y = y; + + XtDispatchEvent (&dummy); +} + +static int +string_width (mw, s) + XlwMenuWidget mw; + char* s; +{ + XCharStruct xcs; + int drop; + + XTextExtents (mw->menu.font, s, strlen (s), &drop, &drop, &drop, &xcs); + return xcs.width; +} + +static int +event_is_in_menu_item (mw, event, name, string_w) + XlwMenuWidget mw; + struct input_event *event; + char *name; + int *string_w; +{ + *string_w += string_width (mw, name) + + 2 * (mw->menu.horizontal_spacing + mw->menu.shadow_thickness); + return (XINT (event->x) < *string_w); +} + + +Lisp_Object +map_event_to_object (event, f) + struct input_event *event; + FRAME_PTR f; +{ + int i,j, string_w; + window_state* ws; + XlwMenuWidget mw = (XlwMenuWidget) f->display.x->menubar_widget; + widget_value *val; + + + string_w = 0; + /* Find the window */ + for (val = mw->menu.old_stack [0]->contents; val; val = val->next) + { + ws = &mw->menu.windows [0]; + if (ws && event_is_in_menu_item (mw, event, val->name, &string_w)) + { + Lisp_Object items; + items = FRAME_MENU_BAR_ITEMS (f); + for (; CONSP (items); items = XCONS (items)->cdr) + if (!strcmp (val->name, + XSTRING (Fcar (Fcdr (Fcar (items))))->data)) + return items; + } + } + return Qnil; } +static widget_value * +set_menu_items (menu, prefixes, panes, names, enables, menus, + items, number_of_panes, obj_list, title, error_name) + Lisp_Object menu; + Lisp_Object **prefixes; + int *panes; + char ***names[]; + int ***enables; + char ***menus; + int **items; + int *number_of_panes; + Lisp_Object ***obj_list; + char **title; + char **error_name; +{ + Lisp_Object keymap, tem; + Lisp_Object ltitle, selection; + int i, j; + widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; + int last, selidx, lpane, status; + int lines, sofar; + + keymap = Fkeymapp (menu); + tem = Qnil; + + if (XTYPE (menu) == Lisp_Cons) + tem = Fkeymapp (Fcar (menu)); + if (!NILP (keymap)) + { + /* We were given a keymap. Extract menu info from the keymap. */ + Lisp_Object prompt; + keymap = get_keymap (menu); + + /* Search for a string appearing directly as an element of the keymap. + That string is the title of the menu. */ + prompt = map_prompt (keymap); + if (!NILP (prompt)) + *title = (char *) XSTRING (prompt)->data; + + /* Extract the detailed info to make one pane. */ + *number_of_panes = keymap_panes (obj_list, menus, names, enables, + items, prefixes, menu, 1); + /* The menu title seems to be ignored, + so put it in the pane title. */ + if ((*menus)[0] == 0) + (*menus)[0] = *title; + } + else if (!NILP (tem)) + { + /* We were given a list of keymaps. */ + Lisp_Object prompt; + int nmaps = XFASTINT (Flength (menu)); + Lisp_Object *maps + = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object)); + int i; + *title = 0; + + /* The first keymap that has a prompt string + supplies the menu title. */ + for (tem = menu, i = 0; XTYPE (tem) == Lisp_Cons; tem = Fcdr (tem)) + { + maps[i++] = keymap = get_keymap (Fcar (tem)); + + prompt = map_prompt (keymap); + if (*title == 0 && !NILP (prompt)) + *title = (char *) XSTRING (prompt)->data; + } + + /* Extract the detailed info to make one pane. */ + *number_of_panes = keymap_panes (obj_list, menus, names, enables, + items, prefixes, maps, nmaps); + /* The menu title seems to be ignored, + so put it in the pane title. */ + if ((*menus)[0] == 0) + (*menus)[0] = *title; + } + else + { + /* We were given an old-fashioned menu. */ + ltitle = Fcar (menu); + CHECK_STRING (ltitle, 1); + *title = (char *) XSTRING (ltitle)->data; + *prefixes = 0; + *number_of_panes = list_of_panes (obj_list, menus, names, enables, + items, Fcdr (menu)); + } + + *error_name = 0; + if (*number_of_panes == 0) + return 0; + + *error_name = (char *) 0; /* Initialize error pointer to null */ + + wv = malloc_widget_value (); + wv->name = "menu"; + wv->value = 0; + wv->enabled = 1; + first_wv = wv; + + for (*panes = 0, lines = 0; *panes < *number_of_panes; + lines += (*items)[*panes], (*panes)++) + ; + /* datap = (struct indices *) xmalloc (lines * sizeof (struct indices)); */ + /* datap = (char *) xmalloc (lines * sizeof (char)); + datap_save = datap;*/ + + for (*panes = 0, sofar = 0; *panes < *number_of_panes; + sofar += (*items)[*panes], (*panes)++) + { + if (strcmp((*menus)[*panes], "")) + { + wv = malloc_widget_value (); + if (save_wv) + save_wv->next = wv; + else + first_wv->contents = wv; + wv->name = (*menus)[*panes]; + wv->value = 0; + wv->enabled = 1; + } + prev_wv = 0; + save_wv = wv; + + for (selidx = 0; selidx < (*items)[*panes]; selidx++) + { + wv = malloc_widget_value (); + if (prev_wv) + prev_wv->next = wv; + else + save_wv->contents = wv; + wv->name = (*names)[*panes][selidx]; + wv->value = 0; + selection = (*obj_list)[*panes][selidx]; + if (*prefixes != 0) + { + selection = Fcons (selection, Qnil); + if (!NILP ((*prefixes)[*panes])) + selection = Fcons ((*prefixes)[*panes], selection); + } + wv->call_data = LISP_TO_VOID(selection); + wv->enabled = (*enables)[*panes][selidx]; + prev_wv = wv; + } + } + + return (first_wv); +} + +static void +free_menu_items (names, enables, menus, items, number_of_panes, + obj_list, title, error_name) + char **names[]; + int *enables[]; + char **menus; + int *items; + int number_of_panes; + Lisp_Object **obj_list; + char *title; + char *error_name; +{ + int i; + /* now free up the strings */ + for (i = 0; i < number_of_panes; i++) + { + xfree (names[i]); + xfree (enables[i]); + xfree (obj_list[i]); + } + xfree (menus); + xfree (obj_list); + xfree (names); + xfree (enables); + xfree (items); + /* free (title); */ + if (error_name) error (error_name); + +} + +static Lisp_Object menu_item_selection; + +static void +popup_selection_callback (widget, id, client_data) + Widget widget; + LWLIB_ID id; + XtPointer client_data; +{ +#if 0 + last_popup_selection_callback_id = id; + menubar_selection_callback (widget, id, client_data); + /* lw_destroy_all_widgets() will be called from popup_down_callback() */ +#endif + VOID_TO_LISP (menu_item_selection, client_data); +} + +static void +popup_down_callback (widget, id, client_data) + Widget widget; + LWLIB_ID id; + XtPointer client_data; +{ +#if 0 + if (popup_menu_up_p == 0) abort (); + popup_menu_up_p--; + /* if this isn't called immediately after the selection callback, then + there wasn't a menu selection. */ + if (id != last_popup_selection_callback_id) + menubar_selection_callback (widget, id, (XtPointer) -1); +#endif + BLOCK_INPUT; + lw_destroy_all_widgets (id); + UNBLOCK_INPUT; +/* ungcpro_popup_callbacks (make_number (id)); */ +} + +/* This recursively calls free_widget_value() on the tree of widgets. + It must free all data that was malloc'ed for these widget_values. + Currently, emacs only allocates new storage for the `key' slot. + All other slots are pointers into the data of Lisp_Strings, and + must be left alone. + */ +void +free_menubar_widget_value_tree (wv) + widget_value *wv; +{ + if (! wv) return; + if (wv->key) xfree (wv->key); + + wv->name = wv->value = wv->key = (char *) 0xDEADBEEF; + + if (wv->contents && (wv->contents != (widget_value*)1)) + { + free_menubar_widget_value_tree (wv->contents); + wv->contents = (widget_value *) 0xDEADBEEF; + } + if (wv->next) + { + free_menubar_widget_value_tree (wv->next); + wv->next = (widget_value *) 0xDEADBEEF; + } + BLOCK_INPUT; + free_widget_value (wv); + UNBLOCK_INPUT; +} + +static void +update_one_frame_psheets (f) + FRAME_PTR f; +{ + struct x_display *x = f->display.x; + + int menubar_changed; + + menubar_changed = (x->menubar_widget + && !XtIsManaged (x->menubar_widget)); + + if (! (menubar_changed)) + return; + + BLOCK_INPUT; + XawPanedSetRefigureMode (x->column_widget, 0); + + /* the order in which children are managed is the top to + bottom order in which they are displayed in the paned window. + First, remove the text-area widget. + */ + XtUnmanageChild (x->edit_widget); + + /* remove the menubar that is there now, and put up the menubar that + should be there. + */ + if (menubar_changed) + { + XtManageChild (x->menubar_widget); + XtMapWidget (x->menubar_widget); + XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, 0); + } + + + /* Re-manage the text-area widget */ + XtManageChild (x->edit_widget); + + /* and now thrash the sizes */ + XawPanedSetRefigureMode (x->column_widget, 1); + UNBLOCK_INPUT; +} + +void +set_frame_menubar (f) + FRAME_PTR f; +{ + Widget menubar_widget = f->display.x->menubar_widget; + int id = (int) f; + Lisp_Object tail; + widget_value *wv, *save_wv, *first_wv, *prev_wv = 0; + + BLOCK_INPUT; + + wv = malloc_widget_value (); + wv->name = "menubar"; + wv->value = 0; + wv->enabled = 1; + save_wv = first_wv = wv; + + + for (tail = FRAME_MENU_BAR_ITEMS (f); CONSP (tail); tail = XCONS (tail)->cdr) + { + Lisp_Object string; + + string = Fcar (Fcdr (Fcar (tail))); + + wv = malloc_widget_value (); + if (prev_wv) + prev_wv->next = wv; + else + save_wv->contents = wv; + wv->name = XSTRING (string)->data; + wv->value = 0; + wv->enabled = 1; + prev_wv = wv; + } + + if (menubar_widget) + lw_modify_all_widgets (id, first_wv, False); + else + { + menubar_widget = lw_create_widget ("menubar", "menubar", + id, first_wv, + f->display.x->column_widget, + 0, 0, + 0, 0); + f->display.x->menubar_widget = menubar_widget; + XtVaSetValues (menubar_widget, + XtNshowGrip, 0, + XtNresizeToPreferred, 1, + XtNallowResize, 1, + 0); + } + + free_menubar_widget_value_tree (first_wv); + + update_one_frame_psheets (f); + + UNBLOCK_INPUT; +} +#endif /* USE_X_TOOLKIT */ + struct indices { int pane; int line; }; +extern void process_expose_from_menu (); + +#ifdef USE_X_TOOLKIT +extern XtAppContext Xt_app_con; + Lisp_Object +xmenu_show (f, val, x, y, menubarp, vw) + FRAME_PTR f; + widget_value *val; + int x; + int y; + int menubarp; + widget_value *vw; +{ + int menu_id, id = (int)f; + Lisp_Object selection; + Widget menu; + + /* + * 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. */ + + BLOCK_INPUT; + menu_id = ++popup_id_tick; + menu = lw_create_widget ("popup", val->name, menu_id, val, + f->display.x->widget, 1, 0, + popup_selection_callback, popup_down_callback); + free_menubar_widget_value_tree (val); + + /* reset the selection */ + menu_item_selection = Qnil; + + { + XButtonPressedEvent dummy; + XlwMenuWidget mw; + + mw = ((XlwMenuWidget) + ((CompositeWidget)menu)->composite.children[0]); + + dummy.type = ButtonPress; + dummy.serial = 0; + dummy.send_event = 0; + dummy.display = XtDisplay (menu); + dummy.window = XtWindow (XtParent (menu)); + dummy.time = CurrentTime; + dummy.button = 0; + dummy.x_root = x; + dummy.y_root = y; + + if (menubarp) + { +#if 0 + /* we are in the menubar */ + XtUnmapWidget (f->display.x->menubar_widget); + vw->call_data = (XtPointer) 1; + XtMapWidget (f->display.x->menubar_widget); +#else + vw->call_data = (XtPointer) 1; + dispatch_dummy_expose (f->display.x->menubar_widget, x, y); +#endif + } + + + /* We activate directly the lucid implementation */ + pop_up_menu (mw, &dummy); + } + + /* Enters XEvent loop */ + 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); + feq_tmp = (XMEventQue *) malloc (sizeof (XMEventQue)); + + if (feq_tmp == NULL) + return(Qnil); + + feq_tmp->event = event; + feq_tmp->next = feq; + feq = feq_tmp; + } + + if (menubarp) + { +#if 1 + XtUnmapWidget (f->display.x->menubar_widget); + vw->call_data = (XtPointer) 0; + XtMapWidget (f->display.x->menubar_widget); +#else + vw->call_data = (XtPointer) 0; + dispatch_dummy_expose (f->display.x->menubar_widget, 0, 0); + XFlushQueue (); +#endif + } + + /* Return any foreign events that were queued to the X event queue. */ + while (feq != NULL) + { + feq_tmp = feq; + XPutBackEvent (XDISPLAY &feq_tmp->event); + feq = feq_tmp->next; + free ((char *)feq_tmp); + } + + UNBLOCK_INPUT; + + return menu_item_selection; +} + +#else /* not USE_X_TOOLKIT */ xmenu_show (parent, startx, starty, line_list, enable_list, pane_list, prefixes, line_cnt, pane_cnt, item_list, title, error) Window parent; @@ -363,6 +1004,7 @@ BLOCK_INPUT; *error = (char *) 0; /* Initialize error pointer to null */ + GXMenu = XMenuCreate (XDISPLAY parent, "emacs"); if (GXMenu == NUL) { @@ -370,7 +1012,7 @@ UNBLOCK_INPUT; return (0); } - + for (panes = 0, lines = 0; panes < pane_cnt; lines += line_cnt[panes], panes++) ; @@ -390,6 +1032,7 @@ UNBLOCK_INPUT; return (0); } + for (selidx = 0; selidx < line_cnt[panes]; selidx++) { /* add the selection stuff to the menus */ @@ -466,9 +1109,11 @@ /* free (datap_save);*/ return (entry); } +#endif /* not USE_X_TOOLKIT */ syms_of_xmenu () { + popup_id_tick = (1<<16); defsubr (&Sx_popup_menu); }