Add 2009 to copyright years.
[bpt/emacs.git] / src / nsmenu.m
index 7fbc1b1..3d190a9 100644 (file)
@@ -1,5 +1,5 @@
 /* NeXT/Open/GNUstep and MacOSX Cocoa menu and toolbar module.
-   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -21,7 +21,10 @@ By Adrian Robert, based on code from original nsmenu.m (Carl Edman,
 Christian Limpach, Scott Bender, Christophe de Dinechin) and code in the
 Carbon version by Yamamoto Mitsuharu. */
 
+/* This should be the first include, as it may set up #defines affecting
+   interpretation of even the system includes. */
 #include "config.h"
+
 #include "lisp.h"
 #include "window.h"
 #include "buffer.h"
@@ -53,8 +56,6 @@ int menu_trace_num = 0;
 #include "nsmenu_common.c"
 #endif
 
-extern struct widget_value;
-
 extern Lisp_Object Qundefined, Qmenu_enable, Qmenu_bar_update_hook;
 extern Lisp_Object QCtoggle, QCradio;
 
@@ -65,7 +66,10 @@ extern Lisp_Object Voverriding_local_map, Voverriding_local_map_menu_flag,
                   Qoverriding_local_map, Qoverriding_terminal_local_map;
 
 extern long context_menu_value;
-EmacsMenu *mainMenu, *svcsMenu;
+EmacsMenu *mainMenu, *svcsMenu, *dockMenu;
+
+/* Nonzero means a menu is currently active.  */
+static int popup_activated_flag;
 
 /* NOTE: toolbar implementation is at end,
   following complete menu implementation. */
@@ -78,7 +82,7 @@ EmacsMenu *mainMenu, *svcsMenu;
    ========================================================================== */
 
 
-/*23: PENDING: not currently used, but should normalize with other terms. */
+/*23: FIXME: not currently used, but should normalize with other terms. */
 void
 x_activate_menubar (struct frame *f)
 {
@@ -96,6 +100,13 @@ free_frame_menubar (struct frame *f)
 }
 
 
+int
+popup_activated ()
+{
+  return popup_activated_flag;
+}
+
+
 /* --------------------------------------------------------------------------
     Update menubar.  Three cases:
     1) deep_p = 0, submenu = nil: Fresh switch onto a frame -- either set up
@@ -197,9 +208,9 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu)
        }
       set_buffer_internal_1 (XBUFFER (buffer));
 
-      /* PENDING: for some reason this is not needed in other terms,
-         but some menu updates call Info-extract-pointer which causes
-         abort-on-error if waiting-for-input.  Needs further investigation. */
+      /* TODO: for some reason this is not needed in other terms,
+           but some menu updates call Info-extract-pointer which causes
+           abort-on-error if waiting-for-input.  Needs further investigation. */
       owfi = waiting_for_input;
       waiting_for_input = 0;
 
@@ -239,10 +250,10 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu)
          if (NILP (string))
            break;
 
-          /* PENDING: we'd like to only parse the needed submenu, but this
-             was causing crashes in the _common parsing code.. need to make
-             sure proper initialization done.. */
-/*             if (submenu && strcmp (submenuTitle, SDATA (string)))
+          /* FIXME: we'd like to only parse the needed submenu, but this
+               was causing crashes in the _common parsing code.. need to make
+               sure proper initialization done.. */
+/*        if (submenu && strcmp (submenuTitle, SDATA (string)))
              continue; */
 
          submenu_start[i] = menu_items_used;
@@ -298,16 +309,16 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu)
       set_buffer_internal_1 (prev);
 
       /* Compare the new menu items with previous, and leave off if no change */
