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