use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / nsmenu.m
index 5af813a..7600b60 100644 (file)
@@ -1,5 +1,5 @@
 /* NeXT/Open/GNUstep and MacOSX Cocoa menu and toolbar module.
-   Copyright (C) 2007-2013 Free Software Foundation, Inc.
+   Copyright (C) 2007-2014 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -174,11 +174,12 @@ ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
       int *submenu_n_panes;
       struct buffer *prev = current_buffer;
       Lisp_Object buffer;
-      ptrdiff_t specpdl_count = SPECPDL_INDEX ();
       int previous_menu_items_used = f->menu_bar_items_used;
       Lisp_Object *previous_items
        = alloca (previous_menu_items_used * sizeof *previous_items);
 
+      dynwind_begin ();
+
       /* lisp preliminaries */
       buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
       specbind (Qinhibit_quit, Qt);
@@ -258,7 +259,7 @@ ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
           fprintf (stderr, "ERROR: did not find lisp menu for submenu '%s'.\n",
                   [[submenu title] UTF8String]);
          discard_menu_items ();
-         unbind_to (specpdl_count, Qnil);
+          dynwind_end ();
           [pool release];
           unblock_input ();
          return;
@@ -266,12 +267,8 @@ ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
 
       /* parse stage 2: insert into lucid 'widget_value' structures
          [comments in other terms say not to evaluate lisp code here] */
-      wv = xmalloc_widget_value ();
-      wv->name = "menubar";
-      wv->value = 0;
-      wv->enabled = 1;
+      wv = make_widget_value ("menubar", NULL, true, Qnil);
       wv->button_type = BUTTON_TYPE_NONE;
-      wv->help = Qnil;
       first_wv = wv;
 
       for (i = 0; i < 4*n; i += 4)
@@ -320,7 +317,7 @@ ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
 
               free_menubar_widget_value_tree (first_wv);
               discard_menu_items ();
-              unbind_to (specpdl_count, Qnil);
+              dynwind_end ();
               [pool release];
               unblock_input ();
               return;
@@ -332,7 +329,7 @@ ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
       f->menu_bar_items_used = menu_items_used;
 
       /* Calls restore_menu_items, etc., as they were outside */
-      unbind_to (specpdl_count, Qnil);
+      dynwind_end ();
 
       /* Parse stage 2a: now GC cannot happen during the lifetime of the
          widget_value, so it's safe to store data from a Lisp_String */
@@ -378,12 +375,8 @@ ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
       int n;
       Lisp_Object string;
 
-      wv = xmalloc_widget_value ();
-      wv->name = "menubar";
-      wv->value = 0;
-      wv->enabled = 1;
+      wv = make_widget_value ("menubar", NULL, true, Qnil);
       wv->button_type = BUTTON_TYPE_NONE;
-      wv->help = Qnil;
       first_wv = wv;
 
       /* Make widget-value tree w/ just the top level menu bar strings */
@@ -439,12 +432,8 @@ ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
            memcpy (previous_strings[i/4], SDATA (string),
                     min (10, SBYTES (string) + 1));
 
-         wv = xmalloc_widget_value ();
-         wv->name = SSDATA (string);
-         wv->value = 0;
-         wv->enabled = 1;
+         wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
          wv->button_type = BUTTON_TYPE_NONE;
-         wv->help = Qnil;
          wv->call_data = (void *) (intptr_t) (-1);
 
 #ifdef NS_IMPL_COCOA
@@ -730,7 +719,7 @@ extern NSString *NSMenuDidBeginTrackingNotification;
 
 - (void)fillWithWidgetValue: (void *)wvptr
 {
-  [self fillWithWidgetValue: wvptr frame:nil];
+  [self fillWithWidgetValue: wvptr frame: (struct frame *)nil];
 }
 
 - (void)fillWithWidgetValue: (void *)wvptr frame: (struct frame *)f
@@ -824,24 +813,24 @@ extern NSString *NSMenuDidBeginTrackingNotification;
    ========================================================================== */
 
 Lisp_Object
