X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/150349607cf648e78d34aa16ef1d43d774bc6044..8510724d46951d651a78424e12b93ccee100c665:/src/nsmenu.m diff --git a/src/nsmenu.m b/src/nsmenu.m index 822aa94efa..f6b2075a84 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -1,5 +1,5 @@ /* NeXT/Open/GNUstep and MacOSX Cocoa menu and toolbar module. - Copyright (C) 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -21,7 +21,10 @@ By Adrian Robert, based on code from original nsmenu.m (Carl Edman, Christian Limpach, Scott Bender, Christophe de Dinechin) and code in the Carbon version by Yamamoto Mitsuharu. */ +/* This should be the first include, as it may set up #defines affecting + interpretation of even the system includes. */ #include "config.h" + #include "lisp.h" #include "window.h" #include "buffer.h" @@ -33,9 +36,12 @@ Carbon version by Yamamoto Mitsuharu. */ #include "termhooks.h" #include "keyboard.h" -/* for profiling */ +#define NSMENUPROFILE 0 + +#if NSMENUPROFILE #include #include +#endif #define MenuStagger 10.0 @@ -63,7 +69,11 @@ extern Lisp_Object Voverriding_local_map, Voverriding_local_map_menu_flag, Qoverriding_local_map, Qoverriding_terminal_local_map; extern long context_menu_value; -EmacsMenu *mainMenu, *svcsMenu; +EmacsMenu *mainMenu, *svcsMenu, *dockMenu; + +/* Nonzero means a menu is currently active. */ +static int popup_activated_flag; +static NSModalSession popupSession; /* NOTE: toolbar implementation is at end, following complete menu implementation. */ @@ -76,7 +86,7 @@ EmacsMenu *mainMenu, *svcsMenu; ========================================================================== */ -/*23: FIXME: not currently used, but should normalize with other terms. */ +/* FIXME: not currently used, but should normalize with other terms. */ void x_activate_menubar (struct frame *f) { @@ -94,6 +104,13 @@ free_frame_menubar (struct frame *f) } +int +popup_activated () +{ + return popup_activated_flag; +} + + /* -------------------------------------------------------------------------- Update menubar. Three cases: 1) deep_p = 0, submenu = nil: Fresh switch onto a frame -- either set up @@ -101,7 +118,6 @@ free_frame_menubar (struct frame *f) 2) deep_p = 1, submenu = nil: Recompute all submenus. 3) deep_p = 1, submenu = non-nil: Update contents of a single submenu. -------------------------------------------------------------------------- */ -/*#define NSMENUPROFILE 1 */ void ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu) { @@ -116,7 +132,7 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu) widget_value *wv, *first_wv, *prev_wv = 0; int i; -#ifdef NSMENUPROFILE +#if NSMENUPROFILE struct timeb tb; long t; #endif @@ -150,7 +166,7 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu) [attMenu close]; } -#ifdef NSMENUPROFILE +#if NSMENUPROFILE ftime (&tb); t = -(1000*tb.time+tb.millitm); #endif @@ -316,7 +332,7 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu) { /* No change.. */ -#ifdef NSMENUPROFILE +#if NSMENUPROFILE ftime (&tb); t += 1000*tb.time+tb.millitm; fprintf (stderr, "NO CHANGE! CUTTING OUT after %ld msec.\n", t); @@ -467,7 +483,7 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu) free_menubar_widget_value_tree (first_wv); -#ifdef NSMENUPROFILE +#if NSMENUPROFILE ftime (&tb); t += 1000*tb.time+tb.millitm; fprintf (stderr, "Menu update took %ld msec.\n", t); @@ -558,7 +574,10 @@ name_is_separator (name) since key equivalents are handled through emacs. On Leopard, even keystroke events generate SystemDefined events, but their subtype is 8. */ - if ([event type] != NSSystemDefined || [event subtype] == 8) + if ([event type] != NSSystemDefined || [event subtype] == 8 + /* Also, don't try this if from an event picked up asynchronously, + as lots of lisp evaluation happens in ns_update_menubar. */ + || handling_signal != 0) return; /*fprintf (stderr, "Updating menu '%s'\n", [[self title] UTF8String]); NSLog (@"%@\n", event); */ ns_update_menubar (frame, 1, self); @@ -574,24 +593,31 @@ name_is_separator (name) } -/* parse a wdiget_value's key rep (examples: 's-p', 's-S', '(C-x C-s)', '') - into an accelerator string */ +/* Parse a widget_value's key rep (examples: 's-p', 's-S', '(C-x C-s)', '') + into an accelerator string. We are only able to display a single character + for an accelerator, together with an optional modifier combination. (Under + Carbon more control was possible, but in Cocoa multi-char strings passed to + NSMenuItem get ignored. For now we try to display a super-single letter + combo, and return the others as strings to be appended to the item title. + (This is signaled by setting keyEquivModMask to 0 for now.) */ -(NSString *)parseKeyEquiv: (char *)key { char *tpos = key; - keyEquivModMask = 0; - /* currently we just parse 'super' combinations; - later we'll set keyEquivModMask */ + keyEquivModMask = NSCommandKeyMask; + if (!key || !strlen (key)) return @""; while (*tpos == ' ' || *tpos == '(') tpos++; - if (*tpos != 's'/* || tpos[3] != ')'*/) - return @""; + if (*tpos != 's') { + keyEquivModMask = 0; /* signal */ + return [NSString stringWithUTF8String: tpos]; + } return [NSString stringWithFormat: @"%c", tpos[2]]; } + - (NSMenuItem *)addItemWithWidgetValue: (void *)wvptr { NSMenuItem *item; @@ -610,12 +636,13 @@ name_is_separator (name) title = @"< ? >"; /* (get out in the open so we know about it) */ keyEq = [self parseKeyEquiv: wv->key]; + if (keyEquivModMask == 0) + title = [title stringByAppendingFormat: @" (%@)", keyEq]; item = [self addItemWithTitle: (NSString *)title action: @selector (menuDown:) keyEquivalent: keyEq]; - if (keyEquivModMask) - [item setKeyEquivalentModifierMask: keyEquivModMask]; + [item setKeyEquivalentModifierMask: keyEquivModMask]; [item setEnabled: wv->enabled]; @@ -665,7 +692,7 @@ name_is_separator (name) if (wv->contents) { - EmacsMenu *submenu = [[EmacsMenu alloc] initWithTitle: @"Submenu"]; + EmacsMenu *submenu = [[EmacsMenu alloc] initWithTitle: [item title]]; [self setSubmenu: submenu forItem: item]; [submenu fillWithWidgetValue: wv->contents]; @@ -1117,10 +1144,13 @@ ns_popup_menu (Lisp_Object position, Lisp_Object menu) free_menubar_widget_value_tree (first_wv); unbind_to (specpdl_count2, Qnil); + popup_activated_flag = 1; tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps]; + popup_activated_flag = 0; [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; UNBLOCK_INPUT; + discard_menu_items (); unbind_to (specpdl_count, Qnil); UNGCPRO; @@ -1459,6 +1489,21 @@ update_frame_tool_bar (FRAME_PTR f) ========================================================================== */ + +static Lisp_Object +pop_down_menu (Lisp_Object arg) +{ + struct Lisp_Save_Value *p = XSAVE_VALUE (arg); + popup_activated_flag = 0; + BLOCK_INPUT; + [NSApp endModalSession: popupSession]; + [((EmacsDialogPanel *) (p->pointer)) close]; + [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; + UNBLOCK_INPUT; + return Qnil; +} + + Lisp_Object ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header) { @@ -1474,7 +1519,9 @@ ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header) isQ = NILP (header); - if (EQ (position, Qt)) + if (EQ (position, Qt) + || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) + || EQ (XCAR (position), Qtool_bar)))) { window = selected_window; } @@ -1490,33 +1537,42 @@ ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header) window = Fcar (tem); /* POSN_WINDOW (tem) */ } } - else if (FRAMEP (position)) + else if (WINDOWP (position) || FRAMEP (position)) { window = position; } else - { - CHECK_LIVE_WINDOW (position); - window = position; - } - + window = Qnil; + if (FRAMEP (window)) f = XFRAME (window); - else + else if (WINDOWP (window)) { CHECK_LIVE_WINDOW (window); f = XFRAME (WINDOW_FRAME (XWINDOW (window))); } + else + CHECK_WINDOW (window); + p.x = (int)f->left_pos + ((int)FRAME_COLUMN_WIDTH (f) * f->text_cols)/2; p.y = (int)f->top_pos + (FRAME_LINE_HEIGHT (f) * f->text_lines)/2; + + BLOCK_INPUT; dialog = [[EmacsDialogPanel alloc] initFromContents: contents isQuestion: isQ]; - - tem = [dialog runDialogAt: p]; + { + int specpdl_count = SPECPDL_INDEX (); + record_unwind_protect (pop_down_menu, make_save_value (dialog, 0)); + popup_activated_flag = 1; + tem = [dialog runDialogAt: p]; + popup_activated_flag = 0; + unbind_to (specpdl_count, Qnil); + } [dialog close]; - [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; + UNBLOCK_INPUT; + return tem; } @@ -1732,7 +1788,7 @@ void process_dialog (id window, Lisp_Object list) return self; seltag = [[sellist objectAtIndex: 0] tag]; - if (seltag == XHASH (Qundefined)) // FIXME: BIG UGLY HACK!! + if (seltag != XHASH (Qundefined)) // FIXME: BIG UGLY HACK!! [NSApp stopModalWithCode: seltag]; return self; } @@ -1821,25 +1877,21 @@ void process_dialog (id window, Lisp_Object list) - (Lisp_Object)runDialogAt: (NSPoint)p { - NSEvent *e; - NSModalSession session; int ret; - [self center]; /*XXX p ignored? */ - [self orderFront: NSApp]; - - session = [NSApp beginModalSessionForWindow: self]; - while ((ret = [NSApp runModalSession: session]) == NSRunContinuesResponse) + popupSession = [NSApp beginModalSessionForWindow: self]; + while (popup_activated_flag + && (ret = [NSApp runModalSession: popupSession]) + == NSRunContinuesResponse) { - (e = [NSApp nextEventMatchingMask: NSAnyEventMask - untilDate: [NSDate distantFuture] - inMode: NSEventTrackingRunLoopMode - dequeue: NO]); -/*fprintf (stderr, "ret = %d\te = %p\n", ret, e); */ + /* Run this for timers.el, indep of atimers; might not return. + TODO: use return value to avoid calling every iteration. */ + timer_check (1); + [NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1]]; } - [NSApp endModalSession: session]; + [NSApp endModalSession: popupSession]; - { // FIXME: BIG UGLY HACK!!! + { /* FIXME: BIG UGLY HACK!!! */ Lisp_Object tmp; *(EMACS_INT*)(&tmp) = ret; return tmp; @@ -1849,7 +1901,6 @@ void process_dialog (id window, Lisp_Object list) @end - /* ========================================================================== Lisp definitions @@ -1934,6 +1985,12 @@ for instance using the window manager, then this produces a quit and return ns_popup_dialog (position, contents, header); } +DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0, + doc: /* Return t if a menu or popup dialog is active. */) + () +{ + return popup_activated () ? Qt : Qnil; +} /* ========================================================================== @@ -1947,6 +2004,7 @@ syms_of_nsmenu () defsubr (&Sx_popup_menu); defsubr (&Sx_popup_dialog); defsubr (&Sns_reset_menu); + defsubr (&Smenu_or_popup_active_p); staticpro (&menu_items); menu_items = Qnil;