]> code.delx.au - gnu-emacs/blobdiff - lwlib/xlwmenu.c
(motion_event_is_in_menu): Make x and y signed.
[gnu-emacs] / lwlib / xlwmenu.c
index c47412848dac69939af562655503cdea62bb52ab..c2aae8d0e61cbe07e5b1fad274cf08217af61495 100644 (file)
@@ -14,7 +14,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING.  If not, write to
+Alongalong with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /* Created by devin@lucid.com */
@@ -24,6 +24,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/types.h>
 #include <X11/Xos.h>
 #include <X11/IntrinsicP.h>
+#include <X11/ObjectP.h>
 #include <X11/StringDefs.h>
 #include <X11/cursorfont.h>
 #include <X11/bitmaps/gray>
@@ -32,11 +33,43 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 static int pointer_grabbed;
 static XEvent menu_post_event;
 
+XFontStruct *xlwmenu_default_font;
+
 static char 
 xlwMenuTranslations [] = 
-"<BtnDown>:    start()\n\
-<Motion>:      drag()\n\
-<BtnUp>:       select()\n\
+"<BtnDown>:      start()\n\
+<Motion>:        drag()\n\
+<BtnUp>:         select()\n\
+<Key>Shift_L:     nothing()\n\
+<Key>Shift_R:     nothing()\n\
+<Key>Meta_L:      nothing()\n\
+<Key>Meta_R:      nothing()\n\
+<Key>Control_L:   nothing()\n\
+<Key>Control_R:   nothing()\n\
+<Key>Hyper_L:     nothing()\n\
+<Key>Hyper_R:     nothing()\n\
+<Key>Super_L:     nothing()\n\
+<Key>Super_R:     nothing()\n\
+<Key>Alt_L:       nothing()\n\
+<Key>Alt_R:       nothing()\n\
+<Key>Caps_Lock:   nothing()\n\
+<Key>Shift_Lock:  nothing()\n\
+<KeyUp>Shift_L:   nothing()\n\
+<KeyUp>Shift_R:   nothing()\n\
+<KeyUp>Meta_L:    nothing()\n\
+<KeyUp>Meta_R:    nothing()\n\
+<KeyUp>Control_L: nothing()\n\
+<KeyUp>Control_R: nothing()\n\
+<KeyUp>Hyper_L:   nothing()\n\
+<KeyUp>Hyper_R:   nothing()\n\
+<KeyUp>Super_L:   nothing()\n\
+<KeyUp>Super_R:   nothing()\n\
+<KeyUp>Alt_L:     nothing()\n\
+<KeyUp>Alt_R:     nothing()\n\
+<KeyUp>Caps_Lock: nothing()\n\
+<KeyUp>Shift_Lock:nothing()\n\
+<Key>:            key()\n\
+<KeyUp>:          key()\n\
 ";
 
 #define offset(field) XtOffset(XlwMenuWidget, field)
@@ -94,6 +127,8 @@ static void XlwMenuClassInitialize();
 static void Start();
 static void Drag();
 static void Select();
+static void Key();
+static void Nothing();
 
 static XtActionsRec 
 xlwMenuActionsList [] =
@@ -101,6 +136,8 @@ xlwMenuActionsList [] =
   {"start",            Start},
   {"drag",             Drag},
   {"select",           Select},
+  {"key",              Key},
+  {"nothing",          Nothing},
 };
 
 #define SuperClass ((CoreWidgetClass)&coreClassRec)