-ns_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
+ns_menu_show (struct frame *f, int x, int y, int menuflags,
              Lisp_Object title, const char **error)
 {
   EmacsMenu *pmenu;
   NSPoint p;
   Lisp_Object tem;
-  ptrdiff_t specpdl_count = SPECPDL_INDEX ();
   widget_value *wv, *first_wv = 0;
+  bool keymaps = (menuflags & MENU_KEYMAPS);
+
+  block_input ();
+
+  dynwind_begin ();
 
   p.x = x; p.y = y;
 
   /* now parse stage 2 as in ns_update_menubar */
-  wv = xmalloc_widget_value ();
-  wv->name = "contextmenu";
-  wv->value = 0;
-  wv->enabled = 1;
+  wv = make_widget_value ("contextmenu", NULL, true, Qnil);
   wv->button_type = BUTTON_TYPE_NONE;
-  wv->help = Qnil;
   first_wv = wv;
 
 #if 0
@@ -912,18 +901,14 @@ ns_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
             with its items as a submenu beneath it.  */
          if (!keymaps && strcmp (pane_string, ""))
            {
-             wv = xmalloc_widget_value ();
+             wv = make_widget_value (pane_string, NULL, true, Qnil);
              if (save_wv)
                save_wv->next = wv;
              else
                first_wv->contents = wv;
-             wv->name = pane_string;
              if (keymaps && !NILP (prefix))
                wv->name++;
-             wv->value = 0;
-             wv->enabled = 1;
              wv->button_type = BUTTON_TYPE_NONE;
-             wv->help = Qnil;
              save_wv = wv;
              prev_wv = 0;
            }
@@ -961,20 +946,18 @@ ns_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
            }
 #endif /* not HAVE_MULTILINGUAL_MENU */
 
-         wv = xmalloc_widget_value ();
+         wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
+                                 STRINGP (help) ? help : Qnil);
          if (prev_wv)
            prev_wv->next = wv;
          else
            save_wv->contents = wv;
-         wv->name = SSDATA (item_name);
          if (!NILP (descrip))
            wv->key = SSDATA (descrip);
-         wv->value = 0;
          /* If this item has a null value,
             make the call_data null so that it won't display a box
             when the mouse is on it.  */
          wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
-         wv->enabled = !NILP (enable);
 
          if (NILP (type))
            wv->button_type = BUTTON_TYPE_NONE;
@@ -987,11 +970,6 @@ ns_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
 
          wv->selected = !NILP (selected);
 
-          if (! STRINGP (help))
-           help = Qnil;
-
-         wv->help = help;
-
          prev_wv = wv;
 
          i += MENU_ITEMS_ITEM_LENGTH;
@@ -1002,24 +980,19 @@ ns_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
 
   if (!NILP (title))
     {
-      widget_value *wv_title = xmalloc_widget_value ();
-      widget_value *wv_sep = xmalloc_widget_value ();
+      widget_value *wv_title;
+      widget_value *wv_sep = make_widget_value ("--", NULL, false, Qnil);
 
       /* Maybe replace this separator with a bitmap or owner-draw item
         so that it looks better.  Having two separators looks odd.  */
-      wv_sep->name = "--";
       wv_sep->next = first_wv->contents;
-      wv_sep->help = Qnil;
 
 #ifndef HAVE_MULTILINGUAL_MENU
       if (STRING_MULTIBYTE (title))
        title = ENCODE_MENU_STRING (title);
 #endif
-
-      wv_title->name = SSDATA (title);
-      wv_title->enabled = NO;
+      wv_title = make_widget_value (SSDATA (title), NULL, false, Qnil);
       wv_title->button_type = BUTTON_TYPE_NONE;
-      wv_title->help = Qnil;
       wv_title->next = wv_sep;
       first_wv->contents = wv_title;
     }
@@ -1028,13 +1001,14 @@ ns_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
                                [NSString stringWithUTF8String: SSDATA (title)]];
   [pmenu fillWithWidgetValue: first_wv->contents];
   free_menubar_widget_value_tree (first_wv);
-  unbind_to (specpdl_count, Qnil);
+  dynwind_end ();
 
   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 ();
   return tem;
 }
 
@@ -1051,8 +1025,10 @@ free_frame_tool_bar (struct frame *f)
     Under NS we just hide the toolbar until it might be needed again.
    -------------------------------------------------------------------------- */
 {
+  EmacsView *view = FRAME_NS_VIEW (f);
   block_input ();
-  [[FRAME_NS_VIEW (f) toolbar] setVisible: NO];
+  view->wait_for_tool_bar = NO;
+  [[view toolbar] setVisible: NO];
   FRAME_TOOLBAR_HEIGHT (f) = 0;
   unblock_input ();
 }
