changeset 53564:609ef1718642

Changes for lucid popup menus (keyboard traversal enabled) and dialogs (Xaw and Xm pop down on ESC).
author Jan Djärv <jan.h.d@swipnet.se>
date Mon, 12 Jan 2004 01:45:22 +0000
parents 110584d2405e
children 5a46a8191136
files lwlib/ChangeLog lwlib/lwlib-Xaw.c lwlib/lwlib-Xlw.c lwlib/lwlib-Xm.c lwlib/xlwmenu.c lwlib/xlwmenu.h lwlib/xlwmenuP.h
diffstat 7 files changed, 170 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/lwlib/ChangeLog	Mon Jan 12 01:02:18 2004 +0000
+++ b/lwlib/ChangeLog	Mon Jan 12 01:45:22 2004 +0000
@@ -1,3 +1,31 @@
+2004-01-12  Jan Dj,Ad(Brv  <jan.h.d@swipnet.se>
+
+	* 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  <fx@gnu.org>
 
 	* xlwmenu.c: Include lisp.h, not ../src/lisp.h.
--- a/lwlib/lwlib-Xaw.c	Mon Jan 12 01:02:18 2004 +0000
+++ b/lwlib/lwlib-Xaw.c	Mon Jan 12 01:45:22 2004 +0000
@@ -277,6 +277,9 @@
 
 static char overrideTrans[] =
 	"<Message>WM_PROTOCOLS: lwlib_delete_dialog()";
+/* Dialogs pop down on any key press */
+static char dialogOverride[] =
+       "<KeyPress>:	lwlib_delete_dialog()";
 static void wm_delete_window();
 static XtActionsRec xaw_actions [] = {
   {"lwlib_delete_dialog", wm_delete_window}
@@ -333,6 +336,8 @@
 
   ac = 0;
   dialog = XtCreateManagedWidget (name, dialogWidgetClass, shell, av, ac);
+  override = XtParseTranslationTable (dialogOverride);
+  XtOverrideTranslations (dialog, override);
 
   bc = 0;
   button = 0;
@@ -511,8 +516,8 @@
 }
 
 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 @@
   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);
--- a/lwlib/lwlib-Xlw.c	Mon Jan 12 01:02:18 2004 +0000
+++ b/lwlib/lwlib-Xlw.c	Mon Jan 12 01:45:22 2004 +0000
@@ -180,6 +180,7 @@
   XtAddCallback (widget, XtNselect, pick_hook, (XtPointer)instance);
   XtAddCallback (widget, XtNhighlightCallback, highlight_hook,
 		 (XtPointer)instance);
+
   return popup_shell;
 }
 
@@ -251,7 +252,6 @@
      Widget widget;
      XEvent *event;
 {
-  XButtonPressedEvent dummy;
   XlwMenuWidget mw;
 
   if (!XtIsShell (widget))
@@ -260,21 +260,24 @@
   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);
+      XEvent dummy;
+      XButtonPressedEvent *bd = &dummy.xbutton;
 
-      pop_up_menu (mw, &dummy);
+      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);
     }
 }
 
--- a/lwlib/lwlib-Xm.c	Mon Jan 12 01:02:18 2004 +0000
+++ b/lwlib/lwlib-Xm.c	Mon Jan 12 01:45:22 2004 +0000
@@ -1035,6 +1035,33 @@
 
 /* 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 @@
       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 @@
       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 @@
 
   XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
 		 (XtPointer) instance);
+
   return widget;
 }
 
--- a/lwlib/xlwmenu.c	Mon Jan 12 01:02:18 2004 +0000
+++ b/lwlib/xlwmenu.c	Mon Jan 12 01:45:22 2004 +0000
@@ -197,6 +197,8 @@
 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 @@
   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 @@
 {
 }
 
-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 @@
   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 @@
   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 @@
 	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 @@
   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 @@
 {
   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 <down> 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 @@
 {
   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.  <up> 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 @@
   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 <left> 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 @@
   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 <right> 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 @@
 
 
 /* Special code to pop-up a menu */
-void
+static void
 pop_up_menu (mw, event)
      XlwMenuWidget mw;
      XButtonPressedEvent* event;
@@ -2349,6 +2394,7 @@
       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 @@
       /* 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
--- a/lwlib/xlwmenu.h	Mon Jan 12 01:02:18 2004 +0000
+++ b/lwlib/xlwmenu.h	Mon Jan 12 01:45:22 2004 +0000
@@ -53,9 +53,6 @@
 
 extern WidgetClass xlwMenuWidgetClass;
 
-void
-pop_up_menu __P ((XlwMenuWidget, XButtonPressedEvent*));
-
 #endif /* _XlwMenu_h */
 
 /* arch-tag: 0c019735-d61b-4080-be85-4fdd6e50ae07
--- a/lwlib/xlwmenuP.h	Mon Jan 12 01:02:18 2004 +0000
+++ b/lwlib/xlwmenuP.h	Mon Jan 12 01:45:22 2004 +0000
@@ -47,6 +47,7 @@
   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;