]> git.eshelyaron.com Git - emacs.git/commitdiff
Remove NS menu synthesized events (bug#44333)
authorAlan Third <alan@idiocy.org>
Wed, 23 Dec 2020 20:12:02 +0000 (20:12 +0000)
committerAlan Third <alan@idiocy.org>
Sun, 27 Dec 2020 16:51:47 +0000 (16:51 +0000)
Remove the frame tracking stuff as it's not used for anything, and
move the update tracking into the EmacsMenu class.

* src/nsmenu.m (ns_update_menubar): Copy the parsing code from xmenu.c
and rework the NS specific code around to update the existing menus
instead of rebuilding them completely.
(ns_activate_menubar):
([EmacsMenu trackingNotification:]):
([EmacsMenu menuWillOpen:]):
([EmacsMenu menuDidClose:]): Remove unused functions.
([EmacsMenu menuNeedsUpdate:]): Remove menu tracking code and add code
to check whether an update is required.
([EmacsMenu fillWithWidgetValue:]):
([EmacsMenu addSubmenuWithTitle:]):
([EmacsMenu initWithTitle:]): Remove references to frame.
([EmacsMenu setFrame:]): Remove method.
([EmacsMenu clear]): Rename to removeAllItems.
([EmacsMenu removeAllItems]): Use built-in removeAllItems, if
available.
(syms_of_nsmenu): Remove tracking code.
* src/nsterm.m (ns_check_menu_open):
(ns_check_pending_open_menu):
(ns_create_terminal): Remove unused functions.
(ns_term_init): Get rid of menu tracking.
* src/nsterm.h (EmacsMenu): Remove frame, add needsUpdate and update
method definitions.

src/nsmenu.m
src/nsterm.h
src/nsterm.m

index efad978316edc8bc2e8f95c75fd1eb4e42756141..3f0cd0c6ed4b7c18992e56d83c2fc4b459e4bdd1 100644 (file)
@@ -47,21 +47,11 @@ Carbon version by Yamamoto Mitsuharu. */
 #endif
 
 
-#if 0
-/* Include lisp -> C common menu parsing code.  */
-#define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
-#include "nsmenu_common.c"
-#endif
-
 extern long context_menu_value;
 EmacsMenu *svcsMenu;
 /* Nonzero means a menu is currently active.  */
 static int popup_activated_flag;
 
-/* Nonzero means we are tracking and updating menus.  */
-static int trackingMenu;
-
-
 /* NOTE: toolbar implementation is at end,
    following complete menu implementation.  */
 
@@ -98,16 +88,18 @@ popup_activated (void)
     3) deep_p, submenu = non-nil: Update contents of a single submenu.
    -------------------------------------------------------------------------- */
 static void
-ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
+ns_update_menubar (struct frame *f, bool deep_p)
 {
   NSAutoreleasePool *pool;
-  id menu = [NSApp mainMenu];
-  static EmacsMenu *last_submenu = nil;
   BOOL needsSet = NO;
-  bool owfi;
+  id menu = [NSApp mainMenu];
+
   Lisp_Object items;
   widget_value *wv, *first_wv, *prev_wv = 0;
   int i;
+  int *submenu_start, *submenu_end;
+  bool *submenu_top_level_items;
+  int *submenu_n_panes;
 
 #if NSMENUPROFILE
   struct timeb tb;
@@ -141,115 +133,94 @@ ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
   t = -(1000*tb.time+tb.millitm);
 #endif
 
-#ifdef NS_IMPL_GNUSTEP
-  deep_p = 1; /* until GNUstep NSMenu implements the Panther delegation model */
-#endif
-
   if (deep_p)
     {
-      /* Fully parse one or more of the submenus.  */
-      int n = 0;
-      int *submenu_start, *submenu_end;
-      bool *submenu_top_level_items;
-      int *submenu_n_panes;
+      /* Make a widget-value tree representing the entire menu trees.  */
+
       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);
+      int subitems;
 
-      /* lisp preliminaries */
       buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
       specbind (Qinhibit_quit, Qt);
+      /* Don't let the debugger step into this code
+        because it is not reentrant.  */
       specbind (Qdebug_on_next_call, Qnil);
+
       record_unwind_save_match_data ();
       if (NILP (Voverriding_local_map_menu_flag))
        {
          specbind (Qoverriding_terminal_local_map, Qnil);
          specbind (Qoverriding_local_map, Qnil);
        }
-      set_buffer_internal_1 (XBUFFER (buffer));
 
-      /* 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;
+      set_buffer_internal_1 (XBUFFER (buffer));
 
-      /* lucid hook and possible reset */
+      /* Run the Lucid hook.  */
       safe_run_hooks (Qactivate_menubar_hook);
+
+      /* If it has changed current-menubar from previous value,
+        really recompute the menubar from the value.  */
       if (! NILP (Vlucid_menu_bar_dirty_flag))
        call0 (Qrecompute_lucid_menubar);
       safe_run_hooks (Qmenu_bar_update_hook);
       fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
 
-      /* Now ready to go */
       items = FRAME_MENU_BAR_ITEMS (f);
 
-      /* Save the frame's previous menu bar contents data */
+      /* Save the frame's previous menu bar contents data */
       if (previous_menu_items_used)
-       memcpy (previous_items, aref_addr (f->menu_bar_vector, 0),
-               previous_menu_items_used * sizeof (Lisp_Object));
+       memcpy (previous_items, xvector_contents (f->menu_bar_vector),
+               previous_menu_items_used * word_size);
 
-      /* parse stage 1: extract from lisp */
+      /* Fill in menu_items with the current menu bar contents.
+        This can evaluate Lisp code.  */
       save_menu_items ();
 
       menu_items = f->menu_bar_vector;
       menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
-      submenu_start = alloca (ASIZE (items) * sizeof *submenu_start);
-      submenu_end = alloca (ASIZE (items) * sizeof *submenu_end);
-      submenu_n_panes = alloca (ASIZE (items) * sizeof *submenu_n_panes);
-      submenu_top_level_items = alloca (ASIZE (items)
+      subitems = ASIZE (items) / 4;
+      submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
+      submenu_end = alloca (subitems * sizeof *submenu_end);
+      submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
+      submenu_top_level_items = alloca (subitems
                                        * sizeof *submenu_top_level_items);
       init_menu_items ();
-      for (i = 0; i < ASIZE (items); i += 4)
+      for (i = 0; i < subitems; i++)
        {
          Lisp_Object key, string, maps;
 
-         key = AREF (items, i);
-         string = AREF (items, i + 1);
-         maps = AREF (items, i + 2);
+         key = AREF (items, 4 * i);
+         string = AREF (items, 4 * i + 1);
+         maps = AREF (items, 4 * i + 2);
          if (NILP (string))
            break;
 
-          /* 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 ([[submenu title] UTF8String], SSDATA (string)))
-               continue; */
-
          submenu_start[i] = menu_items_used;
 
          menu_items_n_panes = 0;
-         submenu_top_level_items[i] = parse_single_submenu (key, string, maps);
+         submenu_top_level_items[i]
+           = parse_single_submenu (key, string, maps);
          submenu_n_panes[i] = menu_items_n_panes;
+
          submenu_end[i] = menu_items_used;
-          n++;
        }
 
+      submenu_start[i] = -1;
       finish_menu_items ();
-      waiting_for_input = owfi;
 
+      /* Convert menu_items into widget_value trees
+        to display the menu.  This cannot evaluate Lisp code.  */
 
-      if (submenu && n == 0)
-        {
-          /* should have found a menu for this one but didn't */
-          fprintf (stderr, "ERROR: did not find lisp menu for submenu '%s'.\n",
-                  [[submenu title] UTF8String]);
-         discard_menu_items ();
-         unbind_to (specpdl_count, Qnil);
-          unblock_input ();
-         return;
-        }
-
-      /* parse stage 2: insert into lucid 'widget_value' structures
-         [comments in other terms say not to evaluate lisp code here] */
       wv = make_widget_value ("menubar", NULL, true, Qnil);
       wv->button_type = BUTTON_TYPE_NONE;
       first_wv = wv;
 
-      for (i = 0; i < 4*n; i += 4)
+      for (i = 0; submenu_start[i] >= 0; i++)
        {
          menu_items_n_panes = submenu_n_panes[i];
          wv = digest_single_submenu (submenu_start[i], submenu_end[i],
@@ -259,169 +230,79 @@ ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
          else
            first_wv->contents = wv;
          /* Don't set wv->name here; GC during the loop might relocate it.  */
-         wv->enabled = 1;
+         wv->enabled = true;
          wv->button_type = BUTTON_TYPE_NONE;
          prev_wv = wv;
        }
 
       set_buffer_internal_1 (prev);
 
-      /* Compare the new menu items with previous, and leave off if no change.  */
-      /* 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++)
-            /* 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], AREF (menu_items, i)))
-              if (!(STRINGP (previous_items[i])
-                    && STRINGP (AREF (menu_items, i))
-                    && !strcmp (SSDATA (previous_items[i]),
-                               SSDATA (AREF (menu_items, i)))))
-                  break;
-          if (i == previous_menu_items_used)
-            {
-              /* No change.  */
+      /* If there has been no change in the Lisp-level contents
+        of the menu bar, skip redisplaying it.  Just exit.  */
 
-#if NSMENUPROFILE
-              ftime (&tb);
-              t += 1000*tb.time+tb.millitm;
-              fprintf (stderr, "NO CHANGE!  CUTTING OUT after %ld msec.\n", t);
-#endif
+      /* Compare the new menu items with the ones computed last time.  */
+      for (i = 0; i < previous_menu_items_used; i++)
+       if (menu_items_used == i
+           || (!EQ (previous_items[i], AREF (menu_items, i))))
+         break;
+      if (i == menu_items_used && i == previous_menu_items_used && i != 0)
+       {
+         /* The menu items have not changed.  Don't bother updating
+            the menus in any form, since it would be a no-op.  */
+         free_menubar_widget_value_tree (first_wv);
+         discard_menu_items ();
+         unbind_to (specpdl_count, Qnil);
+         return;
+       }
 
-              free_menubar_widget_value_tree (first_wv);
-              discard_menu_items ();
-              unbind_to (specpdl_count, Qnil);
-              unblock_input ();
-              return;
-            }
-        }
       /* The menu items are different, so store them in the frame.  */
-      /* FIXME: this is not correct for single-submenu case.  */
       fset_menu_bar_vector (f, menu_items);
       f->menu_bar_items_used = menu_items_used;
 
-      /* Calls restore_menu_items, etc., as they were outside.  */
+      /* This undoes save_menu_items.  */
       unbind_to (specpdl_count, Qnil);
 
-      /* 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.  */
+      /* Now GC cannot happen during the lifetime of the widget_value,
+        so it's safe to store data from a Lisp_String.  */
       wv = first_wv->contents;
       for (i = 0; i < ASIZE (items); i += 4)
        {
          Lisp_Object string;
          string = AREF (items, i + 1);
          if (NILP (string))
-           break;
-
-         wv->name = SSDATA (string);
+            break;
+          wv->name = SSDATA (string);
           update_submenu_strings (wv->contents);
-         wv = wv->next;
+          wv = wv->next;
        }
 
-      /* Now, update the NS menu; if we have a submenu, use that, otherwise
-         create a new menu for each sub and fill it.  */
-      if (submenu)
-        {
-          const char *submenuTitle = [[submenu title] UTF8String];
-          for (wv = first_wv->contents; wv; wv = wv->next)
-            {
-              if (!strcmp (submenuTitle, wv->name))
-                {
-                  [submenu fillWithWidgetValue: wv->contents];
-                  last_submenu = submenu;
-                  break;
-                }
-            }
-        }
-      else
-        {
-          [menu fillWithWidgetValue: first_wv->contents frame: f];
-        }
-
     }
   else
     {
-      static int n_previous_strings = 0;
-      static char previous_strings[100][10];
-      static struct frame *last_f = NULL;
-      int n;
-      Lisp_Object string;
+      /* Make a widget-value tree containing
+        just the top level menu bar strings.  */
 
       wv = make_widget_value ("menubar", NULL, true, Qnil);
       wv->button_type = BUTTON_TYPE_NONE;
       first_wv = wv;
 
-      /* Make widget-value tree with just the top level menu bar strings.  */
       items = FRAME_MENU_BAR_ITEMS (f);
-      if (NILP (items))
-        {
-          free_menubar_widget_value_tree (first_wv);
-          unblock_input ();
-          return;
-        }
-
-
-      /* Check if no change: this mechanism is a bit rough, but ready.  */
-      n = ASIZE (items) / 4;
-      if (f == last_f && n_previous_strings == n)
-        {
-          for (i = 0; i<n; i++)
-            {
-             string = AREF (items, 4*i+1);
-
-              if (EQ (string, make_fixnum (0))) // FIXME: Why???  --Stef
-                continue;
-              if (NILP (string))
-                {
-                  if (previous_strings[i][0])
-                    break;
-                  else
-                    continue;
-                }
-              else if (memcmp (previous_strings[i], SDATA (string),
-                         min (10, SBYTES (string) + 1)))
-                break;
-            }
-
-          if (i == n)
-            {
-              free_menubar_widget_value_tree (first_wv);
-              unblock_input ();
-              return;
-            }
-        }
-
-      [menu clear];
       for (i = 0; i < ASIZE (items); i += 4)
        {
+         Lisp_Object string;
+
          string = AREF (items, i + 1);
          if (NILP (string))
            break;
 
-          if (n < 100)
-           memcpy (previous_strings[i/4], SDATA (string),
-                    min (10, SBYTES (string) + 1));
-
          wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
          wv->button_type = BUTTON_TYPE_NONE;
+         /* This prevents lwlib from assuming this
+            menu item is really supposed to be empty.  */
+         /* The intptr_t cast avoids a warning.
+            This value just has to be different from small integers.  */
          wv->call_data = (void *) (intptr_t) (-1);
 
-#ifdef NS_IMPL_COCOA
-          /* We'll update the real copy under app menu when time comes.  */
-          if (!strcmp ("Services", wv->name))
-            {
-              /* But we need to make sure it will update on demand.  */
-              [svcsMenu setFrame: f];
-            }
-          else
-#endif
-          [menu addSubmenuWithTitle: wv->name forFrame: f];
-
          if (prev_wv)
            prev_wv->next = wv;
          else
@@ -429,15 +310,68 @@ ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
          prev_wv = wv;
        }
 
-      last_f = f;
-      if (n < 100)
-        n_previous_strings = n;
-      else
-        n_previous_strings = 0;
+      /* Forget what we thought we knew about what is in the
+        detailed contents of the menu bar menus.
+        Changing the top level always destroys the contents.  */
+      f->menu_bar_items_used = 0;
+    }
+
+  /* Now, update the NS menu.  */
+  if (deep_p)
+    {
+      /* This path is typically used when a menu has been clicked.  I
+         think Apple expect us to only update that one menu, however
+         to update one we need to do the hard work of parsing the
+         whole tree, so we may as well update them all.  */
+#ifdef NS_IMPL_COCOA
+      int i = 1;
+#else
+      int i = 0;
+#endif
+      for (wv = first_wv->contents; wv; wv = wv->next)
+        {
+          /* The contents of wv should match the top level menu.  */
+          EmacsMenu *submenu = (EmacsMenu*)[[menu itemAtIndex:i++] submenu];
 
+          [submenu fillWithWidgetValue: wv->contents];
+        }
     }