-      /* PENDING: following other terms here, but seems like this should be
-         done before parse stage 2 above, since its results aren't used */
+      /* FIXME: following other terms here, but seems like this should be
+           done before parse stage 2 above, since its results aren't used */
       if (previous_menu_items_used
           && (!submenu || (submenu && submenu == last_submenu))
           && menu_items_used == previous_menu_items_used)
         {
           for (i = 0; i < previous_menu_items_used; i++)
-            /* PENDING: this ALWAYS fails on Buffers menu items.. something
-               about their strings causes them to change every time, so we
-               double-check failures */
+            /* FIXME: this ALWAYS fails on Buffers menu items.. something
+                 about their strings causes them to change every time, so we
+                 double-check failures */
             if (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i]))
               if (!(STRINGP (previous_items[i])
                     && STRINGP (XVECTOR (menu_items)->contents[i])
@@ -333,7 +344,7 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu)
             }
         }
       /* The menu items are different, so store them in the frame */
-      /* PENDING: this is not correct for single-submenu case */
+      /* FIXME: this is not correct for single-submenu case */
       f->menu_bar_vector = menu_items;
       f->menu_bar_items_used = menu_items_used;
 
@@ -594,9 +605,10 @@ name_is_separator (name)
   return [NSString stringWithFormat: @"%c", tpos[2]];
 }
 