@@ -323,10 +360,10 @@ size_menu (mw, level)
      XlwMenuWidget mw;
      int level;
 {
-  int          label_width = 0;
+  unsigned int  label_width = 0;
   int          rest_width = 0;
   int          max_rest_width = 0;
-  int          height = 0;
+  unsigned int  height = 0;
   int          horizontal_p = mw->menu.horizontal && (level == 0);
   widget_value*        val;
   window_state*        ws;
@@ -483,8 +520,11 @@ display_menu_item (mw, val, ws, where, highlighted_p, horizontal_p, just_compute
       width = ws->width - 2 * shadow;
     }
 
+#if 0
   /* see if it should be a button in the menubar */
   button_p = horizontal_p && val->call_data;
+#endif
+  button_p = 0;
 
   /* Only highlight an enabled item that has a callback. */
   if (highlighted_p)
@@ -515,10 +555,19 @@ display_menu_item (mw, val, ws, where, highlighted_p, horizontal_p, just_compute
        }
       else 
        {
+         int x_offset = x + h_spacing + shadow;
          char* display_string = resource_widget_value (mw, val);
          draw_shadow_rectangle (mw, ws->window, x, y, width, height, True);
-         XDrawString (XtDisplay (mw), ws->window, text_gc,
-                      x + h_spacing + shadow,
+
+         /* Deal with centering a menu title. */
+         if (!horizontal_p && !val->contents && !val->call_data)
+           {
+             int l = string_width (mw, display_string);
+
+             if (width > l)
+               x_offset = (width - l) >> 1;
+           }
+          XDrawString (XtDisplay (mw), ws->window, text_gc, x_offset,
                       y + v_spacing + shadow + font_ascent,
                       display_string, strlen (display_string));
          
@@ -729,8 +778,8 @@ fit_to_screen (mw, ws, previous_ws, horizontal_p)
      window_state* previous_ws;
      Boolean horizontal_p;
 {
-  int screen_width = WidthOfScreen (XtScreen (mw));
-  int screen_height = HeightOfScreen (XtScreen (mw));
+  unsigned int screen_width = WidthOfScreen (XtScreen (mw));
+  unsigned int screen_height = HeightOfScreen (XtScreen (mw));
 
   if (ws->x < 0)
     ws->x = 0;
@@ -740,6 +789,8 @@ fit_to_screen (mw, ws, previous_ws, horizontal_p)
        ws->x = previous_ws->x - ws->width;
       else
        ws->x = screen_width - ws->width;
+      if (ws->x < 0)
+        ws->x = 0;
     }
   if (ws->y < 0)
     ws->y = 0;
@@ -749,6 +800,8 @@ fit_to_screen (mw, ws, previous_ws, horizontal_p)
        ws->y = previous_ws->y - ws->height;
       else
        ws->y = screen_height - ws->height;
+      if (ws->y < 0) 
+        ws->y = 0;
     }
 }
 
@@ -795,7 +848,7 @@ remap_menubar (mw)
     old_stack [i] = new_stack [i];
   mw->menu.old_depth = new_depth;
 
-  /* refresh the last seletion */
+  /* refresh the last selection */
   selection_position.x = 0;
   selection_position.y = 0;
   display_menu (mw, last_same, new_selection == old_selection,
@@ -1045,15 +1098,13 @@ release_shadow_gcs (mw)
 }
 
 static void
-XlwMenuInitialize (request, new, args, num_args)
+XlwMenuInitialize (request, mw, args, num_args)
      Widget request;
-     Widget new;
+     XlwMenuWidget mw;
      ArgList args;
      Cardinal *num_args;
 {
   /* Get the GCs and the widget size */
-  XlwMenuWidget mw = (XlwMenuWidget)new;
-  
   XSetWindowAttributes xswa;
   int mask;
   
@@ -1072,10 +1123,17 @@ XlwMenuInitialize (request, new, args, num_args)
 /*  mw->menu.cursor = XCreateFontCursor (display, mw->menu.cursor_shape); */
   mw->menu.cursor = mw->menu.cursor_shape;
   
-  mw->menu.gray_pixmap = XCreatePixmapFromBitmapData (display, window,
-                                                     gray_bits, gray_width,
-                                                     gray_height, 1, 0, 1);
+  mw->menu.gray_pixmap
+    = XCreatePixmapFromBitmapData (display, window, gray_bits,
+                                  gray_width, gray_height,
+                                  (unsigned long)1, (unsigned long)0, 1);
   
+  /* I don't understand why this ends up 0 sometimes,
+     but it does.  This kludge works around it.
+     Can anyone find a real fix?   -- rms.  */
+  if (mw->menu.font == 0)
+    mw->menu.font = xlwmenu_default_font;
+
   make_drawing_gcs (mw);
   make_shadow_gcs (mw);
   
@@ -1227,6 +1285,11 @@ XlwMenuSetValues (current, request, new)
       && newmw->menu.contents->contents
       && newmw->menu.contents->contents->change >= VISIBLE_CHANGE)
     redisplay = True;
+  /* Do redisplay if the contents are entirely eliminated.  */
+  if (newmw->menu.contents
+      && newmw->menu.contents->contents == 0
+      && newmw->menu.contents->change >= VISIBLE_CHANGE)
+    redisplay = True;
 
   if (newmw->core.background_pixel != oldmw->core.background_pixel
       || newmw->menu.foreground != oldmw->menu.foreground
@@ -1286,10 +1349,8 @@ handle_single_motion_event (mw, ev)
     set_new_state (mw, val, level);
   remap_menubar (mw);
   
-#if 0
   /* Sync with the display.  Makes it feel better on X terms. */
   XSync (XtDisplay (mw), False);
-#endif
 }
 
 static void
@@ -1330,21 +1391,18 @@ Start (w, ev, params, num_params)
       pop_up_menu (mw, ev);
     }
   else
-    /* If we push a button while the menu is posted semipermanently,
-       releasing the button should always pop the menu down.  */
-    next_release_must_exit = 1;
-
-#if 0
-  XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
-  
-  /* 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;
+    {
+      /* If we push a button while the menu is posted semipermanently,
+        releasing the button should always pop the menu down.  */
+      next_release_must_exit = 1;
 
-  /* handles the down like a move, slots are compatible */
-  handle_motion_event (mw, &ev->xmotion);
-#endif
+      /* 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;
 
+      /* handles the down like a move, slots are compatible */
+      handle_motion_event (mw, &ev->xmotion);
+    }
 }
 
 static void 