-  free_menubar_widget_value_tree (first_wv);
+  else
+    {
+      /* Make sure we skip the "application" menu, which is always the
+         first entry in our top-level menu.  */
+#ifdef NS_IMPL_COCOA
+      int i = 1;
+#else
+      int i = 0;
+#endif
+      for (wv = first_wv->contents; wv; wv = wv->next)
+        {
+          if (i < [menu numberOfItems])
+            {
+              NSString *titleStr = [NSString stringWithUTF8String: wv->name];
+              NSMenuItem *item = [menu itemAtIndex:i];
+              EmacsMenu *submenu = (EmacsMenu*)[item submenu];
 
+              [item setTitle:titleStr];
+              [submenu setTitle:titleStr];
+              [submenu removeAllItems];
+            }
+          else
+            [menu addSubmenuWithTitle: wv->name];
+
+          i += 1;
+        }
+
+      while (i < [menu numberOfItems])
+        {
+          /* Remove any extra items.  */
+          [menu removeItemAtIndex:i];
+        }
+    }
+
+
+  free_menubar_widget_value_tree (first_wv);
 
 #if NSMENUPROFILE
   ftime (&tb);
@@ -460,21 +394,10 @@ ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
 void
 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
 {
-  ns_update_menubar (f, deep_p, nil);
-}
-
-void
-ns_activate_menubar (struct frame *f)
-{
-#ifdef NS_IMPL_COCOA
-  ns_update_menubar (f, true, nil);
-  ns_check_pending_open_menu ();
-#endif
+  ns_update_menubar (f, deep_p);
 }
 
 
