1 /* NeXT/Open/GNUstep and MacOSX Cocoa menu and toolbar module.
2 Copyright (C) 2007-2016 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;
56 EmacsMenu *mainMenu, *svcsMenu, *dockMenu;
58 /* Nonzero means a menu is currently active. */
59 static int popup_activated_flag;
61 /* Nonzero means we are tracking and updating menus. */
62 static int trackingMenu;
65 /* NOTE: toolbar implementation is at end,
66 following complete menu implementation. */
69 /* ==========================================================================
71 Menu: Externally-called functions
73 ========================================================================== */
76 /* Supposed to discard menubar and free storage. Since we share the
77 menubar among frames and update its context for the focused window,
78 there is nothing to do here. */
80 free_frame_menubar (struct frame *f)
87 popup_activated (void)
89 return popup_activated_flag;
93 /* --------------------------------------------------------------------------
94 Update menubar. Three cases:
95 1) ! deep_p, submenu = nil: Fresh switch onto a frame -- either set up
96 just top-level menu strings (OS X), or goto case (2) (GNUstep).
97 2) deep_p, submenu = nil: Recompute all submenus.
98 3) deep_p, submenu = non-nil: Update contents of a single submenu.
99 -------------------------------------------------------------------------- */
101 ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
103 NSAutoreleasePool *pool;
104 id menu = [NSApp mainMenu];
105 static EmacsMenu *last_submenu = nil;
109 widget_value *wv, *first_wv, *prev_wv = 0;
117 NSTRACE ("ns_update_menubar");
119 if (f != SELECTED_FRAME ())
121 XSETFRAME (Vmenu_updating_frame, f);
122 /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */
125 pool = [[NSAutoreleasePool alloc] init];
127 /* Menu may have been created automatically; if so, discard it. */
128 if ([menu isKindOfClass: [EmacsMenu class]] == NO)
136 menu = [[EmacsMenu alloc] initWithTitle: ns_app_name];
142 t = -(1000*tb.time+tb.millitm);
145 #ifdef NS_IMPL_GNUSTEP
146 deep_p = 1; /* until GNUstep NSMenu implements the Panther delegation model */
151 /* Fully parse one or more of the submenus. */
153 int *submenu_start, *submenu_end;
154 bool *submenu_top_level_items;
155 int *submenu_n_panes;
156 struct buffer *prev = current_buffer;
158 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
159 int previous_menu_items_used = f->menu_bar_items_used;
160 Lisp_Object *previous_items
161 = alloca (previous_menu_items_used * sizeof *previous_items);
163 /* lisp preliminaries */
164 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
165 specbind (Qinhibit_quit, Qt);
166 specbind (Qdebug_on_next_call, Qnil);
167 record_unwind_save_match_data ();
168 if (NILP (Voverriding_local_map_menu_flag))
170 specbind (Qoverriding_terminal_local_map, Qnil);
171 specbind (Qoverriding_local_map, Qnil);
173 set_buffer_internal_1 (XBUFFER (buffer));
175 /* TODO: for some reason this is not needed in other terms,
176 but some menu updates call Info-extract-pointer which causes
177 abort-on-error if waiting-for-input. Needs further investigation. */
178 owfi = waiting_for_input;
179 waiting_for_input = 0;
181 /* lucid hook and possible reset */
182 safe_run_hooks (Qactivate_menubar_hook);
183 if (! NILP (Vlucid_menu_bar_dirty_flag))
184 call0 (Qrecompute_lucid_menubar);
185 safe_run_hooks (Qmenu_bar_update_hook);
186 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
188 /* Now ready to go */
189 items = FRAME_MENU_BAR_ITEMS (f);
191 /* Save the frame's previous menu bar contents data */
192 if (previous_menu_items_used)
193 memcpy (previous_items, aref_addr (f->menu_bar_vector, 0),
194 previous_menu_items_used * sizeof (Lisp_Object));
196 /* parse stage 1: extract from lisp */
199 menu_items = f->menu_bar_vector;
200 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
201 submenu_start = alloca (ASIZE (items) * sizeof *submenu_start);
202 submenu_end = alloca (ASIZE (items) * sizeof *submenu_end);
203 submenu_n_panes = alloca (ASIZE (items) * sizeof *submenu_n_panes);
204 submenu_top_level_items = alloca (ASIZE (items)
205 * sizeof *submenu_top_level_items);
207 for (i = 0; i < ASIZE (items); i += 4)
209 Lisp_Object key, string, maps;
211 key = AREF (items, i);
212 string = AREF (items, i + 1);
213 maps = AREF (items, i + 2);
217 /* FIXME: we'd like to only parse the needed submenu, but this
218 was causing crashes in the _common parsing code.. need to make
219 sure proper initialization done.. */
220 /* if (submenu && strcmp ([[submenu title] UTF8String], SSDATA (string)))
223 submenu_start[i] = menu_items_used;
225 menu_items_n_panes = 0;
226 submenu_top_level_items[i] = parse_single_submenu (key, string, maps);
227 submenu_n_panes[i] = menu_items_n_panes;
228 submenu_end[i] = menu_items_used;
232 finish_menu_items ();
233 waiting_for_input = owfi;
236 if (submenu && n == 0)
238 /* should have found a menu for this one but didn't */
239 fprintf (stderr, "ERROR: did not find lisp menu for submenu '%s'.\n",
240 [[submenu title] UTF8String]);
241 discard_menu_items ();
242 unbind_to (specpdl_count, Qnil);
248 /* parse stage 2: insert into lucid 'widget_value' structures
249 [comments in other terms say not to evaluate lisp code here] */
250 wv = make_widget_value ("menubar", NULL, true, Qnil);
251 wv->button_type = BUTTON_TYPE_NONE;
254 for (i = 0; i < 4*n; i += 4)
256 menu_items_n_panes = submenu_n_panes[i];
257 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
258 submenu_top_level_items[i]);
262 first_wv->contents = wv;
263 /* Don't set wv->name here; GC during the loop might relocate it. */
265 wv->button_type = BUTTON_TYPE_NONE;
269 set_buffer_internal_1 (prev);
271 /* Compare the new menu items with previous, and leave off if no change */
272 /* FIXME: following other terms here, but seems like this should be
273 done before parse stage 2 above, since its results aren't used */
274 if (previous_menu_items_used
275 && (!submenu || (submenu && submenu == last_submenu))
276 && menu_items_used == previous_menu_items_used)
278 for (i = 0; i < previous_menu_items_used; i++)
279 /* FIXME: this ALWAYS fails on Buffers menu items.. something
280 about their strings causes them to change every time, so we
281 double-check failures */
282 if (!EQ (previous_items[i], AREF (menu_items, i)))
283 if (!(STRINGP (previous_items[i])
284 && STRINGP (AREF (menu_items, i))
285 && !strcmp (SSDATA (previous_items[i]),
286 SSDATA (AREF (menu_items, i)))))
288 if (i == previous_menu_items_used)
294 t += 1000*tb.time+tb.millitm;
295 fprintf (stderr, "NO CHANGE! CUTTING OUT after %ld msec.\n", t);
298 free_menubar_widget_value_tree (first_wv);
299 discard_menu_items ();
300 unbind_to (specpdl_count, Qnil);
306 /* The menu items are different, so store them in the frame */
307 /* FIXME: this is not correct for single-submenu case */
308 fset_menu_bar_vector (f, menu_items);
309 f->menu_bar_items_used = menu_items_used;
311 /* Calls restore_menu_items, etc., as they were outside */
312 unbind_to (specpdl_count, Qnil);
314 /* Parse stage 2a: now GC cannot happen during the lifetime of the
315 widget_value, so it's safe to store data from a Lisp_String */
316 wv = first_wv->contents;
317 for (i = 0; i < ASIZE (items); i += 4)
320 string = AREF (items, i + 1);
324 wv->name = SSDATA (string);
325 update_submenu_strings (wv->contents);
329 /* Now, update the NS menu; if we have a submenu, use that, otherwise
330 create a new menu for each sub and fill it. */
333 const char *submenuTitle = [[submenu title] UTF8String];
334 for (wv = first_wv->contents; wv; wv = wv->next)
336 if (!strcmp (submenuTitle, wv->name))
338 [submenu fillWithWidgetValue: wv->contents];
339 last_submenu = submenu;
346 [menu fillWithWidgetValue: first_wv->contents frame: f];
352 static int n_previous_strings = 0;
353 static char previous_strings[100][10];
354 static struct frame *last_f = NULL;
358 wv = make_widget_value ("menubar", NULL, true, Qnil);
359 wv->button_type = BUTTON_TYPE_NONE;
362 /* Make widget-value tree w/ just the top level menu bar strings */
363 items = FRAME_MENU_BAR_ITEMS (f);
366 free_menubar_widget_value_tree (first_wv);
373 /* check if no change.. this mechanism is a bit rough, but ready */
374 n = ASIZE (items) / 4;
375 if (f == last_f && n_previous_strings == n)
377 for (i = 0; i<n; i++)
379 string = AREF (items, 4*i+1);
381 if (EQ (string, make_number (0))) // FIXME: Why??? --Stef
385 if (previous_strings[i][0])
390 else if (memcmp (previous_strings[i], SDATA (string),
391 min (10, SBYTES (string) + 1)))
397 free_menubar_widget_value_tree (first_wv);
405 for (i = 0; i < ASIZE (items); i += 4)
407 string = AREF (items, i + 1);
412 memcpy (previous_strings[i/4], SDATA (string),
413 min (10, SBYTES (string) + 1));
415 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
416 wv->button_type = BUTTON_TYPE_NONE;
417 wv->call_data = (void *) (intptr_t) (-1);
420 /* we'll update the real copy under app menu when time comes */
421 if (!strcmp ("Services", wv->name))
423 /* but we need to make sure it will update on demand */
424 [svcsMenu setFrame: f];
428 [menu addSubmenuWithTitle: wv->name forFrame: f];
433 first_wv->contents = wv;
439 n_previous_strings = n;
441 n_previous_strings = 0;
444 free_menubar_widget_value_tree (first_wv);
449 t += 1000*tb.time+tb.millitm;
450 fprintf (stderr, "Menu update took %ld msec.\n", t);
455 [NSApp setMainMenu: menu];
463 /* Main emacs core entry point for menubar menus: called to indicate that the
464 frame's menus have changed, and the *step representation should be updated
467 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
469 ns_update_menubar (f, deep_p, nil);
473 x_activate_menubar (struct frame *f)
476 ns_update_menubar (f, true, nil);
477 ns_check_pending_open_menu ();
484 /* ==========================================================================
486 Menu: class implementation
488 ========================================================================== */
491 /* Menu that can define itself from Emacs "widget_value"s and will lazily
492 update itself when user clicked. Based on Carbon/AppKit implementation
493 by Yamamoto Mitsuharu. */
494 @implementation EmacsMenu
496 /* override designated initializer */
497 - initWithTitle: (NSString *)title
500 if ((self = [super initWithTitle: title]))
501 [self setAutoenablesItems: NO];
506 /* used for top-level */
507 - initWithTitle: (NSString *)title frame: (struct frame *)f
509 [self initWithTitle: title];
512 [self setDelegate: self];
518 - (void)setFrame: (struct frame *)f
524 -(void)trackingNotification:(NSNotification *)notification
526 /* Update menu in menuNeedsUpdate only while tracking menus. */
527 trackingMenu = ([notification name] == NSMenuDidBeginTrackingNotification
529 if (! trackingMenu) ns_check_menu_open (nil);
532 - (void)menuWillOpen:(NSMenu *)menu
536 #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
537 // On 10.6 we get repeated calls, only the one for NSSystemDefined is "real".
538 if ([[NSApp currentEvent] type] != NSSystemDefined) return;
541 /* When dragging from one menu to another, we get willOpen followed by didClose,
542 i.e. trackingMenu == 3 in willOpen and then 2 after didClose.
543 We have updated all menus, so avoid doing it when trackingMenu == 3. */
544 if (trackingMenu == 2)
545 ns_check_menu_open (menu);
548 - (void)menuDidClose:(NSMenu *)menu
553 #endif /* NS_IMPL_COCOA */
555 /* delegate method called when a submenu is being opened: run a 'deep' call
556 to set_frame_menubar */
557 - (void)menuNeedsUpdate: (NSMenu *)menu
559 if (!FRAME_LIVE_P (frame))
562 /* Cocoa/Carbon will request update on every keystroke
563 via IsMenuKeyEvent -> CheckMenusForKeyEvent. These are not needed
564 since key equivalents are handled through emacs.
565 On Leopard, even keystroke events generate SystemDefined event.
566 Third-party applications that enhance mouse / trackpad
567 interaction, or also VNC/Remote Desktop will send events
568 of type AppDefined rather than SysDefined.
569 Menus will fail to show up if they haven't been initialized.
570 AppDefined events may lack timing data.
572 Thus, we rely on the didBeginTrackingNotification notification
573 as above to indicate the need for updates.
574 From 10.6 on, we could also use -[NSMenu propertiesToUpdate]: In the
575 key press case, NSMenuPropertyItemImage (e.g.) won't be set.
577 if (trackingMenu == 0)
579 /*fprintf (stderr, "Updating menu '%s'\n", [[self title] UTF8String]); NSLog (@"%@\n", event); */
580 #ifdef NS_IMPL_GNUSTEP
581 /* Don't know how to do this for anything other than OSX >= 10.5
582 This is wrong, as it might run Lisp code in the event loop. */
583 ns_update_menubar (frame, true, self);
588 - (BOOL)performKeyEquivalent: (NSEvent *)theEvent
590 if (SELECTED_FRAME () && FRAME_NS_P (SELECTED_FRAME ())
591 && FRAME_NS_VIEW (SELECTED_FRAME ()))
592 [FRAME_NS_VIEW (SELECTED_FRAME ()) keyDown: theEvent];
597 /* Parse a widget_value's key rep (examples: 's-p', 's-S', '(C-x C-s)', '<f13>')
598 into an accelerator string. We are only able to display a single character
599 for an accelerator, together with an optional modifier combination. (Under
600 Carbon more control was possible, but in Cocoa multi-char strings passed to
601 NSMenuItem get ignored. For now we try to display a super-single letter
602 combo, and return the others as strings to be appended to the item title.
603 (This is signaled by setting keyEquivModMask to 0 for now.) */
604 -(NSString *)parseKeyEquiv: (const char *)key
606 const char *tpos = key;
607 keyEquivModMask = NSEventModifierFlagCommand;
609 if (!key || !strlen (key))
612 while (*tpos == ' ' || *tpos == '(')
614 if ((*tpos == 's') && (*(tpos+1) == '-'))
616 return [NSString stringWithFormat: @"%c", tpos[2]];
618 keyEquivModMask = 0; /* signal */
619 return [NSString stringWithUTF8String: tpos];
623 - (NSMenuItem *)addItemWithWidgetValue: (void *)wvptr
626 widget_value *wv = (widget_value *)wvptr;
628 if (menu_separator_name_p (wv->name))
630 item = [NSMenuItem separatorItem];
631 [self addItem: item];
635 NSString *title, *keyEq;
636 title = [NSString stringWithUTF8String: wv->name];
638 title = @"< ? >"; /* (get out in the open so we know about it) */
640 keyEq = [self parseKeyEquiv: wv->key];
642 /* OS X just ignores modifier strings longer than one character */
643 if (keyEquivModMask == 0)
644 title = [title stringByAppendingFormat: @" (%@)", keyEq];
647 item = [self addItemWithTitle: (NSString *)title
648 action: @selector (menuDown:)
649 keyEquivalent: keyEq];
650 [item setKeyEquivalentModifierMask: keyEquivModMask];
652 [item setEnabled: wv->enabled];
654 /* Draw radio buttons and tickboxes */
655 if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
656 wv->button_type == BUTTON_TYPE_RADIO))
657 [item setState: NSOnState];
659 [item setState: NSOffState];
661 [item setTag: (NSInteger)wv->call_data];
673 for (n = [self numberOfItems]-1; n >= 0; n--)
675 NSMenuItem *item = [self itemAtIndex: n];
676 NSString *title = [item title];
677 if ([ns_app_name isEqualToString: title]
678 && ![item isSeparatorItem])
680 [self removeItemAtIndex: n];
685 - (void)fillWithWidgetValue: (void *)wvptr
687 [self fillWithWidgetValue: wvptr frame: (struct frame *)nil];
690 - (void)fillWithWidgetValue: (void *)wvptr frame: (struct frame *)f
692 widget_value *wv = (widget_value *)wvptr;
694 /* clear existing contents */
697 /* add new contents */
698 for (; wv != NULL; wv = wv->next)
700 NSMenuItem *item = [self addItemWithWidgetValue: wv];
707 submenu = [[EmacsMenu alloc] initWithTitle: [item title] frame:f];
709 submenu = [[EmacsMenu alloc] initWithTitle: [item title]];
711 [self setSubmenu: submenu forItem: item];
712 [submenu fillWithWidgetValue: wv->contents];
714 [item setAction: (SEL)nil];
718 #ifdef NS_IMPL_GNUSTEP
719 if ([[self window] isVisible])
725 /* adds an empty submenu and returns it */
726 - (EmacsMenu *)addSubmenuWithTitle: (const char *)title forFrame: (struct frame *)f
728 NSString *titleStr = [NSString stringWithUTF8String: title];
729 NSMenuItem *item = [self addItemWithTitle: titleStr
730 action: (SEL)nil /*@selector (menuDown:) */
732 EmacsMenu *submenu = [[EmacsMenu alloc] initWithTitle: titleStr frame: f];
733 [self setSubmenu: submenu forItem: item];
738 /* run a menu in popup mode */
739 - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f
740 keymaps: (bool)keymaps
742 EmacsView *view = FRAME_NS_VIEW (f);
746 /* p = [view convertPoint:p fromView: nil]; */
747 p.y = NSHeight ([view frame]) - p.y;
748 e = [[view window] currentEvent];
749 event = [NSEvent mouseEventWithType: NSEventTypeRightMouseDown
752 timestamp: [e timestamp]
753 windowNumber: [[view window] windowNumber]
755 eventNumber: 0/*[e eventNumber] */
759 context_menu_value = -1;
760 [NSMenu popUpContextMenu: self withEvent: event forView: view];
761 retVal = context_menu_value;
762 context_menu_value = 0;
764 ? find_and_return_menu_selection (f, keymaps, (void *)retVal)
772 /* ==========================================================================
774 Context Menu: implementing functions
776 ========================================================================== */
779 ns_menu_show (struct frame *f, int x, int y, int menuflags,
780 Lisp_Object title, const char **error)
785 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
786 widget_value *wv, *first_wv = 0;
787 bool keymaps = (menuflags & MENU_KEYMAPS);
789 NSTRACE ("ns_menu_show");
795 /* now parse stage 2 as in ns_update_menubar */
796 wv = make_widget_value ("contextmenu", NULL, true, Qnil);
797 wv->button_type = BUTTON_TYPE_NONE;
801 /* FIXME: a couple of one-line differences prevent reuse */
802 wv = digest_single_submenu (0, menu_items_used, 0);
805 widget_value *save_wv = 0, *prev_wv = 0;
806 widget_value **submenu_stack
807 = alloca (menu_items_used * sizeof *submenu_stack);
808 /* Lisp_Object *subprefix_stack
809 = alloca (menu_items_used * sizeof *subprefix_stack); */
810 int submenu_depth = 0;
814 /* Loop over all panes and items, filling in the tree. */
816 while (i < menu_items_used)
818 if (EQ (AREF (menu_items, i), Qnil))
820 submenu_stack[submenu_depth++] = save_wv;
826 else if (EQ (AREF (menu_items, i), Qlambda))
829 save_wv = submenu_stack[--submenu_depth];
833 else if (EQ (AREF (menu_items, i), Qt)
834 && submenu_depth != 0)
835 i += MENU_ITEMS_PANE_LENGTH;
836 /* Ignore a nil in the item list.
837 It's meaningful only for dialog boxes. */
838 else if (EQ (AREF (menu_items, i), Qquote))
840 else if (EQ (AREF (menu_items, i), Qt))
842 /* Create a new pane. */
843 Lisp_Object pane_name, prefix;
844 const char *pane_string;
846 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
847 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
849 #ifndef HAVE_MULTILINGUAL_MENU
850 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
852 pane_name = ENCODE_MENU_STRING (pane_name);
853 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
856 pane_string = (NILP (pane_name)
857 ? "" : SSDATA (pane_name));
858 /* If there is just one top-level pane, put all its items directly
859 under the top-level menu. */
860 if (menu_items_n_panes == 1)
863 /* If the pane has a meaningful name,
864 make the pane a top-level menu item
865 with its items as a submenu beneath it. */
866 if (!keymaps && strcmp (pane_string, ""))
868 wv = make_widget_value (pane_string, NULL, true, Qnil);
872 first_wv->contents = wv;
873 if (keymaps && !NILP (prefix))
875 wv->button_type = BUTTON_TYPE_NONE;
885 i += MENU_ITEMS_PANE_LENGTH;
889 /* Create a new item within current pane. */
890 Lisp_Object item_name, enable, descrip, def, type, selected, help;
891 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
892 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
893 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
894 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
895 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
896 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
897 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
899 #ifndef HAVE_MULTILINGUAL_MENU
900 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
902 item_name = ENCODE_MENU_STRING (item_name);
903 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
906 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
908 descrip = ENCODE_MENU_STRING (descrip);
909 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
911 #endif /* not HAVE_MULTILINGUAL_MENU */
913 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
914 STRINGP (help) ? help : Qnil);
918 save_wv->contents = wv;
920 wv->key = SSDATA (descrip);
921 /* If this item has a null value,
922 make the call_data null so that it won't display a box
923 when the mouse is on it. */
924 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
927 wv->button_type = BUTTON_TYPE_NONE;
928 else if (EQ (type, QCtoggle))
929 wv->button_type = BUTTON_TYPE_TOGGLE;
930 else if (EQ (type, QCradio))
931 wv->button_type = BUTTON_TYPE_RADIO;
935 wv->selected = !NILP (selected);
939 i += MENU_ITEMS_ITEM_LENGTH;
947 widget_value *wv_title;
948 widget_value *wv_sep = make_widget_value ("--", NULL, false, Qnil);
950 /* Maybe replace this separator with a bitmap or owner-draw item
951 so that it looks better. Having two separators looks odd. */
952 wv_sep->next = first_wv->contents;
954 #ifndef HAVE_MULTILINGUAL_MENU
955 if (STRING_MULTIBYTE (title))
956 title = ENCODE_MENU_STRING (title);
958 wv_title = make_widget_value (SSDATA (title), NULL, false, Qnil);
959 wv_title->button_type = BUTTON_TYPE_NONE;
960 wv_title->next = wv_sep;
961 first_wv->contents = wv_title;
964 pmenu = [[EmacsMenu alloc] initWithTitle:
965 [NSString stringWithUTF8String: SSDATA (title)]];
966 [pmenu fillWithWidgetValue: first_wv->contents];
967 free_menubar_widget_value_tree (first_wv);
968 unbind_to (specpdl_count, Qnil);
970 popup_activated_flag = 1;
971 tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps];
972 popup_activated_flag = 0;
973 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
980 /* ==========================================================================
982 Toolbar: externally-called functions
984 ========================================================================== */
987 free_frame_tool_bar (struct frame *f)
988 /* --------------------------------------------------------------------------
989 Under NS we just hide the toolbar until it might be needed again.
990 -------------------------------------------------------------------------- */
992 EmacsView *view = FRAME_NS_VIEW (f);
994 NSTRACE ("free_frame_tool_bar");
997 view->wait_for_tool_bar = NO;
999 FRAME_TOOLBAR_HEIGHT (f) = 0;
1001 /* Note: This trigger an animation, which calls windowDidResize
1003 f->output_data.ns->in_animation = 1;
1004 [[view toolbar] setVisible: NO];
1005 f->output_data.ns->in_animation = 0;
1011 update_frame_tool_bar (struct frame *f)
1012 /* --------------------------------------------------------------------------
1013 Update toolbar contents
1014 -------------------------------------------------------------------------- */
1017 EmacsView *view = FRAME_NS_VIEW (f);
1018 NSWindow *window = [view window];
1019 EmacsToolbar *toolbar = [view toolbar];
1022 NSTRACE ("update_frame_tool_bar");
1024 if (view == nil || toolbar == nil) return;
1027 oldh = FRAME_TOOLBAR_HEIGHT (f);
1029 #ifdef NS_IMPL_COCOA
1030 [toolbar clearActive];
1035 /* update EmacsToolbar as in GtkUtils, build items list */
1036 for (i = 0; i < f->n_tool_bar_items; ++i)
1038 #define TOOLPROP(IDX) AREF (f->tool_bar_items, \
1039 i * TOOL_BAR_ITEM_NSLOTS + (IDX))
1041 BOOL enabled_p = !NILP (TOOLPROP (TOOL_BAR_ITEM_ENABLED_P));
1046 Lisp_Object helpObj;
1047 const char *helpText;
1049 /* Check if this is a separator. */
1050 if (EQ (TOOLPROP (TOOL_BAR_ITEM_TYPE), Qt))
1052 /* Skip separators. Newer OSX don't show them, and on GNUstep they
1053 are wide as a button, thus overflowing the toolbar most of
1058 /* If image is a vector, choose the image according to the
1060 image = TOOLPROP (TOOL_BAR_ITEM_IMAGES);
1061 if (VECTORP (image))
1063 /* NS toolbar auto-computes disabled and selected images */
1064 idx = TOOL_BAR_IMAGE_ENABLED_SELECTED;
1065 eassert (ASIZE (image) >= idx);
1066 image = AREF (image, idx);
1072 helpObj = TOOLPROP (TOOL_BAR_ITEM_HELP);
1074 helpObj = TOOLPROP (TOOL_BAR_ITEM_CAPTION);
1075 helpText = NILP (helpObj) ? "" : SSDATA (helpObj);
1077 /* Ignore invalid image specifications. */
1078 if (!valid_image_p (image))
1080 /* Don't log anything, GNUS makes invalid images all the time. */
1084 img_id = lookup_image (f, image);
1085 img = IMAGE_FROM_ID (f, img_id);
1086 prepare_image_for_display (f, img);
1088 if (img->load_failed_p || img->pixmap == nil)
1090 NSLog (@"Could not prepare toolbar image for display.");
1094 [toolbar addDisplayItemWithImage: img->pixmap
1098 enabled: enabled_p];
1102 if (![toolbar isVisible])
1104 f->output_data.ns->in_animation = 1;
1105 [toolbar setVisible: YES];
1106 f->output_data.ns->in_animation = 0;
1109 #ifdef NS_IMPL_COCOA
1110 if ([toolbar changed])
1112 /* inform app that toolbar has changed */
1113 NSDictionary *dict = [toolbar configurationDictionary];
1114 NSMutableDictionary *newDict = [dict mutableCopy];
1115 NSEnumerator *keys = [[dict allKeys] objectEnumerator];
1117 while ((key = [keys nextObject]) != nil)
1119 NSObject *val = [dict objectForKey: key];
1120 if ([val isKindOfClass: [NSArray class]])
1123 [toolbar toolbarDefaultItemIdentifiers: toolbar]
1128 [toolbar setConfigurationFromDictionary: newDict];
1133 FRAME_TOOLBAR_HEIGHT (f) =
1134 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1135 - FRAME_NS_TITLEBAR_HEIGHT (f);
1136 if (FRAME_TOOLBAR_HEIGHT (f) < 0) // happens if frame is fullscreen.
1137 FRAME_TOOLBAR_HEIGHT (f) = 0;
1139 if (oldh != FRAME_TOOLBAR_HEIGHT (f))
1140 [view updateFrameSize:YES];
1141 if (view->wait_for_tool_bar && FRAME_TOOLBAR_HEIGHT (f) > 0)
1143 view->wait_for_tool_bar = NO;
1144 [view setNeedsDisplay: YES];
1151 /* ==========================================================================
1153 Toolbar: class implementation
1155 ========================================================================== */
1157 @implementation EmacsToolbar
1159 - initForView: (EmacsView *)view withIdentifier: (NSString *)identifier
1161 NSTRACE ("[EmacsToolbar initForView: withIdentifier:]");
1163 self = [super initWithIdentifier: identifier];
1165 [self setDisplayMode: NSToolbarDisplayModeIconOnly];
1166 [self setSizeMode: NSToolbarSizeModeSmall];
1167 [self setDelegate: self];
1168 identifierToItem = [[NSMutableDictionary alloc] initWithCapacity: 10];
1169 activeIdentifiers = [[NSMutableArray alloc] initWithCapacity: 8];
1170 prevIdentifiers = nil;
1171 prevEnablement = enablement = 0L;
1177 NSTRACE ("[EmacsToolbar dealloc]");
1179 [prevIdentifiers release];
1180 [activeIdentifiers release];
1181 [identifierToItem release];
1185 - (void) clearActive
1187 NSTRACE ("[EmacsToolbar clearActive]");
1189 [prevIdentifiers release];
1190 prevIdentifiers = [activeIdentifiers copy];
1191 [activeIdentifiers removeAllObjects];
1192 prevEnablement = enablement;
1198 NSTRACE ("[EmacsToolbar clearAll]");
1201 while ([[self items] count] > 0)
1202 [self removeItemAtIndex: 0];
1207 NSTRACE ("[EmacsToolbar changed]");
1209 return [activeIdentifiers isEqualToArray: prevIdentifiers] &&
1210 enablement == prevEnablement ? NO : YES;
1213 - (void) addDisplayItemWithImage: (EmacsImage *)img
1216 helpText: (const char *)help
1217 enabled: (BOOL)enabled
1219 NSTRACE ("[EmacsToolbar addDisplayItemWithImage: ...]");
1221 /* 1) come up w/identifier */
1222 NSString *identifier
1223 = [NSString stringWithFormat: @"%lu", (unsigned long)[img hash]];
1224 [activeIdentifiers addObject: identifier];
1226 /* 2) create / reuse item */
1227 NSToolbarItem *item = [identifierToItem objectForKey: identifier];
1230 item = [[[NSToolbarItem alloc] initWithItemIdentifier: identifier]
1232 [item setImage: img];
1233 [item setToolTip: [NSString stringWithUTF8String: help]];
1234 [item setTarget: emacsView];
1235 [item setAction: @selector (toolbarClicked:)];
1236 [identifierToItem setObject: item forKey: identifier];
1239 #ifdef NS_IMPL_GNUSTEP
1240 [self insertItemWithItemIdentifier: identifier atIndex: idx];
1244 [item setEnabled: enabled];
1246 /* 3) update state */
1247 enablement = (enablement << 1) | (enabled == YES);
1250 /* This overrides super's implementation, which automatically sets
1251 all items to enabled state (for some reason). */
1252 - (void)validateVisibleItems
1254 NSTRACE ("[EmacsToolbar validateVisibleItems]");
1258 /* delegate methods */
1260 - (NSToolbarItem *)toolbar: (NSToolbar *)toolbar
1261 itemForItemIdentifier: (NSString *)itemIdentifier
1262 willBeInsertedIntoToolbar: (BOOL)flag
1264 NSTRACE ("[EmacsToolbar toolbar: ...]");
1266 /* look up NSToolbarItem by identifier and return... */
1267 return [identifierToItem objectForKey: itemIdentifier];
1270 - (NSArray *)toolbarDefaultItemIdentifiers: (NSToolbar *)toolbar
1272 NSTRACE ("[EmacsToolbar toolbarDefaultItemIdentifiers:]");
1274 /* return entire set.. */
1275 return activeIdentifiers;
1278 /* for configuration palette (not yet supported) */
1279 - (NSArray *)toolbarAllowedItemIdentifiers: (NSToolbar *)toolbar
1281 NSTRACE ("[EmacsToolbar toolbarAllowedItemIdentifiers:]");
1283 /* return entire set... */
1284 return activeIdentifiers;
1285 //return [identifierToItem allKeys];
1288 - (void)setVisible:(BOOL)shown
1290 NSTRACE ("[EmacsToolbar setVisible:%d]", shown);
1292 [super setVisible:shown];
1296 /* optional and unneeded */
1297 /* - toolbarWillAddItem: (NSNotification *)notification { } */
1298 /* - toolbarDidRemoveItem: (NSNotification *)notification { } */
1299 /* - (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar */
1301 @end /* EmacsToolbar */
1305 /* ==========================================================================
1307 Tooltip: class implementation
1309 ========================================================================== */
1311 /* Needed because NeXTstep does not provide enough control over tooltip
1313 @implementation EmacsTooltip
1317 NSColor *col = [NSColor colorWithCalibratedRed: 1.0 green: 1.0
1318 blue: 0.792 alpha: 0.95];
1319 NSFont *font = [NSFont toolTipsFontOfSize: 0];
1320 NSFont *sfont = [font screenFont];
1321 int height = [sfont ascender] - [sfont descender];
1322 /*[font boundingRectForFont].size.height; */
1323 NSRect r = NSMakeRect (0, 0, 100, height+6);
1325 textField = [[NSTextField alloc] initWithFrame: r];
1326 [textField setFont: font];
1327 [textField setBackgroundColor: col];
1329 [textField setEditable: NO];
1330 [textField setSelectable: NO];
1331 [textField setBordered: NO];
1332 [textField setBezeled: NO];
1333 [textField setDrawsBackground: YES];
1335 win = [[NSWindow alloc]
1336 initWithContentRect: [textField frame]
1338 backing: NSBackingStoreBuffered
1340 [win setHasShadow: YES];
1341 [win setReleasedWhenClosed: NO];
1342 [win setDelegate: self];
1343 [[win contentView] addSubview: textField];
1344 /* [win setBackgroundColor: col]; */
1345 [win setOpaque: NO];
1354 [textField release];
1358 - (void) setText: (char *)text
1360 NSString *str = [NSString stringWithUTF8String: text];
1361 NSRect r = [textField frame];
1364 [textField setStringValue: str];
1365 tooltipDims = [[textField cell] cellSize];
1367 r.size.width = tooltipDims.width;
1368 r.size.height = tooltipDims.height;
1369 [textField setFrame: r];
1372 - (void) showAtX: (int)x Y: (int)y for: (int)seconds
1374 NSRect wr = [win frame];
1376 wr.origin = NSMakePoint (x, y);
1377 wr.size = [textField frame].size;
1379 [win setFrame: wr display: YES];
1380 [win setLevel: NSPopUpMenuWindowLevel];
1381 [win orderFront: self];
1383 timer = [NSTimer scheduledTimerWithTimeInterval: (float)seconds target: self
1384 selector: @selector (hide)
1385 userInfo: nil repeats: NO];
1394 if ([timer isValid])
1403 return timer != nil;
1408 return [textField frame];
1411 @end /* EmacsTooltip */
1415 /* ==========================================================================
1417 Popup Dialog: implementing functions
1419 ========================================================================== */
1422 pop_down_menu (void *arg)
1424 EmacsDialogPanel *panel = arg;
1426 if (popup_activated_flag)
1429 popup_activated_flag = 0;
1431 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
1438 ns_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1441 Lisp_Object tem, title;
1445 NSTRACE ("ns_popup_dialog");
1447 isQ = NILP (header);
1449 check_window_system (f);
1451 p.x = (int)f->left_pos + ((int)FRAME_COLUMN_WIDTH (f) * f->text_cols)/2;
1452 p.y = (int)f->top_pos + (FRAME_LINE_HEIGHT (f) * f->text_lines)/2;
1454 title = Fcar (contents);
1455 CHECK_STRING (title);
1457 if (NILP (Fcar (Fcdr (contents))))
1458 /* No buttons specified, add an "Ok" button so users can pop down
1460 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1463 dialog = [[EmacsDialogPanel alloc] initFromContents: contents
1467 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1469 record_unwind_protect_ptr (pop_down_menu, dialog);
1470 popup_activated_flag = 1;
1471 tem = [dialog runDialogAt: p];
1472 unbind_to (specpdl_count, Qnil); /* calls pop_down_menu */
1481 /* ==========================================================================
1483 Popup Dialog: class implementation
1485 ========================================================================== */
1487 @interface FlippedView : NSView
1492 @implementation FlippedView
1499 @implementation EmacsDialogPanel
1502 #define ICONSIZE 64.0
1503 #define TEXTHEIGHT 20.0
1504 #define MINCELLWIDTH 90.0
1506 - initWithContentRect: (NSRect)contentRect styleMask: (NSUInteger)aStyle
1507 backing: (NSBackingStoreType)backingType defer: (BOOL)flag
1509 NSSize spacing = {SPACER, SPACER};
1512 NSImageView *imgView;
1513 FlippedView *contentView;
1516 dialog_return = Qundefined;
1517 button_values = NULL;
1518 area.origin.x = 3*SPACER;
1519 area.origin.y = 2*SPACER;
1520 area.size.width = ICONSIZE;
1521 area.size.height= ICONSIZE;
1522 img = [[NSImage imageNamed: @"NSApplicationIcon"] copy];
1523 #ifdef NS_IMPL_COCOA
1524 #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
1525 [img setScalesWhenResized: YES];
1528 [img setSize: NSMakeSize (ICONSIZE, ICONSIZE)];
1529 imgView = [[NSImageView alloc] initWithFrame: area];
1530 [imgView setImage: img];
1531 [imgView setEditable: NO];
1533 [imgView autorelease];
1535 aStyle = NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSUtilityWindowMask;
1539 [super initWithContentRect: contentRect styleMask: aStyle
1540 backing: backingType defer: flag];
1541 contentView = [[FlippedView alloc] initWithFrame: [[self contentView] frame]];
1542 [contentView autorelease];
1544 [self setContentView: contentView];
1546 [[self contentView] setAutoresizesSubviews: YES];
1548 [[self contentView] addSubview: imgView];
1549 [self setTitle: @""];
1551 area.origin.x += ICONSIZE+2*SPACER;
1552 /* area.origin.y = TEXTHEIGHT; ICONSIZE/2-10+SPACER; */
1553 area.size.width = 400;
1554 area.size.height= TEXTHEIGHT;
1555 command = [[[NSTextField alloc] initWithFrame: area] autorelease];
1556 [[self contentView] addSubview: command];
1557 [command setStringValue: ns_app_name];
1558 [command setDrawsBackground: NO];
1559 [command setBezeled: NO];
1560 [command setSelectable: NO];
1561 [command setFont: [NSFont boldSystemFontOfSize: 13.0]];
1563 /* area.origin.x = ICONSIZE+2*SPACER;
1564 area.origin.y = TEXTHEIGHT + 2*SPACER;
1565 area.size.width = 400;
1566 area.size.height= 2;
1567 tem = [[[NSBox alloc] initWithFrame: area] autorelease];
1568 [[self contentView] addSubview: tem];
1569 [tem setTitlePosition: NSNoTitle];
1570 [tem setAutoresizingMask: NSViewWidthSizable];*/
1572 /* area.origin.x = ICONSIZE+2*SPACER; */
1573 area.origin.y += TEXTHEIGHT+SPACER;
1574 area.size.width = 400;
1575 area.size.height= TEXTHEIGHT;
1576 title = [[[NSTextField alloc] initWithFrame: area] autorelease];
1577 [[self contentView] addSubview: title];
1578 [title setDrawsBackground: NO];
1579 [title setBezeled: NO];
1580 [title setSelectable: NO];
1581 [title setFont: [NSFont systemFontOfSize: 11.0]];
1583 cell = [[[NSButtonCell alloc] initTextCell: @""] autorelease];
1584 [cell setBordered: NO];
1585 [cell setEnabled: NO];
1586 [cell setCellAttribute: NSCellIsInsetButton to: 8];
1587 [cell setBezelStyle: NSRoundedBezelStyle];
1589 matrix = [[NSMatrix alloc] initWithFrame: contentRect
1590 mode: NSHighlightModeMatrix
1593 numberOfColumns: 1];
1594 [matrix setFrameOrigin: NSMakePoint (area.origin.x,
1595 area.origin.y + (TEXTHEIGHT+3*SPACER))];
1596 [matrix setIntercellSpacing: spacing];
1597 [matrix autorelease];
1599 [[self contentView] addSubview: matrix];
1600 [self setOneShot: YES];
1601 [self setReleasedWhenClosed: YES];
1602 [self setHidesOnDeactivate: YES];
1607 - (BOOL)windowShouldClose: (id)sender
1609 window_closed = YES;
1616 xfree (button_values);
1620 - (void)process_dialog: (Lisp_Object) list
1622 Lisp_Object item, lst = list;
1624 int buttons = 0, btnnr = 0;
1626 for (; XTYPE (lst) == Lisp_Cons; lst = XCDR (lst))
1629 if (XTYPE (item) == Lisp_Cons)
1634 button_values = xmalloc (buttons * sizeof *button_values);
1636 for (; XTYPE (list) == Lisp_Cons; list = XCDR (list))
1639 if (XTYPE (item) == Lisp_String)
1641 [self addString: SSDATA (item) row: row++];
1643 else if (XTYPE (item) == Lisp_Cons)
1645 button_values[btnnr] = XCDR (item);
1646 [self addButton: SSDATA (XCAR (item)) value: btnnr row: row++];
1649 else if (NILP (item))
1658 - (void)addButton: (char *)str value: (int)tag row: (int)row
1667 cell = [matrix cellAtRow: row column: cols-1];
1668 [cell setTarget: self];
1669 [cell setAction: @selector (clicked: )];
1670 [cell setTitle: [NSString stringWithUTF8String: str]];
1672 [cell setBordered: YES];
1673 [cell setEnabled: YES];
1677 - (void)addString: (char *)str row: (int)row
1686 cell = [matrix cellAtRow: row column: cols-1];
1687 [cell setTitle: [NSString stringWithUTF8String: str]];
1688 [cell setBordered: YES];
1689 [cell setEnabled: NO];
1700 - (void)clicked: sender
1702 NSArray *sellist = nil;
1705 sellist = [sender selectedCells];
1706 if ([sellist count] < 1)
1709 seltag = [[sellist objectAtIndex: 0] tag];
1710 dialog_return = button_values[seltag];
1715 - initFromContents: (Lisp_Object)contents isQuestion: (BOOL)isQ
1720 if (XTYPE (contents) == Lisp_Cons)
1722 head = Fcar (contents);
1723 [self process_dialog: Fcdr (contents)];
1728 if (XTYPE (head) == Lisp_String)
1729 [title setStringValue:
1730 [NSString stringWithUTF8String: SSDATA (head)]];
1731 else if (isQ == YES)
1732 [title setStringValue: @"Question"];
1734 [title setStringValue: @"Information"];
1740 if (cols == 1 && rows > 1) /* Never told where to split */
1743 for (i = 0; i < rows/2; i++)
1745 [matrix putCell: [matrix cellAtRow: (rows+1)/2 column: 0]
1746 atRow: i column: 1];
1747 [matrix removeRow: (rows+1)/2];
1753 NSSize csize = [matrix cellSize];
1754 if (csize.width < MINCELLWIDTH)
1756 csize.width = MINCELLWIDTH;
1757 [matrix setCellSize: csize];
1758 [matrix sizeToCells];
1763 [command sizeToFit];
1767 if (r.size.width+r.origin.x > t.size.width+t.origin.x)
1769 t.origin.x = r.origin.x;
1770 t.size.width = r.size.width;
1772 r = [command frame];
1773 if (r.size.width+r.origin.x > t.size.width+t.origin.x)
1775 t.origin.x = r.origin.x;
1776 t.size.width = r.size.width;
1780 s = [(NSView *)[self contentView] frame];
1781 r.size.width += t.origin.x+t.size.width +2*SPACER-s.size.width;
1782 r.size.height += t.origin.y+t.size.height+SPACER-s.size.height;
1783 [self setFrame: r display: NO];
1791 - (void)timeout_handler: (NSTimer *)timedEntry
1793 NSEvent *nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
1794 location: NSMakePoint (0, 0)
1797 windowNumber: [[NSApp mainWindow] windowNumber]
1798 context: [NSApp context]
1804 /* We use sto because stopModal/abortModal out of the main loop does not
1805 seem to work in 10.6. But as we use stop we must send a real event so
1806 the stop is seen and acted upon. */
1808 [NSApp postEvent: nxev atStart: NO];
1811 - (Lisp_Object)runDialogAt: (NSPoint)p
1813 Lisp_Object ret = Qundefined;
1815 while (popup_activated_flag)
1818 struct timespec next_time = timer_check ();
1820 if (timespec_valid_p (next_time))
1822 double time = timespectod (next_time);
1823 tmo = [NSTimer timerWithTimeInterval: time
1825 selector: @selector (timeout_handler:)
1828 [[NSRunLoop currentRunLoop] addTimer: tmo
1829 forMode: NSModalPanelRunLoopMode];
1832 dialog_return = Qundefined;
1833 [NSApp runModalForWindow: self];
1834 ret = dialog_return;
1837 if (tmo != nil) [tmo invalidate]; /* Cancels timer */
1842 if (EQ (ret, Qundefined) && window_closed)
1843 /* Make close button pressed equivalent to C-g. */
1852 /* ==========================================================================
1856 ========================================================================== */
1858 DEFUN ("ns-reset-menu", Fns_reset_menu, Sns_reset_menu, 0, 0, 0,
1859 doc: /* Cause the NS menu to be re-calculated. */)
1862 set_frame_menubar (SELECTED_FRAME (), 1, 0);
1867 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
1868 doc: /* Return t if a menu or popup dialog is active. */)
1871 return popup_activated () ? Qt : Qnil;
1874 /* ==========================================================================
1876 Lisp interface declaration
1878 ========================================================================== */
1881 syms_of_nsmenu (void)
1883 #ifndef NS_IMPL_COCOA
1884 /* Don't know how to keep track of this in Next/Open/GNUstep. Always
1885 update menus there. */
1888 defsubr (&Sns_reset_menu);
1889 defsubr (&Smenu_or_popup_active_p);
1891 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");