1 /* NeXT/Open/GNUstep and macOS Cocoa menu and toolbar module.
2 Copyright (C) 2007-2017 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or (at
9 your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 By Adrian Robert, based on code from original nsmenu.m (Carl Edman,
21 Christian Limpach, Scott Bender, Christophe de Dinechin) and code in the
22 Carbon version by Yamamoto Mitsuharu. */
24 /* This should be the first include, as it may set up #defines affecting
25 interpretation of even the system includes. */
30 #include "character.h"
35 #include "blockinput.h"
37 #include "termhooks.h"
41 #define NSMENUPROFILE 0
44 #include <sys/timeb.h>
45 #include <sys/types.h>
50 /* Include lisp -> C common menu parsing code */
51 #define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
52 #include "nsmenu_common.c"
55 extern long context_menu_value;
57 /* Nonzero means a menu is currently active. */
58 static int popup_activated_flag;
60 /* Nonzero means we are tracking and updating menus. */
61 static int trackingMenu;
64 /* NOTE: toolbar implementation is at end,
65 following complete menu implementation. */
68 /* ==========================================================================
70 Menu: Externally-called functions
72 ========================================================================== */
75 /* Supposed to discard menubar and free storage. Since we share the
76 menubar among frames and update its context for the focused window,
77 there is nothing to do here. */
79 free_frame_menubar (struct frame *f)
86 popup_activated (void)
88 return popup_activated_flag;
92 /* --------------------------------------------------------------------------
93 Update menubar. Three cases:
94 1) ! deep_p, submenu = nil: Fresh switch onto a frame -- either set up
95 just top-level menu strings (macOS), or goto case (2) (GNUstep).
96 2) deep_p, submenu = nil: Recompute all submenus.
97 3) deep_p, submenu = non-nil: Update contents of a single submenu.
98 -------------------------------------------------------------------------- */
100 ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
102 NSAutoreleasePool *pool;
103 id menu = [NSApp mainMenu];
104 static EmacsMenu *last_submenu = nil;
108 widget_value *wv, *first_wv, *prev_wv = 0;
116 NSTRACE ("ns_update_menubar");
118 if (f != SELECTED_FRAME ())
120 XSETFRAME (Vmenu_updating_frame, f);
121 /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */
124 pool = [[NSAutoreleasePool alloc] init];
126 /* Menu may have been created automatically; if so, discard it. */
127 if ([menu isKindOfClass: [EmacsMenu class]] == NO)
135 menu = [[EmacsMenu alloc] initWithTitle: ns_app_name];
141 t = -(1000*tb.time+tb.millitm);
144 #ifdef NS_IMPL_GNUSTEP
145 deep_p = 1; /* until GNUstep NSMenu implements the Panther delegation model */
150 /* Fully parse one or more of the submenus. */
152 int *submenu_start, *submenu_end;
153 bool *submenu_top_level_items;
154 int *submenu_n_panes;
155 struct buffer *prev = current_buffer;
157 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
158 int previous_menu_items_used = f->menu_bar_items_used;
159 Lisp_Object *previous_items
160 = alloca (previous_menu_items_used * sizeof *previous_items);
162 /* lisp preliminaries */
163 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
164 specbind (Qinhibit_quit, Qt);
165 specbind (Qdebug_on_next_call, Qnil);
166 record_unwind_save_match_data ();
167 if (NILP (Voverriding_local_map_menu_flag))
169 specbind (Qoverriding_terminal_local_map, Qnil);
170 specbind (Qoverriding_local_map, Qnil);
172 set_buffer_internal_1 (XBUFFER (buffer));
174 /* TODO: for some reason this is not needed in other terms,
175 but some menu updates call Info-extract-pointer which causes
176 abort-on-error if waiting-for-input. Needs further investigation. */
177 owfi = waiting_for_input;
178 waiting_for_input = 0;
180 /* lucid hook and possible reset */
181 safe_run_hooks (Qactivate_menubar_hook);
182 if (! NILP (Vlucid_menu_bar_dirty_flag))
183 call0 (Qrecompute_lucid_menubar);
184 safe_run_hooks (Qmenu_bar_update_hook);
185 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
187 /* Now ready to go */
188 items = FRAME_MENU_BAR_ITEMS (f);
190 /* Save the frame's previous menu bar contents data */
191 if (previous_menu_items_used)
192 memcpy (previous_items, aref_addr (f->menu_bar_vector, 0),
193 previous_menu_items_used * sizeof (Lisp_Object));
195 /* parse stage 1: extract from lisp */
198 menu_items = f->menu_bar_vector;
199 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
200 submenu_start = alloca (ASIZE (items) * sizeof *submenu_start);
201 submenu_end = alloca (ASIZE (items) * sizeof *submenu_end);
202 submenu_n_panes = alloca (ASIZE (items) * sizeof *submenu_n_panes);
203 submenu_top_level_items = alloca (ASIZE (items)
204 * sizeof *submenu_top_level_items);
206 for (i = 0; i < ASIZE (items); i += 4)
208 Lisp_Object key, string, maps;
210 key = AREF (items, i);
211 string = AREF (items, i + 1);
212 maps = AREF (items, i + 2);
216 /* FIXME: we'd like to only parse the needed submenu, but this
217 was causing crashes in the _common parsing code.. need to make
218 sure proper initialization done.. */
219 /* if (submenu && strcmp ([[submenu title] UTF8String], SSDATA (string)))
222 submenu_start[i] = menu_items_used;
224 menu_items_n_panes = 0;
225 submenu_top_level_items[i] = parse_single_submenu (key, string, maps);
226 submenu_n_panes[i] = menu_items_n_panes;
227 submenu_end[i] = menu_items_used;
231 finish_menu_items ();
232 waiting_for_input = owfi;
235 if (submenu && n == 0)
237 /* should have found a menu for this one but didn't */
238 fprintf (stderr, "ERROR: did not find lisp menu for submenu '%s'.\n",
239 [[submenu title] UTF8String]);
240 discard_menu_items ();
241 unbind_to (specpdl_count, Qnil);
247 /* parse stage 2: insert into lucid 'widget_value' structures
248 [comments in other terms say not to evaluate lisp code here] */
249 wv = make_widget_value ("menubar", NULL, true, Qnil);
250 wv->button_type = BUTTON_TYPE_NONE;
253 for (i = 0; i < 4*n; i += 4)
255 menu_items_n_panes = submenu_n_panes[i];
256 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
257 submenu_top_level_items[i]);
261 first_wv->contents = wv;
262 /* Don't set wv->name here; GC during the loop might relocate it. */
264 wv->button_type = BUTTON_TYPE_NONE;
268 set_buffer_internal_1 (prev);
270 /* Compare the new menu items with previous, and leave off if no change */
271 /* FIXME: following other terms here, but seems like this should be
272 done before parse stage 2 above, since its results aren't used */
273 if (previous_menu_items_used
274 && (!submenu || (submenu && submenu == last_submenu))
275 && menu_items_used == previous_menu_items_used)
277 for (i = 0; i < previous_menu_items_used; i++)
278 /* FIXME: this ALWAYS fails on Buffers menu items.. something
279 about their strings causes them to change every time, so we
280 double-check failures */
281 if (!EQ (previous_items[i], AREF (menu_items, i)))
282 if (!(STRINGP (previous_items[i])
283 && STRINGP (AREF (menu_items, i))
284 && !strcmp (SSDATA (previous_items[i]),
285 SSDATA (AREF (menu_items, i)))))
287 if (i == previous_menu_items_used)
293 t += 1000*tb.time+tb.millitm;
294 fprintf (stderr, "NO CHANGE! CUTTING OUT after %ld msec.\n", t);
297 free_menubar_widget_value_tree (first_wv);
298 discard_menu_items ();
299 unbind_to (specpdl_count, Qnil);
305 /* The menu items are different, so store them in the frame */
306 /* FIXME: this is not correct for single-submenu case */
307 fset_menu_bar_vector (f, menu_items);
308 f->menu_bar_items_used = menu_items_used;
310 /* Calls restore_menu_items, etc., as they were outside */
311 unbind_to (specpdl_count, Qnil);
313 /* Parse stage 2a: now GC cannot happen during the lifetime of the
314 widget_value, so it's safe to store data from a Lisp_String */
315 wv = first_wv->contents;
316 for (i = 0; i < ASIZE (items); i += 4)
319 string = AREF (items, i + 1);
323 wv->name = SSDATA (string);
324 update_submenu_strings (wv->contents);
328 /* Now, update the NS menu; if we have a submenu, use that, otherwise
329 create a new menu for each sub and fill it. */
332 const char *submenuTitle = [[submenu title] UTF8String];
333 for (wv = first_wv->contents; wv; wv = wv->next)
335 if (!strcmp (submenuTitle, wv->name))
337 [submenu fillWithWidgetValue: wv->contents];
338 last_submenu = submenu;
345 [menu fillWithWidgetValue: first_wv->contents frame: f];
351 static int n_previous_strings = 0;
352 static char previous_strings[100][10];
353 static struct frame *last_f = NULL;
357 wv = make_widget_value ("menubar", NULL, true, Qnil);
358 wv->button_type = BUTTON_TYPE_NONE;
361 /* Make widget-value tree w/ just the top level menu bar strings */
362 items = FRAME_MENU_BAR_ITEMS (f);
365 free_menubar_widget_value_tree (first_wv);
372 /* check if no change.. this mechanism is a bit rough, but ready */
373 n = ASIZE (items) / 4;
374 if (f == last_f && n_previous_strings == n)
376 for (i = 0; i<n; i++)
378 string = AREF (items, 4*i+1);
380 if (EQ (string, make_number (0))) // FIXME: Why??? --Stef
384 if (previous_strings[i][0])
389 else if (memcmp (previous_strings[i], SDATA (string),
390 min (10, SBYTES (string) + 1)))
396 free_menubar_widget_value_tree (first_wv);
404 for (i = 0; i < ASIZE (items); i += 4)
406 string = AREF (items, i + 1);
411 memcpy (previous_strings[i/4], SDATA (string),
412 min (10, SBYTES (string) + 1));
414 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
415 wv->button_type = BUTTON_TYPE_NONE;
416 wv->call_data = (void *) (intptr_t) (-1);
419 /* we'll update the real copy under app menu when time comes */
420 if (!strcmp ("Services", wv->name))
422 /* but we need to make sure it will update on demand */
423 [svcsMenu setFrame: f];
427 [menu addSubmenuWithTitle: wv->name forFrame: f];
432 first_wv->contents = wv;
438 n_previous_strings = n;
440 n_previous_strings = 0;
443 free_menubar_widget_value_tree (first_wv);
448 t += 1000*tb.time+tb.millitm;
449 fprintf (stderr, "Menu update took %ld msec.\n", t);
454 [NSApp setMainMenu: menu];
462 /* Main emacs core entry point for menubar menus: called to indicate that the
463 frame's menus have changed, and the *step representation should be updated
466 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
468 ns_update_menubar (f, deep_p, nil);
472 x_activate_menubar (struct frame *f)
475 ns_update_menubar (f, true, nil);
476 ns_check_pending_open_menu ();
483 /* ==========================================================================
485 Menu: class implementation
487 ========================================================================== */
490 /* Menu that can define itself from Emacs "widget_value"s and will lazily
491 update itself when user clicked. Based on Carbon/AppKit implementation
492 by Yamamoto Mitsuharu. */
493 @implementation EmacsMenu
495 /* override designated initializer */
496 - initWithTitle: (NSString *)title
499 if ((self = [super initWithTitle: title]))
500 [self setAutoenablesItems: NO];
505 /* used for top-level */
506 - initWithTitle: (NSString *)title frame: (struct frame *)f
508 [self initWithTitle: title];
511 [self setDelegate: self];
517 - (void)setFrame: (struct frame *)f
523 -(void)trackingNotification:(NSNotification *)notification
525 /* Update menu in menuNeedsUpdate only while tracking menus. */
526 trackingMenu = ([notification name] == NSMenuDidBeginTrackingNotification
528 if (! trackingMenu) ns_check_menu_open (nil);
531 - (void)menuWillOpen:(NSMenu *)menu
535 #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
536 // On 10.6 we get repeated calls, only the one for NSSystemDefined is "real".
537 if ([[NSApp currentEvent] type] != NSSystemDefined) return;
540 /* When dragging from one menu to another, we get willOpen followed by didClose,
541 i.e. trackingMenu == 3 in willOpen and then 2 after didClose.
542 We have updated all menus, so avoid doing it when trackingMenu == 3. */
543 if (trackingMenu == 2)
544 ns_check_menu_open (menu);
547 - (void)menuDidClose:(NSMenu *)menu
552 #endif /* NS_IMPL_COCOA */
554 /* delegate method called when a submenu is being opened: run a 'deep' call
555 to set_frame_menubar */
556 - (void)menuNeedsUpdate: (NSMenu *)menu
558 if (!FRAME_LIVE_P (frame))
561 /* Cocoa/Carbon will request update on every keystroke
562 via IsMenuKeyEvent -> CheckMenusForKeyEvent. These are not needed
563 since key equivalents are handled through emacs.
564 On Leopard, even keystroke events generate SystemDefined event.
565 Third-party applications that enhance mouse / trackpad
566 interaction, or also VNC/Remote Desktop will send events
567 of type AppDefined rather than SysDefined.
568 Menus will fail to show up if they haven't been initialized.
569 AppDefined events may lack timing data.
571 Thus, we rely on the didBeginTrackingNotification notification
572 as above to indicate the need for updates.
573 From 10.6 on, we could also use -[NSMenu propertiesToUpdate]: In the
574 key press case, NSMenuPropertyItemImage (e.g.) won't be set.
576 if (trackingMenu == 0)
578 /*fprintf (stderr, "Updating menu '%s'\n", [[self title] UTF8String]); NSLog (@"%@\n", event); */
579 #ifdef NS_IMPL_GNUSTEP
580 /* Don't know how to do this for anything other than Mac OS X 10.5 and later.
581 This is wrong, as it might run Lisp code in the event loop. */
582 ns_update_menubar (frame, true, self);
587 - (BOOL)performKeyEquivalent: (NSEvent *)theEvent
589 if (SELECTED_FRAME () && FRAME_NS_P (SELECTED_FRAME ())
590 && FRAME_NS_VIEW (SELECTED_FRAME ()))
591 [FRAME_NS_VIEW (SELECTED_FRAME ()) keyDown: theEvent];
596 /* Parse a widget_value's key rep (examples: 's-p', 's-S', '(C-x C-s)', '<f13>')
597 into an accelerator string. We are only able to display a single character
598 for an accelerator, together with an optional modifier combination. (Under
599 Carbon more control was possible, but in Cocoa multi-char strings passed to
600 NSMenuItem get ignored. For now we try to display a super-single letter
601 combo, and return the others as strings to be appended to the item title.
602 (This is signaled by setting keyEquivModMask to 0 for now.) */
603 -(NSString *)parseKeyEquiv: (const char *)key
605 const char *tpos = key;
606 keyEquivModMask = NSEventModifierFlagCommand;
608 if (!key || !strlen (key))
611 while (*tpos == ' ' || *tpos == '(')
613 if ((*tpos == 's') && (*(tpos+1) == '-'))
615 return [NSString stringWithFormat: @"%c", tpos[2]];
617 keyEquivModMask = 0; /* signal */
618 return [NSString stringWithUTF8String: tpos];
622 - (NSMenuItem *)addItemWithWidgetValue: (void *)wvptr
625 widget_value *wv = (widget_value *)wvptr;
627 if (menu_separator_name_p (wv->name))
629 item = [NSMenuItem separatorItem];
630 [self addItem: item];
634 NSString *title, *keyEq;
635 title = [NSString stringWithUTF8String: wv->name];
637 title = @"< ? >"; /* (get out in the open so we know about it) */
639 keyEq = [self parseKeyEquiv: wv->key];
641 /* macOS just ignores modifier strings longer than one character */
642 if (keyEquivModMask == 0)
643 title = [title stringByAppendingFormat: @" (%@)", keyEq];
646 item = [self addItemWithTitle: (NSString *)title
647 action: @selector (menuDown:)
648 keyEquivalent: keyEq];
649 [item setKeyEquivalentModifierMask: keyEquivModMask];
651 [item setEnabled: wv->enabled];
653 /* Draw radio buttons and tickboxes */
654 if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
655 wv->button_type == BUTTON_TYPE_RADIO))
656 [item setState: NSOnState];
658 [item setState: NSOffState];
660 [item setTag: (NSInteger)wv->call_data];
672 for (n = [self numberOfItems]-1; n >= 0; n--)
674 NSMenuItem *item = [self itemAtIndex: n];
675 NSString *title = [item title];
676 if ([ns_app_name isEqualToString: title]
677 && ![item isSeparatorItem])
679 [self removeItemAtIndex: n];
684 - (void)fillWithWidgetValue: (void *)wvptr
686 [self fillWithWidgetValue: wvptr frame: (struct frame *)nil];
689 - (void)fillWithWidgetValue: (void *)wvptr frame: (struct frame *)f
691 widget_value *wv = (widget_value *)wvptr;
693 /* clear existing contents */
696 /* add new contents */
697 for (; wv != NULL; wv = wv->next)
699 NSMenuItem *item = [self addItemWithWidgetValue: wv];
706 submenu = [[EmacsMenu alloc] initWithTitle: [item title] frame:f];
708 submenu = [[EmacsMenu alloc] initWithTitle: [item title]];
710 [self setSubmenu: submenu forItem: item];
711 [submenu fillWithWidgetValue: wv->contents];
713 [item setAction: (SEL)nil];
717 #ifdef NS_IMPL_GNUSTEP
718 if ([[self window] isVisible])
724 /* adds an empty submenu and returns it */
725 - (EmacsMenu *)addSubmenuWithTitle: (const char *)title forFrame: (struct frame *)f
727 NSString *titleStr = [NSString stringWithUTF8String: title];
728 NSMenuItem *item = [self addItemWithTitle: titleStr
729 action: (SEL)nil /*@selector (menuDown:) */
731 EmacsMenu *submenu = [[EmacsMenu alloc] initWithTitle: titleStr frame: f];
732 [self setSubmenu: submenu forItem: item];
737 /* run a menu in popup mode */
738 - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f
739 keymaps: (bool)keymaps
741 EmacsView *view = FRAME_NS_VIEW (f);
745 /* p = [view convertPoint:p fromView: nil]; */
746 p.y = NSHeight ([view frame]) - p.y;
747 e = [[view window] currentEvent];
748 event = [NSEvent mouseEventWithType: NSEventTypeRightMouseDown
751 timestamp: [e timestamp]
752 windowNumber: [[view window] windowNumber]
754 eventNumber: 0/*[e eventNumber] */
758 context_menu_value = -1;
759 [NSMenu popUpContextMenu: self withEvent: event forView: view];
760 retVal = context_menu_value;
761 context_menu_value = 0;
763 ? find_and_return_menu_selection (f, keymaps, (void *)retVal)
771 /* ==========================================================================
773 Context Menu: implementing functions
775 ========================================================================== */
778 ns_menu_show (struct frame *f, int x, int y, int menuflags,
779 Lisp_Object title, const char **error)
784 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
785 widget_value *wv, *first_wv = 0;
786 bool keymaps = (menuflags & MENU_KEYMAPS);
788 NSTRACE ("ns_menu_show");
794 /* now parse stage 2 as in ns_update_menubar */
795 wv = make_widget_value ("contextmenu", NULL, true, Qnil);
796 wv->button_type = BUTTON_TYPE_NONE;
800 /* FIXME: a couple of one-line differences prevent reuse */
801 wv = digest_single_submenu (0, menu_items_used, 0);
804 widget_value *save_wv = 0, *prev_wv = 0;
805 widget_value **submenu_stack
806 = alloca (menu_items_used * sizeof *submenu_stack);
807 /* Lisp_Object *subprefix_stack
808 = alloca (menu_items_used * sizeof *subprefix_stack); */
809 int submenu_depth = 0;
813 /* Loop over all panes and items, filling in the tree. */
815 while (i < menu_items_used)
817 if (EQ (AREF (menu_items, i), Qnil))
819 submenu_stack[submenu_depth++] = save_wv;
825 else if (EQ (AREF (menu_items, i), Qlambda))
828 save_wv = submenu_stack[--submenu_depth];
832 else if (EQ (AREF (menu_items, i), Qt)
833 && submenu_depth != 0)
834 i += MENU_ITEMS_PANE_LENGTH;
835 /* Ignore a nil in the item list.
836 It's meaningful only for dialog boxes. */
837 else if (EQ (AREF (menu_items, i), Qquote))
839 else if (EQ (AREF (menu_items, i), Qt))
841 /* Create a new pane. */
842 Lisp_Object pane_name, prefix;
843 const char *pane_string;
845 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
846 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
848 #ifndef HAVE_MULTILINGUAL_MENU
849 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
851 pane_name = ENCODE_MENU_STRING (pane_name);
852 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
855 pane_string = (NILP (pane_name)
856 ? "" : SSDATA (pane_name));
857 /* If there is just one top-level pane, put all its items directly
858 under the top-level menu. */
859 if (menu_items_n_panes == 1)
862 /* If the pane has a meaningful name,
863 make the pane a top-level menu item
864 with its items as a submenu beneath it. */
865 if (!keymaps && strcmp (pane_string, ""))
867 wv = make_widget_value (pane_string, NULL, true, Qnil);
871 first_wv->contents = wv;
872 if (keymaps && !NILP (prefix))
874 wv->button_type = BUTTON_TYPE_NONE;
884 i += MENU_ITEMS_PANE_LENGTH;
888 /* Create a new item within current pane. */
889 Lisp_Object item_name, enable, descrip, def, type, selected, help;
890 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
891 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
892 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
893 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
894 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
895 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
896 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
898 #ifndef HAVE_MULTILINGUAL_MENU
899 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
901 item_name = ENCODE_MENU_STRING (item_name);
902 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
905 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
907 descrip = ENCODE_MENU_STRING (descrip);
908 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
910 #endif /* not HAVE_MULTILINGUAL_MENU */
912 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
913 STRINGP (help) ? help : Qnil);
917 save_wv->contents = wv;
919 wv->key = SSDATA (descrip);
920 /* If this item has a null value,
921 make the call_data null so that it won't display a box
922 when the mouse is on it. */
923 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
926 wv->button_type = BUTTON_TYPE_NONE;
927 else if (EQ (type, QCtoggle))
928 wv->button_type = BUTTON_TYPE_TOGGLE;
929 else if (EQ (type, QCradio))
930 wv->button_type = BUTTON_TYPE_RADIO;
934 wv->selected = !NILP (selected);
938 i += MENU_ITEMS_ITEM_LENGTH;
946 widget_value *wv_title;
947 widget_value *wv_sep = make_widget_value ("--", NULL, false, Qnil);
949 /* Maybe replace this separator with a bitmap or owner-draw item
950 so that it looks better. Having two separators looks odd. */
951 wv_sep->next = first_wv->contents;
953 #ifndef HAVE_MULTILINGUAL_MENU
954 if (STRING_MULTIBYTE (title))
955 title = ENCODE_MENU_STRING (title);
957 wv_title = make_widget_value (SSDATA (title), NULL, false, Qnil);
958 wv_title->button_type = BUTTON_TYPE_NONE;
959 wv_title->next = wv_sep;
960 first_wv->contents = wv_title;
963 pmenu = [[EmacsMenu alloc] initWithTitle:
964 [NSString stringWithUTF8String: SSDATA (title)]];
965 [pmenu fillWithWidgetValue: first_wv->contents];
966 free_menubar_widget_value_tree (first_wv);
967 unbind_to (specpdl_count, Qnil);
969 popup_activated_flag = 1;
970 tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps];
971 popup_activated_flag = 0;
972 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
979 /* ==========================================================================
981 Toolbar: externally-called functions
983 ========================================================================== */
986 free_frame_tool_bar (struct frame *f)
987 /* --------------------------------------------------------------------------
988 Under NS we just hide the toolbar until it might be needed again.
989 -------------------------------------------------------------------------- */
991 EmacsView *view = FRAME_NS_VIEW (f);
993 NSTRACE ("free_frame_tool_bar");
996 view->wait_for_tool_bar = NO;
998 FRAME_TOOLBAR_HEIGHT (f) = 0;
1000 /* Note: This trigger an animation, which calls windowDidResize
1002 f->output_data.ns->in_animation = 1;
1003 [[view toolbar] setVisible: NO];
1004 f->output_data.ns->in_animation = 0;
1010 update_frame_tool_bar (struct frame *f)
1011 /* --------------------------------------------------------------------------
1012 Update toolbar contents
1013 -------------------------------------------------------------------------- */
1016 EmacsView *view = FRAME_NS_VIEW (f);
1017 NSWindow *window = [view window];
1018 EmacsToolbar *toolbar = [view toolbar];
1021 NSTRACE ("update_frame_tool_bar");
1023 if (view == nil || toolbar == nil) return;
1026 oldh = FRAME_TOOLBAR_HEIGHT (f);
1028 #ifdef NS_IMPL_COCOA
1029 [toolbar clearActive];
1034 /* update EmacsToolbar as in GtkUtils, build items list */
1035 for (i = 0; i < f->n_tool_bar_items; ++i)
1037 #define TOOLPROP(IDX) AREF (f->tool_bar_items, \
1038 i * TOOL_BAR_ITEM_NSLOTS + (IDX))
1040 BOOL enabled_p = !NILP (TOOLPROP (TOOL_BAR_ITEM_ENABLED_P));
1045 Lisp_Object helpObj;
1046 const char *helpText;
1048 /* Check if this is a separator. */
1049 if (EQ (TOOLPROP (TOOL_BAR_ITEM_TYPE), Qt))
1051 /* Skip separators. Newer macOS don't show them, and on
1052 GNUstep they are wide as a button, thus overflowing the
1053 toolbar most of the time. */
1057 /* If image is a vector, choose the image according to the
1059 image = TOOLPROP (TOOL_BAR_ITEM_IMAGES);
1060 if (VECTORP (image))
1062 /* NS toolbar auto-computes disabled and selected images */
1063 idx = TOOL_BAR_IMAGE_ENABLED_SELECTED;
1064 eassert (ASIZE (image) >= idx);
1065 image = AREF (image, idx);
1071 helpObj = TOOLPROP (TOOL_BAR_ITEM_HELP);
1073 helpObj = TOOLPROP (TOOL_BAR_ITEM_CAPTION);
1074 helpText = NILP (helpObj) ? "" : SSDATA (helpObj);
1076 /* Ignore invalid image specifications. */
1077 if (!valid_image_p (image))
1079 /* Don't log anything, GNUS makes invalid images all the time. */
1083 img_id = lookup_image (f, image);
1084 img = IMAGE_FROM_ID (f, img_id);
1085 prepare_image_for_display (f, img);
1087 if (img->load_failed_p || img->pixmap == nil)
1089 NSLog (@"Could not prepare toolbar image for display.");
1093 [toolbar addDisplayItemWithImage: img->pixmap
1097 enabled: enabled_p];
1101 if (![toolbar isVisible])
1103 f->output_data.ns->in_animation = 1;
1104 [toolbar setVisible: YES];
1105 f->output_data.ns->in_animation = 0;
1108 #ifdef NS_IMPL_COCOA
1109 if ([toolbar changed])
1111 /* inform app that toolbar has changed */
1112 NSDictionary *dict = [toolbar configurationDictionary];
1113 NSMutableDictionary *newDict = [dict mutableCopy];
1114 NSEnumerator *keys = [[dict allKeys] objectEnumerator];
1116 while ((key = [keys nextObject]) != nil)
1118 NSObject *val = [dict objectForKey: key];
1119 if ([val isKindOfClass: [NSArray class]])
1122 [toolbar toolbarDefaultItemIdentifiers: toolbar]
1127 [toolbar setConfigurationFromDictionary: newDict];
1132 FRAME_TOOLBAR_HEIGHT (f) =
1133 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1134 - FRAME_NS_TITLEBAR_HEIGHT (f);
1135 if (FRAME_TOOLBAR_HEIGHT (f) < 0) // happens if frame is fullscreen.
1136 FRAME_TOOLBAR_HEIGHT (f) = 0;
1138 if (oldh != FRAME_TOOLBAR_HEIGHT (f))
1139 [view updateFrameSize:YES];
1140 if (view->wait_for_tool_bar && FRAME_TOOLBAR_HEIGHT (f) > 0)
1142 view->wait_for_tool_bar = NO;
1143 [view setNeedsDisplay: YES];
1150 /* ==========================================================================
1152 Toolbar: class implementation
1154 ========================================================================== */
1156 @implementation EmacsToolbar
1158 - initForView: (EmacsView *)view withIdentifier: (NSString *)identifier
1160 NSTRACE ("[EmacsToolbar initForView: withIdentifier:]");
1162 self = [super initWithIdentifier: identifier];
1164 [self setDisplayMode: NSToolbarDisplayModeIconOnly];
1165 [self setSizeMode: NSToolbarSizeModeSmall];
1166 [self setDelegate: self];
1167 identifierToItem = [[NSMutableDictionary alloc] initWithCapacity: 10];
1168 activeIdentifiers = [[NSMutableArray alloc] initWithCapacity: 8];
1169 prevIdentifiers = nil;
1170 prevEnablement = enablement = 0L;
1176 NSTRACE ("[EmacsToolbar dealloc]");
1178 [prevIdentifiers release];
1179 [activeIdentifiers release];
1180 [identifierToItem release];
1184 - (void) clearActive
1186 NSTRACE ("[EmacsToolbar clearActive]");
1188 [prevIdentifiers release];
1189 prevIdentifiers = [activeIdentifiers copy];
1190 [activeIdentifiers removeAllObjects];
1191 prevEnablement = enablement;
1197 NSTRACE ("[EmacsToolbar clearAll]");
1200 while ([[self items] count] > 0)
1201 [self removeItemAtIndex: 0];
1206 NSTRACE ("[EmacsToolbar changed]");
1208 return [activeIdentifiers isEqualToArray: prevIdentifiers] &&
1209 enablement == prevEnablement ? NO : YES;
1212 - (void) addDisplayItemWithImage: (EmacsImage *)img
1215 helpText: (const char *)help
1216 enabled: (BOOL)enabled
1218 NSTRACE ("[EmacsToolbar addDisplayItemWithImage: ...]");
1220 /* 1) come up w/identifier */
1221 NSString *identifier
1222 = [NSString stringWithFormat: @"%lu", (unsigned long)[img hash]];
1223 [activeIdentifiers addObject: identifier];
1225 /* 2) create / reuse item */
1226 NSToolbarItem *item = [identifierToItem objectForKey: identifier];
1229 item = [[[NSToolbarItem alloc] initWithItemIdentifier: identifier]
1231 [item setImage: img];
1232 [item setToolTip: [NSString stringWithUTF8String: help]];
1233 [item setTarget: emacsView];
1234 [item setAction: @selector (toolbarClicked:)];
1235 [identifierToItem setObject: item forKey: identifier];
1238 #ifdef NS_IMPL_GNUSTEP
1239 [self insertItemWithItemIdentifier: identifier atIndex: idx];
1243 [item setEnabled: enabled];
1245 /* 3) update state */
1246 enablement = (enablement << 1) | (enabled == YES);
1249 /* This overrides super's implementation, which automatically sets
1250 all items to enabled state (for some reason). */
1251 - (void)validateVisibleItems
1253 NSTRACE ("[EmacsToolbar validateVisibleItems]");
1257 /* delegate methods */
1259 - (NSToolbarItem *)toolbar: (NSToolbar *)toolbar
1260 itemForItemIdentifier: (NSString *)itemIdentifier
1261 willBeInsertedIntoToolbar: (BOOL)flag
1263 NSTRACE ("[EmacsToolbar toolbar: ...]");
1265 /* look up NSToolbarItem by identifier and return... */
1266 return [identifierToItem objectForKey: itemIdentifier];
1269 - (NSArray *)toolbarDefaultItemIdentifiers: (NSToolbar *)toolbar
1271 NSTRACE ("[EmacsToolbar toolbarDefaultItemIdentifiers:]");
1273 /* return entire set.. */
1274 return activeIdentifiers;
1277 /* for configuration palette (not yet supported) */
1278 - (NSArray *)toolbarAllowedItemIdentifiers: (NSToolbar *)toolbar
1280 NSTRACE ("[EmacsToolbar toolbarAllowedItemIdentifiers:]");
1282 /* return entire set... */
1283 return activeIdentifiers;
1284 //return [identifierToItem allKeys];
1287 - (void)setVisible:(BOOL)shown
1289 NSTRACE ("[EmacsToolbar setVisible:%d]", shown);
1291 [super setVisible:shown];
1295 /* optional and unneeded */
1296 /* - toolbarWillAddItem: (NSNotification *)notification { } */
1297 /* - toolbarDidRemoveItem: (NSNotification *)notification { } */
1298 /* - (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar */
1300 @end /* EmacsToolbar */
1304 /* ==========================================================================
1306 Tooltip: class implementation
1308 ========================================================================== */
1310 /* Needed because NeXTstep does not provide enough control over tooltip
1312 @implementation EmacsTooltip
1316 NSColor *col = [NSColor colorWithCalibratedRed: 1.0 green: 1.0
1317 blue: 0.792 alpha: 0.95];
1318 NSFont *font = [NSFont toolTipsFontOfSize: 0];
1319 NSFont *sfont = [font screenFont];
1320 int height = [sfont ascender] - [sfont descender];
1321 /*[font boundingRectForFont].size.height; */
1322 NSRect r = NSMakeRect (0, 0, 100, height+6);
1324 textField = [[NSTextField alloc] initWithFrame: r];
1325 [textField setFont: font];
1326 [textField setBackgroundColor: col];
1328 [textField setEditable: NO];
1329 [textField setSelectable: NO];
1330 [textField setBordered: NO];
1331 [textField setBezeled: NO];
1332 [textField setDrawsBackground: YES];
1334 win = [[NSWindow alloc]
1335 initWithContentRect: [textField frame]
1337 backing: NSBackingStoreBuffered
1339 [win setHasShadow: YES];
1340 [win setReleasedWhenClosed: NO];
1341 [win setDelegate: self];
1342 [[win contentView] addSubview: textField];
1343 /* [win setBackgroundColor: col]; */
1344 [win setOpaque: NO];
1353 [textField release];
1357 - (void) setText: (char *)text
1359 NSString *str = [NSString stringWithUTF8String: text];
1360 NSRect r = [textField frame];
1363 [textField setStringValue: str];
1364 tooltipDims = [[textField cell] cellSize];
1366 r.size.width = tooltipDims.width;
1367 r.size.height = tooltipDims.height;
1368 [textField setFrame: r];
1371 - (void) showAtX: (int)x Y: (int)y for: (int)seconds
1373 NSRect wr = [win frame];
1375 wr.origin = NSMakePoint (x, y);
1376 wr.size = [textField frame].size;
1378 [win setFrame: wr display: YES];
1379 [win setLevel: NSPopUpMenuWindowLevel];
1380 [win orderFront: self];
1382 timer = [NSTimer scheduledTimerWithTimeInterval: (float)seconds target: self
1383 selector: @selector (hide)
1384 userInfo: nil repeats: NO];
1393 if ([timer isValid])
1402 return timer != nil;
1407 return [textField frame];
1410 @end /* EmacsTooltip */
1414 /* ==========================================================================
1416 Popup Dialog: implementing functions
1418 ========================================================================== */
1421 pop_down_menu (void *arg)
1423 EmacsDialogPanel *panel = arg;
1425 if (popup_activated_flag)
1428 popup_activated_flag = 0;
1430 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
1437 ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1440 Lisp_Object tem, title;
1444 NSTRACE ("ns_popup_dialog");
1446 isQ = NILP (header);
1448 check_window_system (f);
1450 p.x = (int)f->left_pos + ((int)FRAME_COLUMN_WIDTH (f) * f->text_cols)/2;
1451 p.y = (int)f->top_pos + (FRAME_LINE_HEIGHT (f) * f->text_lines)/2;
1453 title = Fcar (contents);
1454 CHECK_STRING (title);
1456 if (NILP (Fcar (Fcdr (contents))))
1457 /* No buttons specified, add an "Ok" button so users can pop down
1459 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1462 dialog = [[EmacsDialogPanel alloc] initFromContents: contents
1466 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1468 record_unwind_protect_ptr (pop_down_menu, dialog);
1469 popup_activated_flag = 1;
1470 tem = [dialog runDialogAt: p];
1471 unbind_to (specpdl_count, Qnil); /* calls pop_down_menu */
1480 /* ==========================================================================
1482 Popup Dialog: class implementation
1484 ========================================================================== */
1486 @interface FlippedView : NSView
1491 @implementation FlippedView
1498 @implementation EmacsDialogPanel
1501 #define ICONSIZE 64.0
1502 #define TEXTHEIGHT 20.0
1503 #define MINCELLWIDTH 90.0
1505 - initWithContentRect: (NSRect)contentRect styleMask: (NSUInteger)aStyle
1506 backing: (NSBackingStoreType)backingType defer: (BOOL)flag
1508 NSSize spacing = {SPACER, SPACER};
1511 NSImageView *imgView;
1512 FlippedView *contentView;
1515 dialog_return = Qundefined;
1516 button_values = NULL;
1517 area.origin.x = 3*SPACER;
1518 area.origin.y = 2*SPACER;
1519 area.size.width = ICONSIZE;
1520 area.size.height= ICONSIZE;
1521 img = [[NSImage imageNamed: @"NSApplicationIcon"] copy];
1522 #ifdef NS_IMPL_COCOA
1523 #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
1524 [img setScalesWhenResized: YES];
1527 [img setSize: NSMakeSize (ICONSIZE, ICONSIZE)];
1528 imgView = [[NSImageView alloc] initWithFrame: area];
1529 [imgView setImage: img];
1530 [imgView setEditable: NO];
1532 [imgView autorelease];
1534 aStyle = NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSUtilityWindowMask;
1538 [super initWithContentRect: contentRect styleMask: aStyle
1539 backing: backingType defer: flag];
1540 contentView = [[FlippedView alloc] initWithFrame: [[self contentView] frame]];
1541 [contentView autorelease];
1543 [self setContentView: contentView];
1545 [[self contentView] setAutoresizesSubviews: YES];
1547 [[self contentView] addSubview: imgView];
1548 [self setTitle: @""];
1550 area.origin.x += ICONSIZE+2*SPACER;
1551 /* area.origin.y = TEXTHEIGHT; ICONSIZE/2-10+SPACER; */
1552 area.size.width = 400;
1553 area.size.height= TEXTHEIGHT;
1554 command = [[[NSTextField alloc] initWithFrame: area] autorelease];
1555 [[self contentView] addSubview: command];
1556 [command setStringValue: ns_app_name];
1557 [command setDrawsBackground: NO];
1558 [command setBezeled: NO];
1559 [command setSelectable: NO];
1560 [command setFont: [NSFont boldSystemFontOfSize: 13.0]];
1562 /* area.origin.x = ICONSIZE+2*SPACER;
1563 area.origin.y = TEXTHEIGHT + 2*SPACER;
1564 area.size.width = 400;
1565 area.size.height= 2;
1566 tem = [[[NSBox alloc] initWithFrame: area] autorelease];
1567 [[self contentView] addSubview: tem];
1568 [tem setTitlePosition: NSNoTitle];
1569 [tem setAutoresizingMask: NSViewWidthSizable];*/
1571 /* area.origin.x = ICONSIZE+2*SPACER; */
1572 area.origin.y += TEXTHEIGHT+SPACER;
1573 area.size.width = 400;
1574 area.size.height= TEXTHEIGHT;
1575 title = [[[NSTextField alloc] initWithFrame: area] autorelease];
1576 [[self contentView] addSubview: title];
1577 [title setDrawsBackground: NO];
1578 [title setBezeled: NO];
1579 [title setSelectable: NO];
1580 [title setFont: [NSFont systemFontOfSize: 11.0]];
1582 cell = [[[NSButtonCell alloc] initTextCell: @""] autorelease];
1583 [cell setBordered: NO];
1584 [cell setEnabled: NO];
1585 [cell setCellAttribute: NSCellIsInsetButton to: 8];
1586 [cell setBezelStyle: NSRoundedBezelStyle];
1588 matrix = [[NSMatrix alloc] initWithFrame: contentRect
1589 mode: NSHighlightModeMatrix
1592 numberOfColumns: 1];
1593 [matrix setFrameOrigin: NSMakePoint (area.origin.x,
1594 area.origin.y + (TEXTHEIGHT+3*SPACER))];
1595 [matrix setIntercellSpacing: spacing];
1596 [matrix autorelease];
1598 [[self contentView] addSubview: matrix];
1599 [self setOneShot: YES];
1600 [self setReleasedWhenClosed: YES];
1601 [self setHidesOnDeactivate: YES];
1606 - (BOOL)windowShouldClose: (id)sender
1608 window_closed = YES;
1615 xfree (button_values);
1619 - (void)process_dialog: (Lisp_Object) list
1621 Lisp_Object item, lst = list;
1623 int buttons = 0, btnnr = 0;
1625 for (; XTYPE (lst) == Lisp_Cons; lst = XCDR (lst))
1628 if (XTYPE (item) == Lisp_Cons)
1633 button_values = xmalloc (buttons * sizeof *button_values);
1635 for (; XTYPE (list) == Lisp_Cons; list = XCDR (list))
1638 if (XTYPE (item) == Lisp_String)
1640 [self addString: SSDATA (item) row: row++];
1642 else if (XTYPE (item) == Lisp_Cons)
1644 button_values[btnnr] = XCDR (item);
1645 [self addButton: SSDATA (XCAR (item)) value: btnnr row: row++];
1648 else if (NILP (item))
1657 - (void)addButton: (char *)str value: (int)tag row: (int)row
1666 cell = [matrix cellAtRow: row column: cols-1];
1667 [cell setTarget: self];
1668 [cell setAction: @selector (clicked: )];
1669 [cell setTitle: [NSString stringWithUTF8String: str]];
1671 [cell setBordered: YES];
1672 [cell setEnabled: YES];
1676 - (void)addString: (char *)str row: (int)row
1685 cell = [matrix cellAtRow: row column: cols-1];
1686 [cell setTitle: [NSString stringWithUTF8String: str]];
1687 [cell setBordered: YES];
1688 [cell setEnabled: NO];
1699 - (void)clicked: sender
1701 NSArray *sellist = nil;
1704 sellist = [sender selectedCells];
1705 if ([sellist count] < 1)
1708 seltag = [[sellist objectAtIndex: 0] tag];
1709 dialog_return = button_values[seltag];
1714 - initFromContents: (Lisp_Object)contents isQuestion: (BOOL)isQ
1719 if (XTYPE (contents) == Lisp_Cons)
1721 head = Fcar (contents);
1722 [self process_dialog: Fcdr (contents)];
1727 if (XTYPE (head) == Lisp_String)
1728 [title setStringValue:
1729 [NSString stringWithUTF8String: SSDATA (head)]];
1730 else if (isQ == YES)
1731 [title setStringValue: @"Question"];
1733 [title setStringValue: @"Information"];
1739 if (cols == 1 && rows > 1) /* Never told where to split */
1742 for (i = 0; i < rows/2; i++)
1744 [matrix putCell: [matrix cellAtRow: (rows+1)/2 column: 0]
1745 atRow: i column: 1];
1746 [matrix removeRow: (rows+1)/2];
1752 NSSize csize = [matrix cellSize];
1753 if (csize.width < MINCELLWIDTH)
1755 csize.width = MINCELLWIDTH;
1756 [matrix setCellSize: csize];
1757 [matrix sizeToCells];
1762 [command sizeToFit];
1766 if (r.size.width+r.origin.x > t.size.width+t.origin.x)
1768 t.origin.x = r.origin.x;
1769 t.size.width = r.size.width;
1771 r = [command frame];
1772 if (r.size.width+r.origin.x > t.size.width+t.origin.x)
1774 t.origin.x = r.origin.x;
1775 t.size.width = r.size.width;
1779 s = [(NSView *)[self contentView] frame];
1780 r.size.width += t.origin.x+t.size.width +2*SPACER-s.size.width;
1781 r.size.height += t.origin.y+t.size.height+SPACER-s.size.height;
1782 [self setFrame: r display: NO];
1790 - (void)timeout_handler: (NSTimer *)timedEntry
1792 NSEvent *nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
1793 location: NSMakePoint (0, 0)
1796 windowNumber: [[NSApp mainWindow] windowNumber]
1797 context: [NSApp context]
1803 /* We use sto because stopModal/abortModal out of the main loop does not
1804 seem to work in 10.6. But as we use stop we must send a real event so
1805 the stop is seen and acted upon. */
1807 [NSApp postEvent: nxev atStart: NO];
1810 - (Lisp_Object)runDialogAt: (NSPoint)p
1812 Lisp_Object ret = Qundefined;
1814 while (popup_activated_flag)
1817 struct timespec next_time = timer_check ();
1819 if (timespec_valid_p (next_time))
1821 double time = timespectod (next_time);
1822 tmo = [NSTimer timerWithTimeInterval: time
1824 selector: @selector (timeout_handler:)
1827 [[NSRunLoop currentRunLoop] addTimer: tmo
1828 forMode: NSModalPanelRunLoopMode];
1831 dialog_return = Qundefined;
1832 [NSApp runModalForWindow: self];
1833 ret = dialog_return;
1836 if (tmo != nil) [tmo invalidate]; /* Cancels timer */
1841 if (EQ (ret, Qundefined) && window_closed)
1842 /* Make close button pressed equivalent to C-g. */
1851 /* ==========================================================================
1855 ========================================================================== */
1857 DEFUN ("ns-reset-menu", Fns_reset_menu, Sns_reset_menu, 0, 0, 0,
1858 doc: /* Cause the NS menu to be re-calculated. */)
1861 set_frame_menubar (SELECTED_FRAME (), 1, 0);
1866 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
1867 doc: /* Return t if a menu or popup dialog is active. */)
1870 return popup_activated () ? Qt : Qnil;
1873 /* ==========================================================================
1875 Lisp interface declaration
1877 ========================================================================== */
1880 syms_of_nsmenu (void)
1882 #ifndef NS_IMPL_COCOA
1883 /* Don't know how to keep track of this in Next/Open/GNUstep. Always
1884 update menus there. */
1887 defsubr (&Sns_reset_menu);
1888 defsubr (&Smenu_or_popup_active_p);
1890 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");