-
-
 /* ==========================================================================
 
     Menu: class implementation
@@ -490,97 +413,31 @@ ns_activate_menubar (struct frame *f)
 /* override designated initializer */
 - (instancetype)initWithTitle: (NSString *)title
 {
-  frame = 0;
   if ((self = [super initWithTitle: title]))
     [self setAutoenablesItems: NO];
-  return self;
-}
-
-
-/* used for top-level */
-- (instancetype)initWithTitle: (NSString *)title frame: (struct frame *)f
-{
-  [self initWithTitle: title];
-  frame = f;
-#ifdef NS_IMPL_COCOA
   [self setDelegate: self];
-#endif
-  return self;
-}
-
-
-- (void)setFrame: (struct frame *)f
-{
-  frame = f;
-}
-
-#ifdef NS_IMPL_COCOA
--(void)trackingNotification:(NSNotification *)notification
-{
-  /* Update menu in menuNeedsUpdate only while tracking menus.  */
-  trackingMenu = ([notification name] == NSMenuDidBeginTrackingNotification
-                  ? 1 : 0);
-  if (! trackingMenu) ns_check_menu_open (nil);
-}
-
-- (void)menuWillOpen:(NSMenu *)menu
-{
-  ++trackingMenu;
-
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
-  // On 10.6 we get repeated calls, only the one for NSSystemDefined is "real".
-  if (
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-      NSAppKitVersionNumber < NSAppKitVersionNumber10_7 &&
-#endif
-      [[NSApp currentEvent] type] != NSEventTypeSystemDefined)
-    return;
-#endif
 
-  /* When dragging from one menu to another, we get willOpen followed by didClose,
-     i.e. trackingMenu == 3 in willOpen and then 2 after didClose.
-     We have updated all menus, so avoid doing it when trackingMenu == 3.  */
-  if (trackingMenu == 2)
-    ns_check_menu_open (menu);
-}
+  needsUpdate = YES;
 
