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