@@ -1355,10 +1413,54 @@ Drag (w, ev, params, num_params)
      Cardinal *num_params;
 {
   XlwMenuWidget mw = (XlwMenuWidget)w;
-  handle_motion_event (mw, &ev->xmotion);
+  if (mw->menu.popped_up)
+    handle_motion_event (mw, &ev->xmotion);
 }
 
-static void 
+/* Do nothing.
+   This is how we handle presses and releases of modifier keys.  */
+static void
+Nothing (w, ev, params, num_params)
+     Widget w;
+     XEvent *ev;
+     String *params;
+     Cardinal *num_params;
+{
+}
+
+/* Handle key press and release events while menu is popped up.
+   Our action is to get rid of the menu.  */
+static void
+Key (w, ev, params, num_params)
+     Widget w;
+     XEvent *ev;
+     String *params;
+     Cardinal *num_params;
+{
+  XlwMenuWidget mw = (XlwMenuWidget)w;
+
+  /* Pop down everything.  */
+  mw->menu.new_depth = 1;
+  remap_menubar (mw);
+
+  if (mw->menu.popped_up)
+    {
+      mw->menu.popped_up = False;
+      XtUngrabPointer ((Widget)mw, ev->xmotion.time);
+      if (XtIsShell (XtParent ((Widget) mw)))
+       XtPopdown (XtParent ((Widget) mw));
+      else
+       {
+         XtRemoveGrab ((Widget) mw);
+         display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL);
+       }
+    }
+
+  /* callback */
+  XtCallCallbackList ((Widget)mw, mw->menu.select, (XtPointer)0);
+}
+
+static void
 Select (w, ev, params, num_params)
      Widget w;
      XEvent *ev;
@@ -1386,12 +1488,17 @@ Select (w, ev, params, num_params)
     {
       mw->menu.popped_up = False;
       XtUngrabPointer ((Widget)mw, ev->xmotion.time);
-      XtPopdown (XtParent (mw));
+      if (XtIsShell (XtParent ((Widget) mw)))
+       XtPopdown (XtParent ((Widget) mw));
+      else
+       {
+         XtRemoveGrab ((Widget) mw);
+         display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL);
+       }
     }
 
   /* callback */
   XtCallCallbackList ((Widget)mw, mw->menu.select, (XtPointer)selected_item);
-  
 }
 
 
@@ -1407,12 +1514,14 @@ pop_up_menu (mw, event)
   int          h;
   int          borderwidth = mw->menu.shadow_thickness;
   Screen*      screen = XtScreen (mw);
+  Display       *display = XtDisplay (mw);
 
   next_release_must_exit = 0;
 
   XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
 
-  size_menu (mw, 0);
+  if (XtIsShell (XtParent ((Widget)mw)))
+    size_menu (mw, 0);
 
   w = mw->menu.windows [0].width;
   h = mw->menu.windows [0].height;
@@ -1429,30 +1538,46 @@ pop_up_menu (mw, event)
     y = HeightOfScreen (screen) - h - 2 * borderwidth;
 
   mw->menu.popped_up = True;
-  XtConfigureWidget (XtParent (mw), x, y, w, h,
-                    XtParent (mw)->core.border_width);
-  XtPopup (XtParent (mw), XtGrabExclusive);
-  display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL);
+  if (XtIsShell (XtParent ((Widget)mw)))
+    {
+      XtConfigureWidget (XtParent ((Widget)mw), x, y, w, h,
+                        XtParent ((Widget)mw)->core.border_width);
+      XtPopup (XtParent ((Widget)mw), XtGrabExclusive);
+      display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL);
+      mw->menu.windows [0].x = x + borderwidth;
+      mw->menu.windows [0].y = y + borderwidth;
+    }
+  else
+    {
+      XEvent *ev = (XEvent *) event;
+
+      XtAddGrab ((Widget) mw, True, True);
+
+      /* 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;
+    }
+
 #ifdef emacs
-  x_catch_errors ();
+  x_catch_errors (display);
 #endif
   XtGrabPointer ((Widget)mw, False,
-                (PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask
+                (PointerMotionMask
+                 | PointerMotionHintMask
+                 | ButtonReleaseMask
                  | ButtonPressMask),
-                GrabModeAsync, GrabModeAsync, None, mw->menu.cursor_shape,
+                GrabModeAsync, GrabModeAsync, None,
+                mw->menu.cursor_shape,
                 event->time);
   pointer_grabbed = 1;
 #ifdef emacs
-  if (x_had_errors_p ())
+  if (x_had_errors_p (display))
     {
       pointer_grabbed = 0;
       XtUngrabPointer ((Widget)mw, event->time);
     }
-  x_uncatch_errors ();
+  x_uncatch_errors (display);
 #endif
 
-  mw->menu.windows [0].x = x + borderwidth;
-  mw->menu.windows [0].y = y + borderwidth;
-
   handle_motion_event (mw, (XMotionEvent*)event);
 }