-- (void)menuDidClose:(NSMenu *)menu
-{
-  --trackingMenu;
+  return self;
 }
 
-#endif /* NS_IMPL_COCOA */
 
 /* Delegate method called when a submenu is being opened: run a 'deep' call
    to set_frame_menubar.  */
+
+/* TODO: GNUstep calls this method when the menu is still being built
+   which throws it into an infinite loop.  One possible solution is to
+   use menuWillOpen instead, but the Apple docs explicitly warn
+   against changing the contents of the menu in it.  I don't know what
+   the right thing to do for GNUstep is.  */
 - (void)menuNeedsUpdate: (NSMenu *)menu
 {
-  if (!FRAME_LIVE_P (frame))
+  if (!FRAME_LIVE_P (SELECTED_FRAME ()))
     return;
 
-  /* Cocoa/Carbon will request update on every keystroke
-     via IsMenuKeyEvent -> CheckMenusForKeyEvent.  These are not needed
-     since key equivalents are handled through emacs.
-     On Leopard, even keystroke events generate SystemDefined event.
-     Third-party applications that enhance mouse / trackpad
-     interaction, or also VNC/Remote Desktop will send events
-     of type AppDefined rather than SysDefined.
-     Menus will fail to show up if they haven't been initialized.
-     AppDefined events may lack timing data.
-
-     Thus, we rely on the didBeginTrackingNotification notification
-     as above to indicate the need for updates.
-     From 10.6 on, we could also use -[NSMenu propertiesToUpdate]: In the
-     key press case, NSMenuPropertyItemImage (e.g.) won't be set.
-  */
-  if (trackingMenu == 0)
-    return;
-/*fprintf (stderr, "Updating menu '%s'\n", [[self title] UTF8String]); NSLog (@"%@\n", event); */
-#ifdef NS_IMPL_GNUSTEP
-  /* Don't know how to do this for anything other than Mac OS X 10.5 and later.
-     This is wrong, as it might run Lisp code in the event loop.  */
-  ns_update_menubar (frame, true, self);
-#endif
+  if (needsUpdate)
+    ns_update_menubar (SELECTED_FRAME (), true);
 }
 
 