@@ -1068,6 +1044,7 @@ update_frame_tool_bar (struct frame *f)
   NSWindow *window = [view window];
   EmacsToolbar *toolbar = [view toolbar];
 
+  if (view == nil || toolbar == nil) return;
   block_input ();
 
 #ifdef NS_IMPL_COCOA
@@ -1093,7 +1070,7 @@ update_frame_tool_bar (struct frame *f)
       /* Check if this is a separator.  */
       if (EQ (TOOLPROP (TOOL_BAR_ITEM_TYPE), Qt))
         {
-          /* Skip separators.  Newer OSX don't show them, and on GNUStep they
+          /* Skip separators.  Newer OSX don't show them, and on GNUstep they
              are wide as a button, thus overflowing the toolbar most of
              the time.  */
           continue;
@@ -1173,9 +1150,13 @@ update_frame_tool_bar (struct frame *f)
   FRAME_TOOLBAR_HEIGHT (f) =
     NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
     - FRAME_NS_TITLEBAR_HEIGHT (f);
-    if (FRAME_TOOLBAR_HEIGHT (f) < 0) // happens if frame is fullscreen.
-      FRAME_TOOLBAR_HEIGHT (f) = 0;
-    unblock_input ();
+  if (FRAME_TOOLBAR_HEIGHT (f) < 0) // happens if frame is fullscreen.
+    FRAME_TOOLBAR_HEIGHT (f) = 0;
+
+  if (view->wait_for_tool_bar && FRAME_TOOLBAR_HEIGHT (f) > 0)
+      [view setNeedsDisplay: YES];
+
+  unblock_input ();
 }
 
 
@@ -1239,7 +1220,7 @@ update_frame_tool_bar (struct frame *f)
 {
   /* 1) come up w/identifier */
   NSString *identifier
-      = [NSString stringWithFormat: @"%u", [img hash]];
+    = [NSString stringWithFormat: @"%lu", (unsigned long)[img hash]];
   [activeIdentifiers addObject: identifier];
 
   /* 2) create / reuse item */
@@ -1449,11 +1430,10 @@ pop_down_menu (void *arg)
 
 
 Lisp_Object
-ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
+ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
 {
   id dialog;
   Lisp_Object window, tem, title;
-  struct frame *f;
   NSPoint p;
   BOOL isQ;
   NSAutoreleasePool *pool;
@@ -1462,41 +1442,6 @@ ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
 
   isQ = NILP (header);
 
-  if (EQ (position, Qt)
-      || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
-                               || EQ (XCAR (position), Qtool_bar))))
-    {
-      window = selected_window;
-    }
-  else if (CONSP (position))
-    {
-      Lisp_Object tem;
-      tem = Fcar (position);
-      if (XTYPE (tem) == Lisp_Cons)
-        window = Fcar (Fcdr (position));
-      else
-        {
-          tem = Fcar (Fcdr (position));  /* EVENT_START (position) */
-          window = Fcar (tem);      /* POSN_WINDOW (tem) */
-        }
-    }
-  else if (WINDOWP (position) || FRAMEP (position))
-    {
-      window = position;
-    }
-  else
-    window = Qnil;
-
-  if (FRAMEP (window))
-    f = XFRAME (window);
-  else if (WINDOWP (window))
-    {
-      CHECK_LIVE_WINDOW (window);
-      f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
-    }
-  else
-    CHECK_WINDOW (window);
-
   check_window_system (f);
 
   p.x = (int)f->left_pos + ((int)FRAME_COLUMN_WIDTH (f) * f->text_cols)/2;
@@ -1516,16 +1461,16 @@ ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
                                            isQuestion: isQ];
 
   {
-    ptrdiff_t specpdl_count = SPECPDL_INDEX ();
     struct Popdown_data *unwind_data = xmalloc (sizeof (*unwind_data));
 
     unwind_data->pool = pool;
     unwind_data->dialog = dialog;
 
+    dynwind_begin ();
     record_unwind_protect_ptr (pop_down_menu, unwind_data);
     popup_activated_flag = 1;
     tem = [dialog runDialogAt: p];
-    unbind_to (specpdl_count, Qnil);  /* calls pop_down_menu */
+    dynwind_end ();
   }
 
   unblock_input ();
