Fix MS-Windows build broken by menu changes on 2014-06-02.
[bpt/emacs.git] / src / nsmenu.m
CommitLineData
edfda783 1/* NeXT/Open/GNUstep and MacOSX Cocoa menu and toolbar module.
ba318903 2 Copyright (C) 2007-2014 Free Software Foundation, Inc.
edfda783
AR
3
4This file is part of GNU Emacs.
5
32d235f8 6GNU Emacs is free software: you can redistribute it and/or modify
edfda783 7it under the terms of the GNU General Public License as published by
32d235f8
GM
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
edfda783
AR
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
32d235f8 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
edfda783 18
32d235f8 19/*
edfda783
AR
20By Adrian Robert, based on code from original nsmenu.m (Carl Edman,
21Christian Limpach, Scott Bender, Christophe de Dinechin) and code in the
22Carbon version by Yamamoto Mitsuharu. */
23
5a06864f
AR
24/* This should be the first include, as it may set up #defines affecting
25 interpretation of even the system includes. */
b29116ef 26#include <config.h>
5a06864f 27
edfda783
AR
28#include "lisp.h"
29#include "window.h"
e5560ff7 30#include "character.h"
edfda783
AR
31#include "buffer.h"
32#include "keymap.h"
33#include "coding.h"
34#include "commands.h"
35#include "blockinput.h"
36#include "nsterm.h"
37#include "termhooks.h"
38#include "keyboard.h"
ef7417fd 39#include "menu.h"
edfda783 40
cbe0b5bf
AR
41#define NSMENUPROFILE 0
42
43#if NSMENUPROFILE
edfda783
AR
44#include <sys/timeb.h>
45#include <sys/types.h>
cbe0b5bf 46#endif
edfda783 47
edfda783
AR
48#if 0
49int menu_trace_num = 0;
50#define NSTRACE(x) fprintf (stderr, "%s:%d: [%d] " #x "\n", \
51 __FILE__, __LINE__, ++menu_trace_num)
52#else
53#define NSTRACE(x)
54#endif
55
56#if 0
57/* Include lisp -> C common menu parsing code */
58#define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
59#include "nsmenu_common.c"
60#endif
61
edfda783
AR
62extern Lisp_Object Qundefined, Qmenu_enable, Qmenu_bar_update_hook;
63extern Lisp_Object QCtoggle, QCradio;
64
edfda783 65Lisp_Object Qdebug_on_next_call;
fb9d0f5a 66extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
edfda783
AR
67
68extern long context_menu_value;
4e622592 69EmacsMenu *mainMenu, *svcsMenu, *dockMenu;
edfda783 70
07b87a10
AR
71/* Nonzero means a menu is currently active. */
72static int popup_activated_flag;
73
5fecd5fc
JD
74/* Nonzero means we are tracking and updating menus. */
75static int trackingMenu;
76
77
edfda783
AR
78/* NOTE: toolbar implementation is at end,
79 following complete menu implementation. */
80
81
82/* ==========================================================================
83
84 Menu: Externally-called functions
85
86 ========================================================================== */
87
88
edfda783
AR
89/* Supposed to discard menubar and free storage. Since we share the
90 menubar among frames and update its context for the focused window,
91 there is nothing to do here. */
92void
93free_frame_menubar (struct frame *f)
94{
95 return;
96}
97
98
07b87a10 99int
3d608a86 100popup_activated (void)
07b87a10
AR
101{
102 return popup_activated_flag;
103}
104
105
edfda783
AR
106/* --------------------------------------------------------------------------
107 Update menubar. Three cases:
18e27ea8 108 1) ! deep_p, submenu = nil: Fresh switch onto a frame -- either set up
edfda783 109 just top-level menu strings (OS X), or goto case (2) (GNUstep).
18e27ea8
PE
110 2) deep_p, submenu = nil: Recompute all submenus.
111 3) deep_p, submenu = non-nil: Update contents of a single submenu.
edfda783 112 -------------------------------------------------------------------------- */
c0342369 113static void
18e27ea8 114ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
edfda783
AR
115{
116 NSAutoreleasePool *pool;
117 id menu = [NSApp mainMenu];
118 static EmacsMenu *last_submenu = nil;
119 BOOL needsSet = NO;
9fa1de30 120 bool owfi;
edfda783
AR
121 Lisp_Object items;
122 widget_value *wv, *first_wv, *prev_wv = 0;
123 int i;
124
cbe0b5bf 125#if NSMENUPROFILE
edfda783
AR
126 struct timeb tb;
127 long t;
128#endif
129
6d01f1fe 130 NSTRACE (ns_update_menubar);
edfda783
AR
131
132 if (f != SELECTED_FRAME ())
133 return;
134 XSETFRAME (Vmenu_updating_frame, f);
135/*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */
136
4d7e6e51 137 block_input ();
edfda783
AR
138 pool = [[NSAutoreleasePool alloc] init];
139
140 /* Menu may have been created automatically; if so, discard it. */
141 if ([menu isKindOfClass: [EmacsMenu class]] == NO)
142 {
143 [menu release];
144 menu = nil;
145 }
146
147 if (menu == nil)
148 {
3988c7d6 149 menu = [[EmacsMenu alloc] initWithTitle: ns_app_name];
edfda783
AR
150 needsSet = YES;
151 }
152 else
153 { /* close up anything on there */
154 id attMenu = [menu attachedMenu];
155 if (attMenu != nil)
156 [attMenu close];
157 }
158
cbe0b5bf 159#if NSMENUPROFILE
edfda783
AR
160 ftime (&tb);
161 t = -(1000*tb.time+tb.millitm);
162#endif
163
edfda783
AR
164#ifdef NS_IMPL_GNUSTEP
165 deep_p = 1; /* until GNUstep NSMenu implements the Panther delegation model */
166#endif
167
168 if (deep_p)
169 {
170 /* Fully parse one or more of the submenus. */
171 int n = 0;
172 int *submenu_start, *submenu_end;
7cded46f
PE
173 bool *submenu_top_level_items;
174 int *submenu_n_panes;
edfda783
AR
175 struct buffer *prev = current_buffer;
176 Lisp_Object buffer;
d311d28c 177 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
edfda783
AR
178 int previous_menu_items_used = f->menu_bar_items_used;
179 Lisp_Object *previous_items
38182d90 180 = alloca (previous_menu_items_used * sizeof *previous_items);
edfda783
AR
181
182 /* lisp preliminaries */
e74aeda8 183 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
edfda783
AR
184 specbind (Qinhibit_quit, Qt);
185 specbind (Qdebug_on_next_call, Qnil);
186 record_unwind_save_match_data ();
187 if (NILP (Voverriding_local_map_menu_flag))
188 {
189 specbind (Qoverriding_terminal_local_map, Qnil);
190 specbind (Qoverriding_local_map, Qnil);
191 }
192 set_buffer_internal_1 (XBUFFER (buffer));
193
df2142db
AR
194 /* TODO: for some reason this is not needed in other terms,
195 but some menu updates call Info-extract-pointer which causes
196 abort-on-error if waiting-for-input. Needs further investigation. */
edfda783
AR
197 owfi = waiting_for_input;
198 waiting_for_input = 0;
199
200 /* lucid hook and possible reset */
201 safe_run_hooks (Qactivate_menubar_hook);
202 if (! NILP (Vlucid_menu_bar_dirty_flag))
203 call0 (Qrecompute_lucid_menubar);
204 safe_run_hooks (Qmenu_bar_update_hook);
f00af5b1 205 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
edfda783
AR
206
207 /* Now ready to go */
208 items = FRAME_MENU_BAR_ITEMS (f);
209
210 /* Save the frame's previous menu bar contents data */
211 if (previous_menu_items_used)
e69b0960 212 memcpy (previous_items, aref_addr (f->menu_bar_vector, 0),
72af86bd 213 previous_menu_items_used * sizeof (Lisp_Object));
edfda783
AR
214
215 /* parse stage 1: extract from lisp */
216 save_menu_items ();
217
e69b0960 218 menu_items = f->menu_bar_vector;
edfda783 219 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
38182d90
PE
220 submenu_start = alloca (ASIZE (items) * sizeof *submenu_start);
221 submenu_end = alloca (ASIZE (items) * sizeof *submenu_end);
222 submenu_n_panes = alloca (ASIZE (items) * sizeof *submenu_n_panes);
223 submenu_top_level_items = alloca (ASIZE (items)
224 * sizeof *submenu_top_level_items);
edfda783 225 init_menu_items ();
96fb4434 226 for (i = 0; i < ASIZE (items); i += 4)
edfda783
AR
227 {
228 Lisp_Object key, string, maps;
229
96fb4434
PE
230 key = AREF (items, i);
231 string = AREF (items, i + 1);
232 maps = AREF (items, i + 2);
edfda783
AR
233 if (NILP (string))
234 break;
235
df2142db
AR
236 /* FIXME: we'd like to only parse the needed submenu, but this
237 was causing crashes in the _common parsing code.. need to make
238 sure proper initialization done.. */
e6076b1b 239/* if (submenu && strcmp ([[submenu title] UTF8String], SSDATA (string)))
edfda783
AR
240 continue; */
241
242 submenu_start[i] = menu_items_used;
243
244 menu_items_n_panes = 0;
245 submenu_top_level_items[i] = parse_single_submenu (key, string, maps);
246 submenu_n_panes[i] = menu_items_n_panes;
247 submenu_end[i] = menu_items_used;
248 n++;
249 }
250
251 finish_menu_items ();
252 waiting_for_input = owfi;
253
254
255 if (submenu && n == 0)
256 {
257 /* should have found a menu for this one but didn't */
258 fprintf (stderr, "ERROR: did not find lisp menu for submenu '%s'.\n",
e6076b1b 259 [[submenu title] UTF8String]);
edfda783
AR
260 discard_menu_items ();
261 unbind_to (specpdl_count, Qnil);
262 [pool release];
4d7e6e51 263 unblock_input ();
edfda783
AR
264 return;
265 }
266
267 /* parse stage 2: insert into lucid 'widget_value' structures
268 [comments in other terms say not to evaluate lisp code here] */
5668fb88 269 wv = make_widget_value ("menubar", NULL, true, Qnil);
edfda783 270 wv->button_type = BUTTON_TYPE_NONE;
edfda783
AR
271 first_wv = wv;
272
273 for (i = 0; i < 4*n; i += 4)
274 {
275 menu_items_n_panes = submenu_n_panes[i];
276 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
277 submenu_top_level_items[i]);
278 if (prev_wv)
279 prev_wv->next = wv;
280 else
281 first_wv->contents = wv;
282 /* Don't set wv->name here; GC during the loop might relocate it. */
283 wv->enabled = 1;
284 wv->button_type = BUTTON_TYPE_NONE;
285 prev_wv = wv;
286 }
287
288 set_buffer_internal_1 (prev);
289
290 /* Compare the new menu items with previous, and leave off if no change */
df2142db
AR
291 /* FIXME: following other terms here, but seems like this should be
292 done before parse stage 2 above, since its results aren't used */
edfda783
AR
293 if (previous_menu_items_used
294 && (!submenu || (submenu && submenu == last_submenu))
295 && menu_items_used == previous_menu_items_used)
296 {
297 for (i = 0; i < previous_menu_items_used; i++)
df2142db
AR
298 /* FIXME: this ALWAYS fails on Buffers menu items.. something
299 about their strings causes them to change every time, so we
300 double-check failures */
96fb4434 301 if (!EQ (previous_items[i], AREF (menu_items, i)))
edfda783 302 if (!(STRINGP (previous_items[i])
96fb4434 303 && STRINGP (AREF (menu_items, i))
0dc8cf50
JD
304 && !strcmp (SSDATA (previous_items[i]),
305 SSDATA (AREF (menu_items, i)))))
edfda783
AR
306 break;
307 if (i == previous_menu_items_used)
308 {
309 /* No change.. */
310
cbe0b5bf 311#if NSMENUPROFILE
edfda783
AR
312 ftime (&tb);
313 t += 1000*tb.time+tb.millitm;
314 fprintf (stderr, "NO CHANGE! CUTTING OUT after %ld msec.\n", t);
315#endif
316
317 free_menubar_widget_value_tree (first_wv);
318 discard_menu_items ();
319 unbind_to (specpdl_count, Qnil);
320 [pool release];
4d7e6e51 321 unblock_input ();
edfda783
AR
322 return;
323 }
324 }
325 /* The menu items are different, so store them in the frame */
df2142db 326 /* FIXME: this is not correct for single-submenu case */
f00af5b1 327 fset_menu_bar_vector (f, menu_items);
edfda783
AR
328 f->menu_bar_items_used = menu_items_used;
329
330 /* Calls restore_menu_items, etc., as they were outside */
331 unbind_to (specpdl_count, Qnil);
332
333 /* Parse stage 2a: now GC cannot happen during the lifetime of the
334 widget_value, so it's safe to store data from a Lisp_String */
335 wv = first_wv->contents;
96fb4434 336 for (i = 0; i < ASIZE (items); i += 4)
edfda783
AR
337 {
338 Lisp_Object string;
96fb4434 339 string = AREF (items, i + 1);
edfda783
AR
340 if (NILP (string))
341 break;
edfda783 342
51b59d79 343 wv->name = SSDATA (string);
edfda783
AR
344 update_submenu_strings (wv->contents);
345 wv = wv->next;
346 }
347
348 /* Now, update the NS menu; if we have a submenu, use that, otherwise
349 create a new menu for each sub and fill it. */
350 if (submenu)
351 {
e6076b1b 352 const char *submenuTitle = [[submenu title] UTF8String];
edfda783
AR
353 for (wv = first_wv->contents; wv; wv = wv->next)
354 {
355 if (!strcmp (submenuTitle, wv->name))
356 {
357 [submenu fillWithWidgetValue: wv->contents];
358 last_submenu = submenu;
359 break;
360 }
361 }
362 }
363 else
364 {
f90e3ebd 365 [menu fillWithWidgetValue: first_wv->contents frame: f];
edfda783
AR
366 }
367
368 }
369 else
370 {
371 static int n_previous_strings = 0;
372 static char previous_strings[100][10];
373 static struct frame *last_f = NULL;
374 int n;
375 Lisp_Object string;
376
5668fb88 377 wv = make_widget_value ("menubar", NULL, true, Qnil);
3988c7d6 378 wv->button_type = BUTTON_TYPE_NONE;
3988c7d6
AR
379 first_wv = wv;
380
edfda783
AR
381 /* Make widget-value tree w/ just the top level menu bar strings */
382 items = FRAME_MENU_BAR_ITEMS (f);
383 if (NILP (items))
384 {
204ee57f 385 free_menubar_widget_value_tree (first_wv);
edfda783 386 [pool release];
4d7e6e51 387 unblock_input ();
edfda783
AR
388 return;
389 }
390
391
392 /* check if no change.. this mechanism is a bit rough, but ready */
96fb4434 393 n = ASIZE (items) / 4;
edfda783
AR
394 if (f == last_f && n_previous_strings == n)
395 {
396 for (i = 0; i<n; i++)
397 {
facfbbbd 398 string = AREF (items, 4*i+1);
edfda783 399
facfbbbd 400 if (EQ (string, make_number (0))) // FIXME: Why??? --Stef
edfda783
AR
401 continue;
402 if (NILP (string))
0dc8cf50
JD
403 {
404 if (previous_strings[i][0])
405 break;
406 else
407 continue;
408 }
409 else if (memcmp (previous_strings[i], SDATA (string),
e99a530f 410 min (10, SBYTES (string) + 1)))
edfda783
AR
411 break;
412 }
413
414 if (i == n)
415 {
204ee57f 416 free_menubar_widget_value_tree (first_wv);
edfda783 417 [pool release];
4d7e6e51 418 unblock_input ();
edfda783
AR
419 return;
420 }
421 }
422
423 [menu clear];
96fb4434 424 for (i = 0; i < ASIZE (items); i += 4)
edfda783 425 {
96fb4434 426 string = AREF (items, i + 1);
edfda783
AR
427 if (NILP (string))
428 break;
429
430 if (n < 100)
b55b9f85
JD
431 memcpy (previous_strings[i/4], SDATA (string),
432 min (10, SBYTES (string) + 1));
edfda783 433
5668fb88 434 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
edfda783 435 wv->button_type = BUTTON_TYPE_NONE;
d311d28c 436 wv->call_data = (void *) (intptr_t) (-1);
edfda783
AR
437
438#ifdef NS_IMPL_COCOA
439 /* we'll update the real copy under app menu when time comes */
440 if (!strcmp ("Services", wv->name))
441 {
442 /* but we need to make sure it will update on demand */
443 [svcsMenu setFrame: f];
edfda783
AR
444 }
445 else
446#endif
447 [menu addSubmenuWithTitle: wv->name forFrame: f];
448
449 if (prev_wv)
450 prev_wv->next = wv;
451 else
452 first_wv->contents = wv;
453 prev_wv = wv;
454 }
455
456 last_f = f;
457 if (n < 100)
458 n_previous_strings = n;
459 else
460 n_previous_strings = 0;
461
462 }
463 free_menubar_widget_value_tree (first_wv);
464
465
cbe0b5bf 466#if NSMENUPROFILE
edfda783
AR
467 ftime (&tb);
468 t += 1000*tb.time+tb.millitm;
469 fprintf (stderr, "Menu update took %ld msec.\n", t);
470#endif
471
472 /* set main menu */
473 if (needsSet)
474 [NSApp setMainMenu: menu];
475
476 [pool release];
4d7e6e51 477 unblock_input ();
edfda783
AR
478
479}
480
481
482/* Main emacs core entry point for menubar menus: called to indicate that the
483 frame's menus have changed, and the *step representation should be updated
484 from Lisp. */
485void
18e27ea8 486set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
edfda783
AR
487{
488 ns_update_menubar (f, deep_p, nil);
489}
490
6d01f1fe
JD
491void
492x_activate_menubar (struct frame *f)
493{
c0342369 494#ifdef NS_IMPL_COCOA
a5bd5abb 495#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
d2d699ac 496 ns_update_menubar (f, true, nil);
6d01f1fe 497 ns_check_pending_open_menu ();
c0342369 498#endif
a5bd5abb 499#endif
6d01f1fe
JD
500}
501
502
503
edfda783 504
edfda783
AR
505/* ==========================================================================
506
507 Menu: class implementation
508
509 ========================================================================== */
510
511
512/* Menu that can define itself from Emacs "widget_value"s and will lazily
513 update itself when user clicked. Based on Carbon/AppKit implementation
514 by Yamamoto Mitsuharu. */
515@implementation EmacsMenu
516
517/* override designated initializer */
518- initWithTitle: (NSString *)title
519{
f90e3ebd 520 frame = 0;
0dc8cf50 521 if ((self = [super initWithTitle: title]))
edfda783
AR
522 [self setAutoenablesItems: NO];
523 return self;
524}
525
526
527/* used for top-level */
528- initWithTitle: (NSString *)title frame: (struct frame *)f
529{
530 [self initWithTitle: title];
531 frame = f;
532#ifdef NS_IMPL_COCOA
533 [self setDelegate: self];
534#endif
535 return self;
536}
537
538
539- (void)setFrame: (struct frame *)f
540{
541 frame = f;
542}
543
5fecd5fc
JD
544#ifdef NS_IMPL_COCOA
545#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
546extern NSString *NSMenuDidBeginTrackingNotification;
547#endif
548#endif
549
550#ifdef NS_IMPL_COCOA
551-(void)trackingNotification:(NSNotification *)notification
552{
553 /* Update menu in menuNeedsUpdate only while tracking menus. */
554 trackingMenu = ([notification name] == NSMenuDidBeginTrackingNotification
555 ? 1 : 0);
a5bd5abb 556#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
d2d699ac 557 if (! trackingMenu) ns_check_menu_open (nil);
a5bd5abb 558#endif
5fecd5fc 559}
6d01f1fe
JD
560
561#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
562- (void)menuWillOpen:(NSMenu *)menu
563{
d2d699ac 564 ++trackingMenu;
6d01f1fe 565
63216c5e 566#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
d2d699ac
JD
567 // On 10.6 we get repeated calls, only the one for NSSystemDefined is "real".
568 if ([[NSApp currentEvent] type] != NSSystemDefined) return;
5fecd5fc 569#endif
edfda783 570
d2d699ac
JD
571 /* When dragging from one menu to another, we get willOpen followed by didClose,
572 i.e. trackingMenu == 3 in willOpen and then 2 after didClose.
573 We have updated all menus, so avoid doing it when trackingMenu == 3. */
574 if (trackingMenu == 2)
575 ns_check_menu_open (menu);
576}
577
578- (void)menuDidClose:(NSMenu *)menu
579{
580 --trackingMenu;
581}
582#endif /* OSX >= 10.5 */
583
584#endif /* NS_IMPL_COCOA */
585
edfda783
AR
586/* delegate method called when a submenu is being opened: run a 'deep' call
587 to set_frame_menubar */
588- (void)menuNeedsUpdate: (NSMenu *)menu
589{
201949c3
AR
590 if (!FRAME_LIVE_P (frame))
591 return;
5fecd5fc
JD
592
593 /* Cocoa/Carbon will request update on every keystroke
edfda783
AR
594 via IsMenuKeyEvent -> CheckMenusForKeyEvent. These are not needed
595 since key equivalents are handled through emacs.
5fecd5fc
JD
596 On Leopard, even keystroke events generate SystemDefined event.
597 Third-party applications that enhance mouse / trackpad
598 interaction, or also VNC/Remote Desktop will send events
599 of type AppDefined rather than SysDefined.
600 Menus will fail to show up if they haven't been initialized.
601 AppDefined events may lack timing data.
602
603 Thus, we rely on the didBeginTrackingNotification notification
604 as above to indicate the need for updates.
605 From 10.6 on, we could also use -[NSMenu propertiesToUpdate]: In the
606 key press case, NSMenuPropertyItemImage (e.g.) won't be set.
607 */
0caaedb1 608 if (trackingMenu == 0)
edfda783
AR
609 return;
610/*fprintf (stderr, "Updating menu '%s'\n", [[self title] UTF8String]); NSLog (@"%@\n", event); */
cf7a0de6
PE
611#if (! defined (NS_IMPL_COCOA) \
612 || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5)
6d01f1fe
JD
613 /* Don't know how to do this for anything other than OSX >= 10.5
614 This is wrong, as it might run Lisp code in the event loop. */
615 ns_update_menubar (frame, true, self);
616#endif
edfda783
AR
617}
618
619
620- (BOOL)performKeyEquivalent: (NSEvent *)theEvent
621{
622 if (SELECTED_FRAME () && FRAME_NS_P (SELECTED_FRAME ())
623 && FRAME_NS_VIEW (SELECTED_FRAME ()))
624 [FRAME_NS_VIEW (SELECTED_FRAME ()) keyDown: theEvent];
625 return YES;
626}
627
628
c7cef62d
AR
629/* Parse a widget_value's key rep (examples: 's-p', 's-S', '(C-x C-s)', '<f13>')
630 into an accelerator string. We are only able to display a single character
631 for an accelerator, together with an optional modifier combination. (Under
632 Carbon more control was possible, but in Cocoa multi-char strings passed to
633 NSMenuItem get ignored. For now we try to display a super-single letter
634 combo, and return the others as strings to be appended to the item title.
635 (This is signaled by setting keyEquivModMask to 0 for now.) */
9c5bd55a 636-(NSString *)parseKeyEquiv: (const char *)key
edfda783 637{
9c5bd55a 638 const char *tpos = key;
c7cef62d
AR
639 keyEquivModMask = NSCommandKeyMask;
640
edfda783
AR
641 if (!key || !strlen (key))
642 return @"";
96fb4434 643
edfda783
AR
644 while (*tpos == ' ' || *tpos == '(')
645 tpos++;
0bae4e09
AR
646 if ((*tpos == 's') && (*(tpos+1) == '-'))
647 {
648 return [NSString stringWithFormat: @"%c", tpos[2]];
649 }
650 keyEquivModMask = 0; /* signal */
651 return [NSString stringWithUTF8String: tpos];
edfda783
AR
652}
653
07b87a10 654
15034960 655- (NSMenuItem *)addItemWithWidgetValue: (void *)wvptr
edfda783 656{
15034960 657 NSMenuItem *item;
edfda783
AR
658 widget_value *wv = (widget_value *)wvptr;
659
4039c786 660 if (menu_separator_name_p (wv->name))
edfda783
AR
661 {
662 item = [NSMenuItem separatorItem];
663 [self addItem: item];
664 }
665 else
666 {
667 NSString *title, *keyEq;
668 title = [NSString stringWithUTF8String: wv->name];
669 if (title == nil)
670 title = @"< ? >"; /* (get out in the open so we know about it) */
671
672 keyEq = [self parseKeyEquiv: wv->key];
84ee8aba
AR
673#ifdef NS_IMPL_COCOA
674 /* OS X just ignores modifier strings longer than one character */
c7cef62d
AR
675 if (keyEquivModMask == 0)
676 title = [title stringByAppendingFormat: @" (%@)", keyEq];
84ee8aba 677#endif
edfda783
AR
678
679 item = [self addItemWithTitle: (NSString *)title
680 action: @selector (menuDown:)
681 keyEquivalent: keyEq];
c7cef62d 682 [item setKeyEquivalentModifierMask: keyEquivModMask];
edfda783
AR
683
684 [item setEnabled: wv->enabled];
685
686 /* Draw radio buttons and tickboxes */
687 if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
688 wv->button_type == BUTTON_TYPE_RADIO))
689 [item setState: NSOnState];
690 else
691 [item setState: NSOffState];
692
f3f08c28 693 [item setTag: (NSInteger)wv->call_data];
edfda783
AR
694 }
695
696 return item;
697}
698
699
700/* convenience */
4ff670a8 701-(void)clear
edfda783
AR
702{
703 int n;
96fb4434 704
edfda783
AR
705 for (n = [self numberOfItems]-1; n >= 0; n--)
706 {
707 NSMenuItem *item = [self itemAtIndex: n];
708 NSString *title = [item title];
4ff670a8 709 if (([title length] == 0 /* OSX 10.5 */
3988c7d6 710 || [ns_app_name isEqualToString: title] /* from 10.6 on */
4ff670a8 711 || [@"Apple" isEqualToString: title]) /* older */
edfda783
AR
712 && ![item isSeparatorItem])
713 continue;
714 [self removeItemAtIndex: n];
715 }
716}
717
718
719- (void)fillWithWidgetValue: (void *)wvptr
d2d699ac 720{
f462f075 721 [self fillWithWidgetValue: wvptr frame: (struct frame *)nil];
d2d699ac
JD
722}
723
f90e3ebd 724- (void)fillWithWidgetValue: (void *)wvptr frame: (struct frame *)f
edfda783
AR
725{
726 widget_value *wv = (widget_value *)wvptr;
727
728 /* clear existing contents */
729 [self setMenuChangedMessagesEnabled: NO];
730 [self clear];
731
732 /* add new contents */
733 for (; wv != NULL; wv = wv->next)
734 {
15034960 735 NSMenuItem *item = [self addItemWithWidgetValue: wv];
edfda783
AR
736
737 if (wv->contents)
738 {
f90e3ebd
JD
739 EmacsMenu *submenu;
740
741 if (f)
742 submenu = [[EmacsMenu alloc] initWithTitle: [item title] frame:f];
743 else
744 submenu = [[EmacsMenu alloc] initWithTitle: [item title]];
edfda783
AR
745
746 [self setSubmenu: submenu forItem: item];
747 [submenu fillWithWidgetValue: wv->contents];
748 [submenu release];
c0342369 749 [item setAction: (SEL)nil];
edfda783
AR
750 }
751 }
752
753 [self setMenuChangedMessagesEnabled: YES];
754#ifdef NS_IMPL_GNUSTEP
755 if ([[self window] isVisible])
756 [self sizeToFit];
4393663b 757#endif
edfda783
AR
758}
759
760
761/* adds an empty submenu and returns it */
9c5bd55a 762- (EmacsMenu *)addSubmenuWithTitle: (const char *)title forFrame: (struct frame *)f
edfda783
AR
763{
764 NSString *titleStr = [NSString stringWithUTF8String: title];
15034960 765 NSMenuItem *item = [self addItemWithTitle: titleStr
c0342369 766 action: (SEL)nil /*@selector (menuDown:) */
15034960 767 keyEquivalent: @""];
edfda783
AR
768 EmacsMenu *submenu = [[EmacsMenu alloc] initWithTitle: titleStr frame: f];
769 [self setSubmenu: submenu forItem: item];
770 [submenu release];
771 return submenu;
772}
773
774/* run a menu in popup mode */
775- (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f
7cded46f 776 keymaps: (bool)keymaps
edfda783
AR
777{
778 EmacsView *view = FRAME_NS_VIEW (f);
3d608a86
J
779 NSEvent *e, *event;
780 long retVal;
781
edfda783
AR
782/* p = [view convertPoint:p fromView: nil]; */
783 p.y = NSHeight ([view frame]) - p.y;
3d608a86
J
784 e = [[view window] currentEvent];
785 event = [NSEvent mouseEventWithType: NSRightMouseDown
786 location: p
787 modifierFlags: 0
788 timestamp: [e timestamp]
789 windowNumber: [[view window] windowNumber]
790 context: [e context]
791 eventNumber: 0/*[e eventNumber] */
792 clickCount: 1
793 pressure: 0];
edfda783
AR
794
795 context_menu_value = -1;
796 [NSMenu popUpContextMenu: self withEvent: event forView: view];
797 retVal = context_menu_value;
798 context_menu_value = 0;
facfbbbd
SM
799 return retVal > 0
800 ? find_and_return_menu_selection (f, keymaps, (void *)retVal)
801 : Qnil;
edfda783
AR
802}
803
804@end /* EmacsMenu */
805
806
807
808/* ==========================================================================
809
810 Context Menu: implementing functions
811
812 ========================================================================== */
813
ef7417fd 814Lisp_Object
a10c8269 815ns_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
42ca4633 816 Lisp_Object title, const char **error)
edfda783
AR
817{
818 EmacsMenu *pmenu;
edfda783 819 NSPoint p;
0dc8cf50 820 Lisp_Object tem;
d311d28c 821 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
edfda783
AR
822 widget_value *wv, *first_wv = 0;
823
f0177f86
EZ
824 block_input ();
825
ef7417fd 826 p.x = x; p.y = y;
edfda783
AR
827
828 /* now parse stage 2 as in ns_update_menubar */
5668fb88 829 wv = make_widget_value ("contextmenu", NULL, true, Qnil);
edfda783 830 wv->button_type = BUTTON_TYPE_NONE;
edfda783
AR
831 first_wv = wv;
832
edfda783 833#if 0
df2142db 834 /* FIXME: a couple of one-line differences prevent reuse */
7cded46f 835 wv = digest_single_submenu (0, menu_items_used, 0);
edfda783
AR
836#else
837 {
838 widget_value *save_wv = 0, *prev_wv = 0;
839 widget_value **submenu_stack
38182d90 840 = alloca (menu_items_used * sizeof *submenu_stack);
edfda783 841/* Lisp_Object *subprefix_stack
38182d90 842 = alloca (menu_items_used * sizeof *subprefix_stack); */
edfda783
AR
843 int submenu_depth = 0;
844 int first_pane = 1;
845 int i;
846
847 /* Loop over all panes and items, filling in the tree. */
848 i = 0;
849 while (i < menu_items_used)
850 {
96fb4434 851 if (EQ (AREF (menu_items, i), Qnil))
edfda783
AR
852 {
853 submenu_stack[submenu_depth++] = save_wv;
854 save_wv = prev_wv;
855 prev_wv = 0;
856 first_pane = 1;
857 i++;
858 }
96fb4434 859 else if (EQ (AREF (menu_items, i), Qlambda))
edfda783
AR
860 {
861 prev_wv = save_wv;
862 save_wv = submenu_stack[--submenu_depth];
863 first_pane = 0;
864 i++;
865 }
96fb4434 866 else if (EQ (AREF (menu_items, i), Qt)
edfda783
AR
867 && submenu_depth != 0)
868 i += MENU_ITEMS_PANE_LENGTH;
869 /* Ignore a nil in the item list.
870 It's meaningful only for dialog boxes. */
96fb4434 871 else if (EQ (AREF (menu_items, i), Qquote))
edfda783 872 i += 1;
96fb4434 873 else if (EQ (AREF (menu_items, i), Qt))
edfda783
AR
874 {
875 /* Create a new pane. */
876 Lisp_Object pane_name, prefix;
9c5bd55a 877 const char *pane_string;
edfda783
AR
878
879 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
880 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
881
882#ifndef HAVE_MULTILINGUAL_MENU
883 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
884 {
885 pane_name = ENCODE_MENU_STRING (pane_name);
886 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
887 }
888#endif
889 pane_string = (NILP (pane_name)
51b59d79 890 ? "" : SSDATA (pane_name));
edfda783
AR
891 /* If there is just one top-level pane, put all its items directly
892 under the top-level menu. */
893 if (menu_items_n_panes == 1)
894 pane_string = "";
895
896 /* If the pane has a meaningful name,
897 make the pane a top-level menu item
898 with its items as a submenu beneath it. */
899 if (!keymaps && strcmp (pane_string, ""))
900 {
5668fb88 901 wv = make_widget_value (pane_string, NULL, true, Qnil);
edfda783
AR
902 if (save_wv)
903 save_wv->next = wv;
904 else
905 first_wv->contents = wv;
edfda783
AR
906 if (keymaps && !NILP (prefix))
907 wv->name++;
edfda783 908 wv->button_type = BUTTON_TYPE_NONE;
edfda783
AR
909 save_wv = wv;
910 prev_wv = 0;
911 }
912 else if (first_pane)
913 {
914 save_wv = wv;
915 prev_wv = 0;
916 }
917 first_pane = 0;
918 i += MENU_ITEMS_PANE_LENGTH;
919 }
920 else
921 {
922 /* Create a new item within current pane. */
923 Lisp_Object item_name, enable, descrip, def, type, selected, help;
924 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
925 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
926 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
927 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
928 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
929 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
930 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
931
932#ifndef HAVE_MULTILINGUAL_MENU
933 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
934 {
935 item_name = ENCODE_MENU_STRING (item_name);
936 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
937 }
938
939 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
940 {
941 descrip = ENCODE_MENU_STRING (descrip);
942 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
943 }
944#endif /* not HAVE_MULTILINGUAL_MENU */
945
5668fb88
DA
946 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enabled),
947 STRINGP (help) ? help : Qnil);
edfda783
AR
948 if (prev_wv)
949 prev_wv->next = wv;
950 else
951 save_wv->contents = wv;
edfda783 952 if (!NILP (descrip))
51b59d79 953 wv->key = SSDATA (descrip);
edfda783
AR
954 /* If this item has a null value,
955 make the call_data null so that it won't display a box
956 when the mouse is on it. */
4939150c 957 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
edfda783
AR
958
959 if (NILP (type))
960 wv->button_type = BUTTON_TYPE_NONE;
961 else if (EQ (type, QCtoggle))
962 wv->button_type = BUTTON_TYPE_TOGGLE;
963 else if (EQ (type, QCradio))
964 wv->button_type = BUTTON_TYPE_RADIO;
965 else
1088b922 966 emacs_abort ();
edfda783
AR
967
968 wv->selected = !NILP (selected);
969
edfda783
AR
970 prev_wv = wv;
971
972 i += MENU_ITEMS_ITEM_LENGTH;
973 }
974 }
975 }
976#endif
977
978 if (!NILP (title))
979 {
5668fb88
DA
980 widget_value *wv_title;
981 widget_value *wv_sep = make_widget_value ("--", NULL, false, Qnil);
edfda783
AR
982
983 /* Maybe replace this separator with a bitmap or owner-draw item
984 so that it looks better. Having two separators looks odd. */
edfda783 985 wv_sep->next = first_wv->contents;
edfda783
AR
986
987#ifndef HAVE_MULTILINGUAL_MENU
988 if (STRING_MULTIBYTE (title))
989 title = ENCODE_MENU_STRING (title);
990#endif
5668fb88 991 wv_title = make_widget_value (SSDATA (title), NULL, false, Qnil);
edfda783 992 wv_title->button_type = BUTTON_TYPE_NONE;
edfda783
AR
993 wv_title->next = wv_sep;
994 first_wv->contents = wv_title;
995 }
996
997 pmenu = [[EmacsMenu alloc] initWithTitle:
0dc8cf50 998 [NSString stringWithUTF8String: SSDATA (title)]];
edfda783
AR
999 [pmenu fillWithWidgetValue: first_wv->contents];
1000 free_menubar_widget_value_tree (first_wv);
ef7417fd 1001 unbind_to (specpdl_count, Qnil);
edfda783 1002
07b87a10 1003 popup_activated_flag = 1;
edfda783 1004 tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps];
07b87a10 1005 popup_activated_flag = 0;
edfda783
AR
1006 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
1007
f0177f86 1008 unblock_input ();
edfda783
AR
1009 return tem;
1010}
1011
1012
edfda783
AR
1013/* ==========================================================================
1014
1015 Toolbar: externally-called functions
1016
1017 ========================================================================== */
1018
1019void
a10c8269 1020free_frame_tool_bar (struct frame *f)
edfda783
AR
1021/* --------------------------------------------------------------------------
1022 Under NS we just hide the toolbar until it might be needed again.
1023 -------------------------------------------------------------------------- */
1024{
abe13366 1025 EmacsView *view = FRAME_NS_VIEW (f);
4d7e6e51 1026 block_input ();
abe13366
JD
1027 view->wait_for_tool_bar = NO;
1028 [[view toolbar] setVisible: NO];
581a8100 1029 FRAME_TOOLBAR_HEIGHT (f) = 0;
4d7e6e51 1030 unblock_input ();
edfda783
AR
1031}
1032
1033void
a10c8269 1034update_frame_tool_bar (struct frame *f)
edfda783
AR
1035/* --------------------------------------------------------------------------
1036 Update toolbar contents
1037 -------------------------------------------------------------------------- */
1038{
c0342369 1039 int i, k = 0;
581a8100
J
1040 EmacsView *view = FRAME_NS_VIEW (f);
1041 NSWindow *window = [view window];
1042 EmacsToolbar *toolbar = [view toolbar];
edfda783 1043
f9d45267 1044 if (view == nil || toolbar == nil) return;
4d7e6e51 1045 block_input ();
c0342369
JD
1046
1047#ifdef NS_IMPL_COCOA
edfda783 1048 [toolbar clearActive];
c0342369
JD
1049#else
1050 [toolbar clearAll];
1051#endif
edfda783
AR
1052
1053 /* update EmacsToolbar as in GtkUtils, build items list */
1054 for (i = 0; i < f->n_tool_bar_items; ++i)
1055 {
e69b0960 1056#define TOOLPROP(IDX) AREF (f->tool_bar_items, \
edfda783
AR
1057 i * TOOL_BAR_ITEM_NSLOTS + (IDX))
1058
1059 BOOL enabled_p = !NILP (TOOLPROP (TOOL_BAR_ITEM_ENABLED_P));
edfda783 1060 int idx;
13464394 1061 ptrdiff_t img_id;
edfda783
AR
1062 struct image *img;
1063 Lisp_Object image;
1064 Lisp_Object helpObj;
9c5bd55a 1065 const char *helpText;
edfda783 1066
c0342369
JD
1067 /* Check if this is a separator. */
1068 if (EQ (TOOLPROP (TOOL_BAR_ITEM_TYPE), Qt))
1069 {
a6c4680a 1070 /* Skip separators. Newer OSX don't show them, and on GNUstep they
c0342369
JD
1071 are wide as a button, thus overflowing the toolbar most of
1072 the time. */
1073 continue;
1074 }
1075
edfda783
AR
1076 /* If image is a vector, choose the image according to the
1077 button state. */
1078 image = TOOLPROP (TOOL_BAR_ITEM_IMAGES);
1079 if (VECTORP (image))
1080 {
1081 /* NS toolbar auto-computes disabled and selected images */
1082 idx = TOOL_BAR_IMAGE_ENABLED_SELECTED;
ef884f23 1083 eassert (ASIZE (image) >= idx);
edfda783
AR
1084 image = AREF (image, idx);
1085 }
1086 else
1087 {
1088 idx = -1;
1089 }
dd723bbd
JD
1090 helpObj = TOOLPROP (TOOL_BAR_ITEM_HELP);
1091 if (NILP (helpObj))
1092 helpObj = TOOLPROP (TOOL_BAR_ITEM_CAPTION);
51b59d79 1093 helpText = NILP (helpObj) ? "" : SSDATA (helpObj);
dd723bbd 1094
edfda783
AR
1095 /* Ignore invalid image specifications. */
1096 if (!valid_image_p (image))
1097 {
dd723bbd 1098 /* Don't log anything, GNUS makes invalid images all the time. */
edfda783
AR
1099 continue;
1100 }
1101
1102 img_id = lookup_image (f, image);
1103 img = IMAGE_FROM_ID (f, img_id);
1104 prepare_image_for_display (f, img);
1105
1106 if (img->load_failed_p || img->pixmap == nil)
1107 {
1108 NSLog (@"Could not prepare toolbar image for display.");
1109 continue;
1110 }
1111
c0342369
JD
1112 [toolbar addDisplayItemWithImage: img->pixmap
1113 idx: k++
1114 tag: i
1115 helpText: helpText
edfda783
AR
1116 enabled: enabled_p];
1117#undef TOOLPROP
1118 }
1119
1120 if (![toolbar isVisible])
1121 [toolbar setVisible: YES];
1122
c0342369 1123#ifdef NS_IMPL_COCOA
edfda783
AR
1124 if ([toolbar changed])
1125 {
1126 /* inform app that toolbar has changed */
1127 NSDictionary *dict = [toolbar configurationDictionary];
1128 NSMutableDictionary *newDict = [dict mutableCopy];
1129 NSEnumerator *keys = [[dict allKeys] objectEnumerator];
79e721e0 1130 id key;
edfda783
AR
1131 while ((key = [keys nextObject]) != nil)
1132 {
1133 NSObject *val = [dict objectForKey: key];
1134 if ([val isKindOfClass: [NSArray class]])
1135 {
1136 [newDict setObject:
1137 [toolbar toolbarDefaultItemIdentifiers: toolbar]
1138 forKey: key];
1139 break;
1140 }
1141 }
1142 [toolbar setConfigurationFromDictionary: newDict];
1143 [newDict release];
1144 }
c0342369 1145#endif
edfda783 1146
581a8100
J
1147 FRAME_TOOLBAR_HEIGHT (f) =
1148 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1149 - FRAME_NS_TITLEBAR_HEIGHT (f);
f9d45267
JD
1150 if (FRAME_TOOLBAR_HEIGHT (f) < 0) // happens if frame is fullscreen.
1151 FRAME_TOOLBAR_HEIGHT (f) = 0;
1152
1153 if (view->wait_for_tool_bar && FRAME_TOOLBAR_HEIGHT (f) > 0)
1154 [view setNeedsDisplay: YES];
1155
1156 unblock_input ();
edfda783
AR
1157}
1158
1159
1160/* ==========================================================================
1161
1162 Toolbar: class implementation
1163
1164 ========================================================================== */
1165
1166@implementation EmacsToolbar
1167
1168- initForView: (EmacsView *)view withIdentifier: (NSString *)identifier
1169{
1170 self = [super initWithIdentifier: identifier];
1171 emacsView = view;
1172 [self setDisplayMode: NSToolbarDisplayModeIconOnly];
1173 [self setSizeMode: NSToolbarSizeModeSmall];
1174 [self setDelegate: self];
1175 identifierToItem = [[NSMutableDictionary alloc] initWithCapacity: 10];
1176 activeIdentifiers = [[NSMutableArray alloc] initWithCapacity: 8];
c0342369 1177 prevIdentifiers = nil;
edfda783
AR
1178 prevEnablement = enablement = 0L;
1179 return self;
1180}
1181
1182- (void)dealloc
1183{
1184 [prevIdentifiers release];
1185 [activeIdentifiers release];
1186 [identifierToItem release];
1187 [super dealloc];
1188}
1189
1190- (void) clearActive
1191{
1192 [prevIdentifiers release];
1193 prevIdentifiers = [activeIdentifiers copy];
1194 [activeIdentifiers removeAllObjects];
1195 prevEnablement = enablement;
1196 enablement = 0L;
1197}
1198
c0342369
JD
1199- (void) clearAll
1200{
1201 [self clearActive];
1202 while ([[self items] count] > 0)
1203 [self removeItemAtIndex: 0];
1204}
1205
edfda783
AR
1206- (BOOL) changed
1207{
1208 return [activeIdentifiers isEqualToArray: prevIdentifiers] &&
1209 enablement == prevEnablement ? NO : YES;
1210}
1211
c0342369
JD
1212- (void) addDisplayItemWithImage: (EmacsImage *)img
1213 idx: (int)idx
1214 tag: (int)tag
1215 helpText: (const char *)help
1216 enabled: (BOOL)enabled
edfda783
AR
1217{
1218 /* 1) come up w/identifier */
facfbbbd 1219 NSString *identifier
fb83ea63 1220 = [NSString stringWithFormat: @"%lu", (unsigned long)[img hash]];
c0342369 1221 [activeIdentifiers addObject: identifier];
edfda783
AR
1222
1223 /* 2) create / reuse item */
1224 NSToolbarItem *item = [identifierToItem objectForKey: identifier];
1225 if (item == nil)
1226 {
1227 item = [[[NSToolbarItem alloc] initWithItemIdentifier: identifier]
1228 autorelease];
1229 [item setImage: img];
f3f08c28 1230 [item setToolTip: [NSString stringWithUTF8String: help]];
edfda783
AR
1231 [item setTarget: emacsView];
1232 [item setAction: @selector (toolbarClicked:)];
c0342369 1233 [identifierToItem setObject: item forKey: identifier];
edfda783
AR
1234 }
1235
c0342369
JD
1236#ifdef NS_IMPL_GNUSTEP
1237 [self insertItemWithItemIdentifier: identifier atIndex: idx];
1238#endif
cf7a0de6 1239
c0342369 1240 [item setTag: tag];
edfda783
AR
1241 [item setEnabled: enabled];
1242
1243 /* 3) update state */
edfda783
AR
1244 enablement = (enablement << 1) | (enabled == YES);
1245}
1246
1247/* This overrides super's implementation, which automatically sets
1248 all items to enabled state (for some reason). */
c0342369
JD
1249- (void)validateVisibleItems
1250{
1251}
edfda783
AR
1252
1253
1254/* delegate methods */
1255
1256- (NSToolbarItem *)toolbar: (NSToolbar *)toolbar
1257 itemForItemIdentifier: (NSString *)itemIdentifier
1258 willBeInsertedIntoToolbar: (BOOL)flag
1259{
1260 /* look up NSToolbarItem by identifier and return... */
1261 return [identifierToItem objectForKey: itemIdentifier];
1262}
1263
1264- (NSArray *)toolbarDefaultItemIdentifiers: (NSToolbar *)toolbar
1265{
1266 /* return entire set.. */
1267 return activeIdentifiers;
1268}
1269
1270/* for configuration palette (not yet supported) */
1271- (NSArray *)toolbarAllowedItemIdentifiers: (NSToolbar *)toolbar
1272{
1273 /* return entire set... */
c0342369
JD
1274 return activeIdentifiers;
1275 //return [identifierToItem allKeys];
edfda783
AR
1276}
1277
1278/* optional and unneeded */
1279/* - toolbarWillAddItem: (NSNotification *)notification { } */
1280/* - toolbarDidRemoveItem: (NSNotification *)notification { } */
1281/* - (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar */
1282
1283@end /* EmacsToolbar */
1284
1285
1286
1287/* ==========================================================================
1288
1289 Tooltip: class implementation
1290
1291 ========================================================================== */
1292
1293/* Needed because NeXTstep does not provide enough control over tooltip
1294 display. */
1295@implementation EmacsTooltip
1296
1297- init
1298{
1299 NSColor *col = [NSColor colorWithCalibratedRed: 1.0 green: 1.0
1300 blue: 0.792 alpha: 0.95];
1301 NSFont *font = [NSFont toolTipsFontOfSize: 0];
1302 NSFont *sfont = [font screenFont];
1303 int height = [sfont ascender] - [sfont descender];
1304/*[font boundingRectForFont].size.height; */
1305 NSRect r = NSMakeRect (0, 0, 100, height+6);
1306
1307 textField = [[NSTextField alloc] initWithFrame: r];
1308 [textField setFont: font];
1309 [textField setBackgroundColor: col];
1310
1311 [textField setEditable: NO];
1312 [textField setSelectable: NO];
ffe57a7a
AA
1313 [textField setBordered: NO];
1314 [textField setBezeled: NO];
edfda783
AR
1315 [textField setDrawsBackground: YES];
1316
1317 win = [[NSWindow alloc]
1318 initWithContentRect: [textField frame]
1319 styleMask: 0
1320 backing: NSBackingStoreBuffered
1321 defer: YES];
ffe57a7a 1322 [win setHasShadow: YES];
edfda783
AR
1323 [win setReleasedWhenClosed: NO];
1324 [win setDelegate: self];
1325 [[win contentView] addSubview: textField];
1326/* [win setBackgroundColor: col]; */
1327 [win setOpaque: NO];
1328
1329 return self;
1330}
1331
1332- (void) dealloc
1333{
1334 [win close];
1335 [win release];
1336 [textField release];
1337 [super dealloc];
1338}
1339
1340- (void) setText: (char *)text
1341{
1342 NSString *str = [NSString stringWithUTF8String: text];
ffe57a7a
AA
1343 NSRect r = [textField frame];
1344 NSSize tooltipDims;
1345
edfda783 1346 [textField setStringValue: str];
ffe57a7a
AA
1347 tooltipDims = [[textField cell] cellSize];
1348
1349 r.size.width = tooltipDims.width;
1350 r.size.height = tooltipDims.height;
1351 [textField setFrame: r];
edfda783
AR
1352}
1353
1354- (void) showAtX: (int)x Y: (int)y for: (int)seconds
1355{
1356 NSRect wr = [win frame];
1357
1358 wr.origin = NSMakePoint (x, y);
1359 wr.size = [textField frame].size;
1360
1361 [win setFrame: wr display: YES];
f38ab167 1362 [win setLevel: NSPopUpMenuWindowLevel];
edfda783
AR
1363 [win orderFront: self];
1364 [win display];
1365 timer = [NSTimer scheduledTimerWithTimeInterval: (float)seconds target: self
1366 selector: @selector (hide)
1367 userInfo: nil repeats: NO];
1368 [timer retain];
1369}
1370
1371- (void) hide
1372{
1373 [win close];
1374 if (timer != nil)
1375 {
1376 if ([timer isValid])
1377 [timer invalidate];
1378 [timer release];
1379 timer = nil;
1380 }
1381}
1382
1383- (BOOL) isActive
1384{
1385 return timer != nil;
1386}
1387
1388- (NSRect) frame
1389{
1390 return [textField frame];
1391}
1392
1393@end /* EmacsTooltip */
1394
1395
1396
1397/* ==========================================================================
1398
1399 Popup Dialog: implementing functions
1400
1401 ========================================================================== */
1402
9d7fa573
JD
1403struct Popdown_data
1404{
1405 NSAutoreleasePool *pool;
1406 EmacsDialogPanel *dialog;
1407};
c96169a0 1408
27e498e6
PE
1409static void
1410pop_down_menu (void *arg)
c96169a0 1411{
27e498e6 1412 struct Popdown_data *unwind_data = arg;
9d7fa573 1413
4d7e6e51 1414 block_input ();
ba301db3
AR
1415 if (popup_activated_flag)
1416 {
9d7fa573 1417 EmacsDialogPanel *panel = unwind_data->dialog;
ba301db3 1418 popup_activated_flag = 0;
9d7fa573
JD
1419 [panel close];
1420 [unwind_data->pool release];
ba301db3 1421 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
ba301db3 1422 }
9d7fa573
JD
1423
1424 xfree (unwind_data);
4d7e6e51 1425 unblock_input ();
c96169a0
AR
1426}
1427
1428
edfda783 1429Lisp_Object
0afa0aab 1430ns_popup_dialog (Lisp_Object position, Lisp_Object header, Lisp_Object contents)
edfda783
AR
1431{
1432 id dialog;
d6f0886c 1433 Lisp_Object window, tem, title;
edfda783
AR
1434 struct frame *f;
1435 NSPoint p;
1436 BOOL isQ;
9d7fa573 1437 NSAutoreleasePool *pool;
edfda783
AR
1438
1439 NSTRACE (x-popup-dialog);
96fb4434 1440
edfda783
AR
1441 isQ = NILP (header);
1442
8612b71a
AR
1443 if (EQ (position, Qt)
1444 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
1445 || EQ (XCAR (position), Qtool_bar))))
edfda783
AR
1446 {
1447 window = selected_window;
1448 }
1449 else if (CONSP (position))
1450 {
1451 Lisp_Object tem;
1452 tem = Fcar (position);
1453 if (XTYPE (tem) == Lisp_Cons)
1454 window = Fcar (Fcdr (position));
1455 else
1456 {
1457 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
1458 window = Fcar (tem); /* POSN_WINDOW (tem) */
1459 }
1460 }
8612b71a 1461 else if (WINDOWP (position) || FRAMEP (position))
edfda783
AR
1462 {
1463 window = position;
1464 }
1465 else
8612b71a
AR
1466 window = Qnil;
1467
edfda783
AR
1468 if (FRAMEP (window))
1469 f = XFRAME (window);
8612b71a 1470 else if (WINDOWP (window))
edfda783
AR
1471 {
1472 CHECK_LIVE_WINDOW (window);
1473 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
1474 }
8612b71a
AR
1475 else
1476 CHECK_WINDOW (window);
1477
7452b7bd
DA
1478 check_window_system (f);
1479
edfda783
AR
1480 p.x = (int)f->left_pos + ((int)FRAME_COLUMN_WIDTH (f) * f->text_cols)/2;
1481 p.y = (int)f->top_pos + (FRAME_LINE_HEIGHT (f) * f->text_lines)/2;
3175b12a 1482
d6f0886c
JD
1483 title = Fcar (contents);
1484 CHECK_STRING (title);
1485
1486 if (NILP (Fcar (Fcdr (contents))))
1487 /* No buttons specified, add an "Ok" button so users can pop down
1488 the dialog. */
6c6f1994 1489 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
d6f0886c 1490
4d7e6e51 1491 block_input ();
9d7fa573 1492 pool = [[NSAutoreleasePool alloc] init];
edfda783
AR
1493 dialog = [[EmacsDialogPanel alloc] initFromContents: contents
1494 isQuestion: isQ];
9d7fa573 1495
c96169a0 1496 {
d311d28c 1497 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
9d7fa573
JD
1498 struct Popdown_data *unwind_data = xmalloc (sizeof (*unwind_data));
1499
1500 unwind_data->pool = pool;
1501 unwind_data->dialog = dialog;
4939150c 1502
27e498e6 1503 record_unwind_protect_ptr (pop_down_menu, unwind_data);
c96169a0
AR
1504 popup_activated_flag = 1;
1505 tem = [dialog runDialogAt: p];
ba301db3 1506 unbind_to (specpdl_count, Qnil); /* calls pop_down_menu */
c96169a0 1507 }
9d7fa573 1508
4d7e6e51 1509 unblock_input ();
c96169a0 1510
edfda783
AR
1511 return tem;
1512}
1513
1514
1515/* ==========================================================================
1516
1517 Popup Dialog: class implementation
1518
1519 ========================================================================== */
1520
1521@interface FlippedView : NSView
1522{
1523}
1524@end
1525
1526@implementation FlippedView
1527- (BOOL)isFlipped
1528{
1529 return YES;
1530}
1531@end
1532
1533@implementation EmacsDialogPanel
1534
1535#define SPACER 8.0
1536#define ICONSIZE 64.0
1537#define TEXTHEIGHT 20.0
1538#define MINCELLWIDTH 90.0
1539
f3f08c28 1540- initWithContentRect: (NSRect)contentRect styleMask: (NSUInteger)aStyle
edfda783
AR
1541 backing: (NSBackingStoreType)backingType defer: (BOOL)flag
1542{
1543 NSSize spacing = {SPACER, SPACER};
1544 NSRect area;
facfbbbd 1545 id cell;
9d7fa573
JD
1546 NSImageView *imgView;
1547 FlippedView *contentView;
1548 NSImage *img;
1549
0f19feff 1550 dialog_return = Qundefined;
7f8941d8 1551 button_values = NULL;
9d7fa573
JD
1552 area.origin.x = 3*SPACER;
1553 area.origin.y = 2*SPACER;
1554 area.size.width = ICONSIZE;
1555 area.size.height= ICONSIZE;
1556 img = [[NSImage imageNamed: @"NSApplicationIcon"] copy];
1557 [img setScalesWhenResized: YES];
1558 [img setSize: NSMakeSize (ICONSIZE, ICONSIZE)];
1559 imgView = [[NSImageView alloc] initWithFrame: area];
1560 [imgView setImage: img];
1561 [imgView setEditable: NO];
1562 [img autorelease];
1563 [imgView autorelease];
edfda783 1564
c0342369 1565 aStyle = NSTitledWindowMask|NSClosableWindowMask|NSUtilityWindowMask;
edfda783
AR
1566 flag = YES;
1567 rows = 0;
1568 cols = 1;
1569 [super initWithContentRect: contentRect styleMask: aStyle
1570 backing: backingType defer: flag];
1571 contentView = [[FlippedView alloc] initWithFrame: [[self contentView] frame]];
9d7fa573
JD
1572 [contentView autorelease];
1573
edfda783
AR
1574 [self setContentView: contentView];
1575
1576 [[self contentView] setAutoresizesSubviews: YES];
1577
1578 [[self contentView] addSubview: imgView];
1579 [self setTitle: @""];
1580
1581 area.origin.x += ICONSIZE+2*SPACER;
1582/* area.origin.y = TEXTHEIGHT; ICONSIZE/2-10+SPACER; */
1583 area.size.width = 400;
1584 area.size.height= TEXTHEIGHT;
1585 command = [[[NSTextField alloc] initWithFrame: area] autorelease];
1586 [[self contentView] addSubview: command];
3988c7d6 1587 [command setStringValue: ns_app_name];
edfda783
AR
1588 [command setDrawsBackground: NO];
1589 [command setBezeled: NO];
1590 [command setSelectable: NO];
1591 [command setFont: [NSFont boldSystemFontOfSize: 13.0]];
1592
1593/* area.origin.x = ICONSIZE+2*SPACER;
1594 area.origin.y = TEXTHEIGHT + 2*SPACER;
1595 area.size.width = 400;
1596 area.size.height= 2;
1597 tem = [[[NSBox alloc] initWithFrame: area] autorelease];
1598 [[self contentView] addSubview: tem];
1599 [tem setTitlePosition: NSNoTitle];
1600 [tem setAutoresizingMask: NSViewWidthSizable];*/
1601
1602/* area.origin.x = ICONSIZE+2*SPACER; */
1603 area.origin.y += TEXTHEIGHT+SPACER;
1604 area.size.width = 400;
1605 area.size.height= TEXTHEIGHT;
1606 title = [[[NSTextField alloc] initWithFrame: area] autorelease];
1607 [[self contentView] addSubview: title];
1608 [title setDrawsBackground: NO];
1609 [title setBezeled: NO];
1610 [title setSelectable: NO];
1611 [title setFont: [NSFont systemFontOfSize: 11.0]];
1612
1613 cell = [[[NSButtonCell alloc] initTextCell: @""] autorelease];
1614 [cell setBordered: NO];
1615 [cell setEnabled: NO];
1616 [cell setCellAttribute: NSCellIsInsetButton to: 8];
1617 [cell setBezelStyle: NSRoundedBezelStyle];
1618
96fb4434
PE
1619 matrix = [[NSMatrix alloc] initWithFrame: contentRect
1620 mode: NSHighlightModeMatrix
1621 prototype: cell
1622 numberOfRows: 0
edfda783 1623 numberOfColumns: 1];
edfda783
AR
1624 [matrix setFrameOrigin: NSMakePoint (area.origin.x,
1625 area.origin.y + (TEXTHEIGHT+3*SPACER))];
1626 [matrix setIntercellSpacing: spacing];
9d7fa573 1627 [matrix autorelease];
edfda783 1628
9d7fa573 1629 [[self contentView] addSubview: matrix];
edfda783
AR
1630 [self setOneShot: YES];
1631 [self setReleasedWhenClosed: YES];
1632 [self setHidesOnDeactivate: YES];
1633 return self;
1634}
1635
1636
1637- (BOOL)windowShouldClose: (id)sender
1638{
7f8941d8 1639 window_closed = YES;
0f19feff 1640 [NSApp stop:self];
edfda783
AR
1641 return NO;
1642}
1643
7f8941d8
JD
1644- (void)dealloc
1645{
1646 xfree (button_values);
1647 [super dealloc];
1648}
edfda783 1649
7f8941d8 1650- (void)process_dialog: (Lisp_Object) list
edfda783 1651{
7f8941d8 1652 Lisp_Object item, lst = list;
edfda783 1653 int row = 0;
7f8941d8
JD
1654 int buttons = 0, btnnr = 0;
1655
1656 for (; XTYPE (lst) == Lisp_Cons; lst = XCDR (lst))
1657 {
1658 item = XCAR (list);
1659 if (XTYPE (item) == Lisp_Cons)
1660 ++buttons;
1661 }
1662
1663 if (buttons > 0)
7d652d97 1664 button_values = xmalloc (buttons * sizeof *button_values);
edfda783
AR
1665
1666 for (; XTYPE (list) == Lisp_Cons; list = XCDR (list))
1667 {
1668 item = XCAR (list);
1669 if (XTYPE (item) == Lisp_String)
1670 {
7f8941d8 1671 [self addString: SSDATA (item) row: row++];
edfda783
AR
1672 }
1673 else if (XTYPE (item) == Lisp_Cons)
1674 {
7f8941d8
JD
1675 button_values[btnnr] = XCDR (item);
1676 [self addButton: SSDATA (XCAR (item)) value: btnnr row: row++];
1677 ++btnnr;
edfda783
AR
1678 }
1679 else if (NILP (item))
1680 {
7f8941d8 1681 [self addSplit];
edfda783
AR
1682 row = 0;
1683 }
1684 }
1685}
1686
1687
7f8941d8 1688- (void)addButton: (char *)str value: (int)tag row: (int)row
edfda783
AR
1689{
1690 id cell;
96fb4434 1691
edfda783
AR
1692 if (row >= rows)
1693 {
1694 [matrix addRow];
1695 rows++;
1696 }
1697 cell = [matrix cellAtRow: row column: cols-1];
1698 [cell setTarget: self];
1699 [cell setAction: @selector (clicked: )];
1700 [cell setTitle: [NSString stringWithUTF8String: str]];
7f8941d8 1701 [cell setTag: tag];
edfda783
AR
1702 [cell setBordered: YES];
1703 [cell setEnabled: YES];
edfda783
AR
1704}
1705
1706
7f8941d8 1707- (void)addString: (char *)str row: (int)row
edfda783
AR
1708{
1709 id cell;
96fb4434 1710
edfda783
AR
1711 if (row >= rows)
1712 {
1713 [matrix addRow];
1714 rows++;
1715 }
1716 cell = [matrix cellAtRow: row column: cols-1];
1717 [cell setTitle: [NSString stringWithUTF8String: str]];
1718 [cell setBordered: YES];
1719 [cell setEnabled: NO];
edfda783
AR
1720}
1721
1722
7f8941d8 1723- (void)addSplit
edfda783
AR
1724{
1725 [matrix addColumn];
1726 cols++;
edfda783
AR
1727}
1728
1729
7f8941d8 1730- (void)clicked: sender
edfda783
AR
1731{
1732 NSArray *sellist = nil;
facfbbbd 1733 EMACS_INT seltag;
edfda783
AR
1734
1735 sellist = [sender selectedCells];
7f8941d8
JD
1736 if ([sellist count] < 1)
1737 return;
edfda783 1738
facfbbbd 1739 seltag = [[sellist objectAtIndex: 0] tag];
7f8941d8
JD
1740 dialog_return = button_values[seltag];
1741 [NSApp stop:self];
edfda783
AR
1742}
1743
1744
1745- initFromContents: (Lisp_Object)contents isQuestion: (BOOL)isQ
1746{
1747 Lisp_Object head;
1748 [super init];
1749
1750 if (XTYPE (contents) == Lisp_Cons)
1751 {
1752 head = Fcar (contents);
7f8941d8 1753 [self process_dialog: Fcdr (contents)];
edfda783
AR
1754 }
1755 else
1756 head = contents;
1757
1758 if (XTYPE (head) == Lisp_String)
1759 [title setStringValue:
0dc8cf50 1760 [NSString stringWithUTF8String: SSDATA (head)]];
edfda783
AR
1761 else if (isQ == YES)
1762 [title setStringValue: @"Question"];
1763 else
1764 [title setStringValue: @"Information"];
1765
1766 {
1767 int i;
1768 NSRect r, s, t;
1769
1770 if (cols == 1 && rows > 1) /* Never told where to split */
1771 {
1772 [matrix addColumn];
7f8941d8 1773 for (i = 0; i < rows/2; i++)
edfda783
AR
1774 {
1775 [matrix putCell: [matrix cellAtRow: (rows+1)/2 column: 0]
1776 atRow: i column: 1];
1777 [matrix removeRow: (rows+1)/2];
1778 }
1779 }
1780
1781 [matrix sizeToFit];
1782 {
1783 NSSize csize = [matrix cellSize];
1784 if (csize.width < MINCELLWIDTH)
1785 {
1786 csize.width = MINCELLWIDTH;
1787 [matrix setCellSize: csize];
1788 [matrix sizeToCells];
1789 }
1790 }
1791
1792 [title sizeToFit];
1793 [command sizeToFit];
1794
1795 t = [matrix frame];
1796 r = [title frame];
1797 if (r.size.width+r.origin.x > t.size.width+t.origin.x)
1798 {
1799 t.origin.x = r.origin.x;
1800 t.size.width = r.size.width;
1801 }
1802 r = [command frame];
1803 if (r.size.width+r.origin.x > t.size.width+t.origin.x)
1804 {
1805 t.origin.x = r.origin.x;
1806 t.size.width = r.size.width;
1807 }
1808
1809 r = [self frame];
1810 s = [(NSView *)[self contentView] frame];
1811 r.size.width += t.origin.x+t.size.width +2*SPACER-s.size.width;
1812 r.size.height += t.origin.y+t.size.height+SPACER-s.size.height;
1813 [self setFrame: r display: NO];
1814 }
1815
1816 return self;
1817}
1818
1819
18e27ea8 1820
ddee6515
JD
1821- (void)timeout_handler: (NSTimer *)timedEntry
1822{
0f19feff
JD
1823 NSEvent *nxev = [NSEvent otherEventWithType: NSApplicationDefined
1824 location: NSMakePoint (0, 0)
1825 modifierFlags: 0
1826 timestamp: 0
1827 windowNumber: [[NSApp mainWindow] windowNumber]
1828 context: [NSApp context]
1829 subtype: 0
1830 data1: 0
1831 data2: 0];
1832
7f8941d8 1833 timer_fired = YES;
0f19feff
JD
1834 /* We use sto because stopModal/abortModal out of the main loop does not
1835 seem to work in 10.6. But as we use stop we must send a real event so
1836 the stop is seen and acted upon. */
1837 [NSApp stop:self];
1838 [NSApp postEvent: nxev atStart: NO];
ddee6515
JD
1839}
1840
edfda783
AR
1841- (Lisp_Object)runDialogAt: (NSPoint)p
1842{
0f19feff 1843 Lisp_Object ret = Qundefined;
edfda783 1844
ddee6515 1845 while (popup_activated_flag)
edfda783 1846 {
ddee6515 1847 NSTimer *tmo = nil;
43aac990 1848 struct timespec next_time = timer_check ();
ddee6515 1849
43aac990 1850 if (timespec_valid_p (next_time))
ddee6515 1851 {
43aac990 1852 double time = timespectod (next_time);
ddee6515
JD
1853 tmo = [NSTimer timerWithTimeInterval: time
1854 target: self
1855 selector: @selector (timeout_handler:)
1856 userInfo: 0
1857 repeats: NO];
1858 [[NSRunLoop currentRunLoop] addTimer: tmo
1859 forMode: NSModalPanelRunLoopMode];
1860 }
7f8941d8 1861 timer_fired = NO;
0f19feff 1862 dialog_return = Qundefined;
7f8941d8 1863 [NSApp runModalForWindow: self];
0f19feff 1864 ret = dialog_return;
ddee6515
JD
1865 if (! timer_fired)
1866 {
1867 if (tmo != nil) [tmo invalidate]; /* Cancels timer */
1868 break;
1869 }
edfda783 1870 }
edfda783 1871
7f8941d8
JD
1872 if (EQ (ret, Qundefined) && window_closed)
1873 /* Make close button pressed equivalent to C-g. */
1874 Fsignal (Qquit, Qnil);
1875
1876 return ret;
edfda783
AR
1877}
1878
1879@end
1880
1881
edfda783
AR
1882/* ==========================================================================
1883
1884 Lisp definitions
1885
1886 ========================================================================== */
1887
1888DEFUN ("ns-reset-menu", Fns_reset_menu, Sns_reset_menu, 0, 0, 0,
eb6f7ed0 1889 doc: /* Cause the NS menu to be re-calculated. */)
5842a27b 1890 (void)
edfda783
AR
1891{
1892 set_frame_menubar (SELECTED_FRAME (), 1, 0);
1893 return Qnil;
1894}
1895
1896
07b87a10
AR
1897DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
1898 doc: /* Return t if a menu or popup dialog is active. */)
5842a27b 1899 (void)
07b87a10
AR
1900{
1901 return popup_activated () ? Qt : Qnil;
1902}
edfda783
AR
1903
1904/* ==========================================================================
1905
1906 Lisp interface declaration
1907
1908 ========================================================================== */
1909
1910void
3d608a86 1911syms_of_nsmenu (void)
edfda783 1912{
5fecd5fc 1913#ifndef NS_IMPL_COCOA
a6c4680a 1914 /* Don't know how to keep track of this in Next/Open/GNUstep. Always
5fecd5fc
JD
1915 update menus there. */
1916 trackingMenu = 1;
1917#endif
edfda783 1918 defsubr (&Sns_reset_menu);
07b87a10 1919 defsubr (&Smenu_or_popup_active_p);
edfda783 1920
088dcc3e 1921 Qdebug_on_next_call = intern_c_string ("debug-on-next-call");
edfda783
AR
1922 staticpro (&Qdebug_on_next_call);
1923}