@@ -674,8 +531,13 @@ ns_activate_menubar (struct frame *f)
 
 
 /* convenience */
--(void)clear
+-(void)removeAllItems
 {
+#ifdef NS_IMPL_COCOA
+  [super removeAllItems];
+#else
+  /* GNUstep doesn't have removeAllItems yet, so do it
+     manually.  */
   int n;
 
   for (n = [self numberOfItems]-1; n >= 0; n--)
@@ -687,20 +549,18 @@ ns_activate_menubar (struct frame *f)
         continue;
       [self removeItemAtIndex: n];
     }
+#endif
+
+  needsUpdate = YES;
 }
 
 
 - (void)fillWithWidgetValue: (void *)wvptr
-{
-  [self fillWithWidgetValue: wvptr frame: (struct frame *)nil];
-}
-
-- (void)fillWithWidgetValue: (void *)wvptr frame: (struct frame *)f
 {
   widget_value *wv = (widget_value *)wvptr;
 
   /* clear existing contents */
-  [self clear];
+  [self removeAllItems];
 
   /* add new contents */
   for (; wv != NULL; wv = wv->next)
@@ -711,10 +571,7 @@ ns_activate_menubar (struct frame *f)
         {
           EmacsMenu *submenu;
 
-          if (f)
-            submenu = [[EmacsMenu alloc] initWithTitle: [item title] frame:f];
-          else
-            submenu = [[EmacsMenu alloc] initWithTitle: [item title]];
+          submenu = [[EmacsMenu alloc] initWithTitle: [item title]];
 
           [self setSubmenu: submenu forItem: item];
           [submenu fillWithWidgetValue: wv->contents];
@@ -723,6 +580,8 @@ ns_activate_menubar (struct frame *f)
         }
     }
 
+  needsUpdate = NO;
+
 #ifdef NS_IMPL_GNUSTEP
   if ([[self window] isVisible])
     [self sizeToFit];
@@ -731,13 +590,13 @@ ns_activate_menubar (struct frame *f)
 
 
 /* Adds an empty submenu and returns it.  */