@@ -1675,24 +1620,24 @@ ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
   int row = 0;
   int buttons = 0, btnnr = 0;
 
-  for (; XTYPE (lst) == Lisp_Cons; lst = XCDR (lst))
+  for (; CONSP (lst); lst = XCDR (lst))
     {
       item = XCAR (list);
-      if (XTYPE (item) == Lisp_Cons)
+      if (CONSP (item))
         ++buttons;
     }
 
   if (buttons > 0)
     button_values = xmalloc (buttons * sizeof *button_values);
 
-  for (; XTYPE (list) == Lisp_Cons; list = XCDR (list))
+  for (; CONSP (list); list = XCDR (list))
     {
       item = XCAR (list);
-      if (XTYPE (item) == Lisp_String)
+      if (STRINGP (item))
         {
           [self addString: SSDATA (item) row: row++];
         }
-      else if (XTYPE (item) == Lisp_Cons)
+      else if (CONSP (item))
         {
           button_values[btnnr] = XCDR (item);
           [self addButton: SSDATA (XCAR (item)) value: btnnr row: row++];
@@ -1769,7 +1714,7 @@ ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
   Lisp_Object head;
   [super init];
 
-  if (XTYPE (contents) == Lisp_Cons)
+  if (CONSP (contents))
     {
       head = Fcar (contents);
       [self process_dialog: Fcdr (contents)];
@@ -1777,7 +1722,7 @@ ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
   else
     head = contents;
 
-  if (XTYPE (head) == Lisp_String)
+  if (STRINGP (head))
       [title setStringValue:
                  [NSString stringWithUTF8String: SSDATA (head)]];
   else if (isQ == YES)
@@ -1867,11 +1812,11 @@ ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
   while (popup_activated_flag)
     {
       NSTimer *tmo = nil;
-      EMACS_TIME next_time = timer_check ();
+      struct timespec next_time = timer_check ();
 
-      if (EMACS_TIME_VALID_P (next_time))
+      if (timespec_valid_p (next_time))
         {
-          double time = EMACS_TIME_TO_DOUBLE (next_time);
+          double time = timespectod (next_time);
           tmo = [NSTimer timerWithTimeInterval: time
                                         target: self
                                       selector: @selector (timeout_handler:)
@@ -1916,34 +1861,6 @@ DEFUN ("ns-reset-menu", Fns_reset_menu, Sns_reset_menu, 0, 0, 0,
 }
 
 
-DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
-       doc: /* Pop up a dialog box and return user's selection.
-POSITION specifies which frame to use.
-This is normally a mouse button event or a window or frame.
-If POSITION is t, it means to use the frame the mouse is on.
-The dialog box appears in the middle of the specified frame.
-
-CONTENTS specifies the alternatives to display in the dialog box.
-It is a list of the form (DIALOG ITEM1 ITEM2...).
-Each ITEM is a cons cell (STRING . VALUE).
-The return value is VALUE from the chosen item.
-
-An ITEM may also be just a string--that makes a nonselectable item.
-An ITEM may also be nil--that means to put all preceding items
-on the left of the dialog box and all following items on the right.
-\(By default, approximately half appear on each side.)
-
-If HEADER is non-nil, the frame title for the box is "Information",
-otherwise it is "Question".
-
-If the user gets rid of the dialog box without making a valid choice,
-for instance using the window manager, then this produces a quit and
-`x-popup-dialog' does not return.  */)
-     (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
-{
-  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.  */)
      (void)
@@ -1960,14 +1877,13 @@ DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_
 void
 syms_of_nsmenu (void)
 {
+#include "nsmenu.x"
+
 #ifndef NS_IMPL_COCOA
-  /* Don't know how to keep track of this in Next/Open/Gnustep.  Always
+  /* Don't know how to keep track of this in Next/Open/GNUstep.  Always
      update menus there.  */
   trackingMenu = 1;
 #endif
-  defsubr (&Sx_popup_dialog);
-  defsubr (&Sns_reset_menu);
-  defsubr (&Smenu_or_popup_active_p);
 
   Qdebug_on_next_call = intern_c_string ("debug-on-next-call");
   staticpro (&Qdebug_on_next_call);