From 244c93fe5767497dd45bb3d3ad22a9c72ccc2d5b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jan=20Dj=C3=A4rv?= Date: Mon, 12 Jan 2004 01:45:22 +0000 Subject: [PATCH] Changes for lucid popup menus (keyboard traversal enabled) and dialogs (Xaw and Xm pop down on ESC). --- lwlib/ChangeLog | 28 ++++++++++++ lwlib/lwlib-Xaw.c | 17 ++++++-- lwlib/lwlib-Xlw.c | 31 +++++++------ lwlib/lwlib-Xm.c | 33 ++++++++++++++ lwlib/xlwmenu.c | 109 +++++++++++++++++++++++++++++++++------------- lwlib/xlwmenu.h | 3 -- lwlib/xlwmenuP.h | 1 + 7 files changed, 171 insertions(+), 51 deletions(-) diff --git a/lwlib/ChangeLog b/lwlib/ChangeLog index f41b323c04..3b69d95539 100644 --- a/lwlib/ChangeLog +++ b/lwlib/ChangeLog @@ -1,3 +1,31 @@ +2004-01-12 Jan Dj,Ad(Brv + + * xlwmenuP.h (_XlwMenu_part): Added top_depth. + + * xlwmenu.h: Removed declaration of pop_up_menu + + * xlwmenu.c (Start): Get correct time if time in event is CurrentTime. + (find_first_selectable, find_next_selectable) + (find_prev_selectable): Add parameter skip_no_call_data to skip + over items with no call data (popup menu titles). + (Down, Up): Compare old_depth to top_depth instead of 2. + Pass True to find_*_selectable:s new parameter if this is a popup menu. + (Left, Right): Compare old_depth to top_depth instead of 2. + Pass 0 to find_*_selectable:s new parameter. + (pop_up_menu): Set top_depth to 1 for pop up menus and 2 for + menu bar menus, to enable keyboard traversal of popups. + + * lwlib-Xm.c (dialog_key_cb): New function. + (make_dialog): Add event handlers to dialog_key_cb for key press + so we can pop down on ESC. + + * lwlib-Xlw.c (xlw_popup_menu): Replace call to pop_up_menu with + XtCallActionProc ("start"). Use a full XEvent since "start" copies it. + + * lwlib-Xaw.c (make_dialog): Add override so dialog pops down + on ESC. + (wm_delete_window): If widget isn't a shell, use the parent. + 2003-05-22 Dave Love * xlwmenu.c: Include lisp.h, not ../src/lisp.h. diff --git a/lwlib/lwlib-Xaw.c b/lwlib/lwlib-Xaw.c index 7f37596457..867193c7cc 100644 --- a/lwlib/lwlib-Xaw.c +++ b/lwlib/lwlib-Xaw.c @@ -277,6 +277,9 @@ xaw_pop_instance (instance, up) static char overrideTrans[] = "WM_PROTOCOLS: lwlib_delete_dialog()"; +/* Dialogs pop down on any key press */ +static char dialogOverride[] = + ": lwlib_delete_dialog()"; static void wm_delete_window(); static XtActionsRec xaw_actions [] = { {"lwlib_delete_dialog", wm_delete_window} @@ -333,6 +336,8 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, ra ac = 0; dialog = XtCreateManagedWidget (name, dialogWidgetClass, shell, av, ac); + override = XtParseTranslationTable (dialogOverride); + XtOverrideTranslations (dialog, override); bc = 0; button = 0; @@ -511,8 +516,8 @@ xaw_generic_callback (widget, closure, call_data) } static void -wm_delete_window (shell, closure, call_data) - Widget shell; +wm_delete_window (w, closure, call_data) + Widget w; XtPointer closure; XtPointer call_data; { @@ -520,7 +525,13 @@ wm_delete_window (shell, closure, call_data) Cardinal nkids; int i; Widget *kids = 0; - Widget widget; + Widget widget, shell; + + if (XtIsSubclass (w, dialogWidgetClass)) + shell = XtParent (w); + else + shell = w; + if (! XtIsSubclass (shell, shellWidgetClass)) abort (); XtVaGetValues (shell, XtNnumChildren, &nkids, NULL); diff --git a/lwlib/lwlib-Xlw.c b/lwlib/lwlib-Xlw.c index d0800e0ca0..248e4e8be7 100644 --- a/lwlib/lwlib-Xlw.c +++ b/lwlib/lwlib-Xlw.c @@ -180,6 +180,7 @@ xlw_create_popup_menu (instance) XtAddCallback (widget, XtNselect, pick_hook, (XtPointer)instance); XtAddCallback (widget, XtNhighlightCallback, highlight_hook, (XtPointer)instance); + return popup_shell; } @@ -251,7 +252,6 @@ xlw_popup_menu (widget, event) Widget widget; XEvent *event; { - XButtonPressedEvent dummy; XlwMenuWidget mw; if (!XtIsShell (widget)) @@ -260,21 +260,24 @@ xlw_popup_menu (widget, event) mw = (XlwMenuWidget)((CompositeWidget)widget)->composite.children [0]; if (event) - pop_up_menu (mw, (XButtonPressedEvent*) event); + XtCallActionProc ((Widget) mw, "start", event, NULL, 0); else { - dummy.type = ButtonPress; - dummy.serial = 0; - dummy.send_event = 0; - dummy.display = XtDisplay (widget); - dummy.window = XtWindow (XtParent (widget)); - dummy.time = CurrentTime; - dummy.button = 0; - XQueryPointer (dummy.display, dummy.window, &dummy.root, - &dummy.subwindow, &dummy.x_root, &dummy.y_root, - &dummy.x, &dummy.y, &dummy.state); - - pop_up_menu (mw, &dummy); + XEvent dummy; + XButtonPressedEvent *bd = &dummy.xbutton; + + bd->type = ButtonPress; + bd->serial = 0; + bd->send_event = 0; + bd->display = XtDisplay (widget); + bd->window = XtWindow (XtParent (widget)); + bd->time = CurrentTime; + bd->button = 0; + XQueryPointer (bd->display, bd->window, &bd->root, + &bd->subwindow, &bd->x_root, &bd->y_root, + &bd->x, &bd->y, &bd->state); + + XtCallActionProc ((Widget) mw, "start", &dummy, NULL, 0); } } diff --git a/lwlib/lwlib-Xm.c b/lwlib/lwlib-Xm.c index f63d13c85e..e57fa57f93 100644 --- a/lwlib/lwlib-Xm.c +++ b/lwlib/lwlib-Xm.c @@ -1035,6 +1035,33 @@ activate_button (widget, closure, call_data) /* creation functions */ +/* Called for key press in dialogs. Used to pop down dialog on ESC. */ +static void +dialog_key_cb (widget, closure, event, continue_to_dispatch) + Widget widget; + XtPointer closure; + XEvent *event; + Boolean *continue_to_dispatch; +{ + KeySym sym = 0; + Modifiers modif_ret; + + XtTranslateKeycode (event->xkey.display, event->xkey.keycode, 0, + &modif_ret, &sym); + + if (sym == osfXK_Cancel) + { + Widget w = *((Widget *) closure); + + while (w && ! XtIsShell (w)) + w = XtParent (w); + + if (XtIsShell (w)) XtPopdown (w); + } + + *continue_to_dispatch = TRUE; +} + /* dialogs */ static Widget make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, @@ -1123,6 +1150,8 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, XtSetArg(al[ac], XmNmarginWidth, 10); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; children [n_children] = XmCreatePushButton (row, button_name, al, ac); + XtAddEventHandler (children [n_children], + KeyPressMask, False, dialog_key_cb, result); if (i == 0) { @@ -1149,6 +1178,9 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, XtSetArg(al[ac], XmNmarginWidth, 10); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; children [n_children] = XmCreatePushButton (row, button_name, al, ac); + XtAddEventHandler (children [n_children], + KeyPressMask, False, dialog_key_cb, result); + if (! button) button = children [n_children]; n_children++; } @@ -1491,6 +1523,7 @@ xm_create_dialog (instance) XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback, (XtPointer) instance); + return widget; } diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c index 917181226c..973fc6ec5d 100644 --- a/lwlib/xlwmenu.c +++ b/lwlib/xlwmenu.c @@ -197,6 +197,8 @@ static void Select(); static void Key(); static void Nothing(); static int separator_height __P ((enum menu_separator)); +static void pop_up_menu __P ((XlwMenuWidget, XButtonPressedEvent *)); + static XtActionsRec xlwMenuActionsList [] = @@ -2004,6 +2006,13 @@ Start (w, ev, params, num_params) if (!mw->menu.popped_up) { menu_post_event = *ev; + /* If event is set to CurrentTime, get the last known time stamp. + This is for calculating if (popup) menus should stay up after + a fast click. */ + if (menu_post_event.xbutton.time == CurrentTime) + menu_post_event.xbutton.time + = XtLastTimestampProcessed (XtDisplay (w)); + pop_up_menu (mw, (XButtonPressedEvent*) ev); } else @@ -2044,15 +2053,17 @@ Nothing (w, ev, params, num_params) { } -widget_value * -find_first_selectable (mw, item) +static widget_value * +find_first_selectable (mw, item, skip_no_call_data) XlwMenuWidget mw; widget_value *item; + int skip_no_call_data; { widget_value *current = item; enum menu_separator separator; - while (lw_separator_p (current->name, &separator, 0) || !current->enabled) + while (lw_separator_p (current->name, &separator, 0) || !current->enabled + || (skip_no_call_data && !current->call_data)) if (current->next) current=current->next; else @@ -2061,8 +2072,8 @@ find_first_selectable (mw, item) return current; } -widget_value * -find_next_selectable (mw, item) +static widget_value * +find_next_selectable (mw, item, skip_no_call_data) XlwMenuWidget mw; widget_value *item; { @@ -2070,7 +2081,8 @@ find_next_selectable (mw, item) enum menu_separator separator; while (current->next && (current=current->next) && - (lw_separator_p (current->name, &separator, 0) || !current->enabled)) + (lw_separator_p (current->name, &separator, 0) || !current->enabled + || (skip_no_call_data && !current->call_data))) ; if (current == item) @@ -2079,7 +2091,9 @@ find_next_selectable (mw, item) return current; current = mw->menu.old_stack [mw->menu.old_depth - 2]->contents; - while (lw_separator_p (current->name, &separator, 0) || !current->enabled) + while (lw_separator_p (current->name, &separator, 0) + || !current->enabled + || (skip_no_call_data && !current->call_data)) { if (current->next) current=current->next; @@ -2093,15 +2107,16 @@ find_next_selectable (mw, item) return current; } -widget_value * -find_prev_selectable (mw, item) +static widget_value * +find_prev_selectable (mw, item, skip_no_call_data) XlwMenuWidget mw; widget_value *item; { widget_value *current = item; widget_value *prev = item; - while ((current=find_next_selectable (mw, current)) != item) + while ((current=find_next_selectable (mw, current, skip_no_call_data)) + != item) { if (prev == current) break; @@ -2120,15 +2135,23 @@ Down (w, ev, params, num_params) { XlwMenuWidget mw = (XlwMenuWidget) w; widget_value* selected_item = mw->menu.old_stack [mw->menu.old_depth - 1]; + int popup_menu_p = mw->menu.top_depth == 1; /* Inside top-level menu-bar? */ - if (mw->menu.old_depth == 2) + if (mw->menu.old_depth == mw->menu.top_depth) /* When in the menu-bar is pressed, display the corresponding - sub-menu and select the first selectable menu item there. */ - set_new_state (mw, find_first_selectable (mw, selected_item->contents), mw->menu.old_depth); + sub-menu and select the first selectable menu item there. + If this is a popup menu, skip items with zero call data (title of + the popup). */ + set_new_state (mw, + find_first_selectable (mw, + selected_item->contents, + popup_menu_p), + mw->menu.old_depth); else /* Highlight next possible (enabled and not separator) menu item. */ - set_new_state (mw, find_next_selectable (mw, selected_item), mw->menu.old_depth - 1); + set_new_state (mw, find_next_selectable (mw, selected_item, popup_menu_p), + mw->menu.old_depth - 1); remap_menubar (mw); } @@ -2142,27 +2165,39 @@ Up (w, ev, params, num_params) { XlwMenuWidget mw = (XlwMenuWidget) w; widget_value* selected_item = mw->menu.old_stack [mw->menu.old_depth - 1]; + int popup_menu_p = mw->menu.top_depth == 1; /* Inside top-level menu-bar? */ - if (mw->menu.old_depth == 2) + if (mw->menu.old_depth == mw->menu.top_depth) { /* FIXME: this is tricky. in the menu-bar should select the last selectable item in the list. So we select the first selectable one and find the previous selectable item. Is there a better way? */ - set_new_state (mw, find_first_selectable (mw, selected_item->contents), mw->menu.old_depth); + /* If this is a popup menu, skip items with zero call data (title of + the popup). */ + set_new_state (mw, + find_first_selectable (mw, + selected_item->contents, + popup_menu_p), + mw->menu.old_depth); remap_menubar (mw); selected_item = mw->menu.old_stack [mw->menu.old_depth - 1]; - set_new_state (mw, find_prev_selectable (mw, selected_item), mw->menu.old_depth - 1); + set_new_state (mw, + find_prev_selectable (mw, + selected_item, + popup_menu_p), + mw->menu.old_depth - 1); } else /* Highlight previous (enabled and not separator) menu item. */ - set_new_state (mw, find_prev_selectable (mw, selected_item), mw->menu.old_depth - 1); + set_new_state (mw, find_prev_selectable (mw, selected_item, popup_menu_p), + mw->menu.old_depth - 1); remap_menubar (mw); } -static void +void Left (w, ev, params, num_params) Widget w; XEvent *ev; @@ -2173,31 +2208,36 @@ Left (w, ev, params, num_params) widget_value* selected_item = mw->menu.old_stack [mw->menu.old_depth - 1]; /* Inside top-level menu-bar? */ - if (mw->menu.old_depth == 2) + if (mw->menu.old_depth == mw->menu.top_depth) /* When in the menu-bar is pressed, display the previous item on the menu-bar. If the current item is the first one, highlight the last item in the menubar (probably Help). */ - set_new_state (mw, find_prev_selectable (mw, selected_item), mw->menu.old_depth - 1); + set_new_state (mw, find_prev_selectable (mw, selected_item, 0), + mw->menu.old_depth - 1); else if (mw->menu.old_depth == 1 && selected_item->contents) /* Is this menu item expandable? */ { set_new_state (mw, selected_item->contents, mw->menu.old_depth); remap_menubar (mw); selected_item = mw->menu.old_stack [mw->menu.old_depth - 1]; - if (!selected_item->enabled && find_first_selectable (mw, selected_item)) - set_new_state (mw, find_first_selectable (mw, selected_item), mw->menu.old_depth - 1); + if (!selected_item->enabled && find_first_selectable (mw, + selected_item, + 0)) + set_new_state (mw, find_first_selectable (mw, selected_item, 0), + mw->menu.old_depth - 1); } else { pop_new_stack_if_no_contents (mw); - set_new_state (mw, mw->menu.old_stack [mw->menu.old_depth - 2], mw->menu.old_depth - 2); + set_new_state (mw, mw->menu.old_stack [mw->menu.old_depth - 2], + mw->menu.old_depth - 2); } remap_menubar (mw); } -static void +void Right (w, ev, params, num_params) Widget w; XEvent *ev; @@ -2208,23 +2248,28 @@ Right (w, ev, params, num_params) widget_value* selected_item = mw->menu.old_stack [mw->menu.old_depth - 1]; /* Inside top-level menu-bar? */ - if (mw->menu.old_depth == 2) + if (mw->menu.old_depth == mw->menu.top_depth) /* When in the menu-bar is pressed, display the next item on the menu-bar. If the current item is the last one, highlight the first item (probably File). */ - set_new_state (mw, find_next_selectable (mw, selected_item), mw->menu.old_depth - 1); + set_new_state (mw, find_next_selectable (mw, selected_item, 0), + mw->menu.old_depth - 1); else if (selected_item->contents) /* Is this menu item expandable? */ { set_new_state (mw, selected_item->contents, mw->menu.old_depth); remap_menubar (mw); selected_item = mw->menu.old_stack [mw->menu.old_depth - 1]; - if (!selected_item->enabled && find_first_selectable (mw, selected_item)) - set_new_state (mw, find_first_selectable (mw, selected_item), mw->menu.old_depth - 1); + if (!selected_item->enabled && find_first_selectable (mw, + selected_item, + 0)) + set_new_state (mw, find_first_selectable (mw, selected_item, 0), + mw->menu.old_depth - 1); } else { pop_new_stack_if_no_contents (mw); - set_new_state (mw, mw->menu.old_stack [mw->menu.old_depth - 2], mw->menu.old_depth - 2); + set_new_state (mw, mw->menu.old_stack [mw->menu.old_depth - 2], + mw->menu.old_depth - 2); } remap_menubar (mw); @@ -2305,7 +2350,7 @@ Select (w, ev, params, num_params) /* Special code to pop-up a menu */ -void +static void pop_up_menu (mw, event) XlwMenuWidget mw; XButtonPressedEvent* event; @@ -2349,6 +2394,7 @@ pop_up_menu (mw, event) display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL); mw->menu.windows [0].x = x + borderwidth; mw->menu.windows [0].y = y + borderwidth; + mw->menu.top_depth = 1; /* Popup menus don't have a bar so top is 1 */ } else { @@ -2359,6 +2405,7 @@ pop_up_menu (mw, event) /* notes the absolute position of the menubar window */ mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x; mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y; + mw->menu.top_depth = 2; } #ifdef emacs diff --git a/lwlib/xlwmenu.h b/lwlib/xlwmenu.h index 3057998d17..c1f37b5617 100644 --- a/lwlib/xlwmenu.h +++ b/lwlib/xlwmenu.h @@ -53,9 +53,6 @@ typedef struct _XlwMenuClassRec *XlwMenuWidgetClass; extern WidgetClass xlwMenuWidgetClass; -void -pop_up_menu __P ((XlwMenuWidget, XButtonPressedEvent*)); - #endif /* _XlwMenu_h */ /* arch-tag: 0c019735-d61b-4080-be85-4fdd6e50ae07 diff --git a/lwlib/xlwmenuP.h b/lwlib/xlwmenuP.h index c3e6283018..f6aa0f4a58 100644 --- a/lwlib/xlwmenuP.h +++ b/lwlib/xlwmenuP.h @@ -47,6 +47,7 @@ typedef struct _XlwMenu_part unsigned free_bottom_shadow_color_p : 1; /* State of the XlwMenu */ + int top_depth; int old_depth; widget_value** old_stack; int old_stack_length; -- 2.20.1