-- (EmacsMenu *)addSubmenuWithTitle: (const char *)title forFrame: (struct frame *)f
+- (EmacsMenu *)addSubmenuWithTitle: (const char *)title
 {
   NSString *titleStr = [NSString stringWithUTF8String: title];
   NSMenuItem *item = [self addItemWithTitle: titleStr
                                      action: (SEL)nil /*@selector (menuDown:) */
                               keyEquivalent: @""];
-  EmacsMenu *submenu = [[EmacsMenu alloc] initWithTitle: titleStr frame: f];
+  EmacsMenu *submenu = [[EmacsMenu alloc] initWithTitle: titleStr];
   [self setSubmenu: submenu forItem: item];
   [submenu release];
   return submenu;
@@ -1881,12 +1740,6 @@ DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_
 void
 syms_of_nsmenu (void)
 {
-#ifndef NS_IMPL_COCOA
-  /* Don't know how to keep track of this in Next/Open/GNUstep.  Always
-     update menus there.  */
-  trackingMenu = 1;
-  PDUMPER_REMEMBER_SCALAR (trackingMenu);
-#endif
   defsubr (&Sns_reset_menu);
   defsubr (&Smenu_or_popup_active_p);
 
index 94472ec107047362e569ab4bbe3d83ea84df53cd..b7b4d3b047c3be1432ecbd02b4f75e4ba5b66b99 100644 (file)
@@ -513,25 +513,18 @@ typedef id instancetype;
 
    ========================================================================== */
 
-#ifdef NS_IMPL_COCOA
 @interface EmacsMenu : NSMenu  <NSMenuDelegate>
-#else
-@interface EmacsMenu : NSMenu
-#endif
 {
-  struct frame *frame;
   unsigned long keyEquivModMask;
+  BOOL needsUpdate;
 }
 
-- (instancetype)initWithTitle: (NSString *)title frame: (struct frame *)f;
-- (void)setFrame: (struct frame *)f;
 - (void)menuNeedsUpdate: (NSMenu *)menu; /* (delegate method) */
 - (NSString *)parseKeyEquiv: (const char *)key;
 - (NSMenuItem *)addItemWithWidgetValue: (void *)wvptr;
 - (void)fillWithWidgetValue: (void *)wvptr;
-- (void)fillWithWidgetValue: (void *)wvptr frame: (struct frame *)f;
-- (EmacsMenu *)addSubmenuWithTitle: (const char *)title forFrame: (struct frame *)f;
-- (void) clear;
+- (EmacsMenu *)addSubmenuWithTitle: (const char *)title;
+- (void) removeAllItems;
 - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f
                  keymaps: (bool)keymaps;
 @end
@@ -1130,8 +1123,6 @@ extern int ns_lisp_to_color (Lisp_Object color, NSColor **col);
 extern NSColor *ns_lookup_indexed_color (unsigned long idx, struct frame *f);
 extern unsigned long ns_index_color (NSColor *color, struct frame *f);
 extern const char *ns_get_pending_menu_title (void);
-extern void ns_check_menu_open (NSMenu *menu);
-extern void ns_check_pending_open_menu (void);
 #endif
 
 /* Implemented in nsfns, published in nsterm.  */
index 2a117a078012164280ee36fc0da1e87cc3a721b4..161677484f95ffbe793682525946146ac07ee873 100644 (file)
@@ -310,24 +310,6 @@ static struct {
   NULL, 0, 0
 };
 
-#ifdef NS_IMPL_COCOA
-/*
- * State for pending menu activation:
- * MENU_NONE     Normal state
- * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
- *               run lisp to update the menu.
- * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
- *               will open.
- */
-#define MENU_NONE 0
-#define MENU_PENDING 1
-#define MENU_OPENING 2
-static int menu_will_open_state = MENU_NONE;
-
-/* Saved position for menu click.  */
-static CGPoint menu_mouse_point;
-#endif
-
 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
 #define NS_FUNCTION_KEY_MASK 0x800000
 #define NSLeftControlKeyMask    (0x000001 | NSEventModifierFlagControl)
@@ -4607,79 +4589,6 @@ check_native_fs ()
 }
 #endif
 
-/* GNUstep does not have cancelTracking.  */
-#ifdef NS_IMPL_COCOA
-/* Check if menu open should be canceled or continued as normal.  */
-void
-ns_check_menu_open (NSMenu *menu)
-{
-  /* Click in menu bar?  */
-  NSArray *a = [[NSApp mainMenu] itemArray];
-  int i;
-  BOOL found = NO;
-
-  if (menu == nil) // Menu tracking ended.
-    {
-      if (menu_will_open_state == MENU_OPENING)
-        menu_will_open_state = MENU_NONE;
-      return;
-    }
-
-  for (i = 0; ! found && i < [a count]; i++)
-    found = menu == [[a objectAtIndex:i] submenu];
-  if (found)
-    {
-      if (menu_will_open_state == MENU_NONE && emacs_event)
-        {
-          NSEvent *theEvent = [NSApp currentEvent];
-          struct frame *emacsframe = SELECTED_FRAME ();
-
-          /* On macOS, the following can cause an event loop when the
-             Spotlight for Help search field is populated.  Avoid this by
-             not postponing mouse drag and non-user-generated mouse down
-             events (Bug#31371).  */
-          if (([theEvent type] == NSEventTypeLeftMouseDown)
-              && [theEvent eventNumber])
-            {
-              [menu cancelTracking];
-              menu_will_open_state = MENU_PENDING;
-              emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
-              EV_TRAILER (theEvent);
-
-              CGEventRef ourEvent = CGEventCreate (NULL);
-              menu_mouse_point = CGEventGetLocation (ourEvent);
-              CFRelease (ourEvent);
-            }
-        }
-      else if (menu_will_open_state == MENU_OPENING)
-        {
-          menu_will_open_state = MENU_NONE;
-        }
-    }
-}
-
-/* Redo saved menu click if state is MENU_PENDING.  */
-void
-ns_check_pending_open_menu ()
-{
-  if (menu_will_open_state == MENU_PENDING)
-    {
-      CGEventSourceRef source
-        = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
-
-      CGEventRef event = CGEventCreateMouseEvent (source,
-                                                  kCGEventLeftMouseDown,
-                                                  menu_mouse_point,
-                                                  kCGMouseButtonLeft);
-      CGEventSetType (event, kCGEventLeftMouseDown);
-      CGEventPost (kCGHIDEventTap, event);
-      CFRelease (event);
-      CFRelease (source);
-
-      menu_will_open_state = MENU_OPENING;
-    }
-}
-#endif /* NS_IMPL_COCOA */
 
 static int
 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
@@ -5416,7 +5325,6 @@ ns_create_terminal (struct ns_display_info *dpyinfo)
   terminal->set_new_font_hook = ns_new_font;
   terminal->implicit_set_name_hook = ns_implicitly_set_name;
   terminal->menu_show_hook = ns_menu_show;
-  terminal->activate_menubar_hook = ns_activate_menubar;
   terminal->popup_dialog_hook = ns_popup_dialog;
   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
@@ -5661,15 +5569,6 @@ ns_term_init (Lisp_Object display_name)
     [NSApp setServicesMenu: svcsMenu];
     /* Needed at least on Cocoa, to get dock menu to show windows */
     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
-
-    [[NSNotificationCenter defaultCenter]
-      addObserver: mainMenu
-         selector: @selector (trackingNotification:)
-             name: NSMenuDidBeginTrackingNotification object: mainMenu];
-    [[NSNotificationCenter defaultCenter]
-      addObserver: mainMenu
-         selector: @selector (trackingNotification:)
-             name: NSMenuDidEndTrackingNotification object: mainMenu];
   }
 #endif /* macOS menu setup */