-- (id <NSMenuItem>)addItemWithWidgetValue: (void *)wvptr
+
+- (NSMenuItem *)addItemWithWidgetValue: (void *)wvptr
 {
-  id <NSMenuItem> item;
+  NSMenuItem *item;
   widget_value *wv = (widget_value *)wvptr;
 
   if (name_is_separator (wv->name))
@@ -663,7 +675,7 @@ name_is_separator (name)
   /* add new contents */
   for (; wv != NULL; wv = wv->next)
     {
-      id <NSMenuItem> item = [self addItemWithWidgetValue: wv];
+      NSMenuItem *item = [self addItemWithWidgetValue: wv];
 
       if (wv->contents)
         {
@@ -691,10 +703,9 @@ name_is_separator (name)
 - (EmacsMenu *)addSubmenuWithTitle: (char *)title forFrame: (struct frame *)f
 {
   NSString *titleStr = [NSString stringWithUTF8String: title];
-  id <NSMenuItem> item
-      = [self addItemWithTitle: titleStr
-                        action: nil /*@selector (menuDown:) */
-                keyEquivalent: @""];
+  NSMenuItem *item = [self addItemWithTitle: titleStr
+                                     action: nil /*@selector (menuDown:) */
+                              keyEquivalent: @""];
   EmacsMenu *submenu = [[EmacsMenu alloc] initWithTitle: titleStr frame: f];
   [self setSubmenu: submenu forItem: item];
   [submenu release];
@@ -830,7 +841,7 @@ ns_popup_menu (Lisp_Object position, Lisp_Object menu)
     }
   else
     {      /* no position given */
-      /* PENDING: if called during dump, we need to stop precomputation of
+      /* FIXME: if called during dump, we need to stop precomputation of
          key equivalents (see below) because the keydefs in ns-win.el have
          not been loaded yet. */
       if (noninteractive)
@@ -934,7 +945,7 @@ ns_popup_menu (Lisp_Object position, Lisp_Object menu)
   specpdl_count2 = SPECPDL_INDEX ();
 
 #if 0
-  /*PENDING: a couple of one-line differences prevent reuse */
+  /* FIXME: a couple of one-line differences prevent reuse */
   wv = digest_single_submenu (0, menu_items_used, Qnil);
 #else
   {
@@ -1107,7 +1118,7 @@ ns_popup_menu (Lisp_Object position, Lisp_Object menu)
 #endif
 
       wv_title->name = (char *) SDATA (title);
-      wv_title->enabled = NULL;
+      wv_title->enabled = NO;
       wv_title->button_type = BUTTON_TYPE_NONE;
       wv_title->help = Qnil;
       wv_title->next = wv_sep;
@@ -1120,10 +1131,13 @@ ns_popup_menu (Lisp_Object position, Lisp_Object menu)
   free_menubar_widget_value_tree (first_wv);
   unbind_to (specpdl_count2, Qnil);
 
+  popup_activated_flag = 1;
   tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps];
+  popup_activated_flag = 0;
   [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
 
   UNBLOCK_INPUT;
+  discard_menu_items ();
   unbind_to (specpdl_count, Qnil);
   UNGCPRO;
 
@@ -1514,8 +1528,9 @@ ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
   p.y = (int)f->top_pos + (FRAME_LINE_HEIGHT (f) * f->text_lines)/2;
   dialog = [[EmacsDialogPanel alloc] initFromContents: contents
                                            isQuestion: isQ];
-
+  popup_activated_flag = 1;
   tem = [dialog runDialogAt: p];
+  popup_activated_flag = 0;
 
   [dialog close];
 
@@ -1735,7 +1750,7 @@ void process_dialog (id window, Lisp_Object list)
     return self;
 
   seltag = [[sellist objectAtIndex: 0] tag];
-  if (seltag == XHASH (Qundefined)) // FIXME: BIG UGLY HACK!!
+  if (seltag != XHASH (Qundefined)) // FIXME: BIG UGLY HACK!!
     [NSApp stopModalWithCode: seltag];
   return self;
 }
@@ -1860,7 +1875,7 @@ void process_dialog (id window, Lisp_Object list)
    ========================================================================== */
 
 DEFUN ("ns-reset-menu", Fns_reset_menu, Sns_reset_menu, 0, 0, 0,
-       "Cause the NS menu to be re-calculated.")
+       doc: /* Cause the NS menu to be re-calculated.  */)
      ()
 {
   set_frame_menubar (SELECTED_FRAME (), 1, 0);
@@ -1869,30 +1884,38 @@ DEFUN ("ns-reset-menu", Fns_reset_menu, Sns_reset_menu, 0, 0, 0,
 
 
 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 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\
-or a list ((XOFFSET YOFFSET) WINDOW)\n\
-where XOFFSET and YOFFSET are positions in pixels 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\
-\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.")
+       doc: /* Pop up a deck-of-cards menu and return user's selection.
+POSITION is a position specification.  This is either a mouse button event
+or a list ((XOFFSET YOFFSET) WINDOW)
+where XOFFSET and YOFFSET are positions in pixels from the top left
+corner of WINDOW.  (WINDOW may be a window or a frame object.)
+This controls the position of the top left of the menu as a whole.
+If POSITION is t, it means to use the current mouse position.
+
+MENU is a specifier for a menu.  For the simplest case, MENU is a keymap.
+The menu items come from key bindings that have a menu string as well as
+a definition; actually, the \"definition\" in such a key binding looks like
+\(STRING . REAL-DEFINITION).  To give the menu a title, put a string into
+the keymap as a top-level element.
+
+If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
+Otherwise, REAL-DEFINITION should be a valid key binding definition.
+
+You can also use a list of keymaps as MENU.
+  Then each keymap makes a separate pane.
+
+When MENU is a keymap or a list of keymaps, the return value is the
+list of events corresponding to the user's choice. Note that
+`x-popup-menu' does not actually execute the command bound to that
+sequence of events.
+
+Alternatively, you can specify a menu of multiple panes
+  with a list of the form (TITLE PANE1 PANE2...),
+where each pane is a list of form (TITLE ITEM1 ITEM2...).
+Each ITEM is normally a cons cell (STRING . VALUE);
+but a string can appear as an item--that makes a nonselectable line
+in the menu.
+With this form of menu, the return value is VALUE from the chosen item.  */)
      (position, menu)
      Lisp_Object position, menu;
 {
@@ -1929,6 +1952,12 @@ for instance using the window manager, then this produces a quit and
   return ns_popup_dialog (position, contents, header);
 }
 
+DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
+       doc: /* Return t if a menu or popup dialog is active.  */)
+     ()
+{
+  return popup_activated () ? Qt : Qnil;
+}
 
 /* ==========================================================================
 
@@ -1942,6 +1971,7 @@ syms_of_nsmenu ()
   defsubr (&Sx_popup_menu);
   defsubr (&Sx_popup_dialog);
   defsubr (&Sns_reset_menu);
+  defsubr (&Smenu_or_popup_active_p);
   staticpro (&menu_items);
   menu_items = Qnil;