1 /* NeXT/Open/GNUstep and MacOSX Cocoa menu and toolbar module.
2 Copyright (C) 2007-2012 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 By Adrian Robert, based on code from original nsmenu.m (Carl Edman,
21 Christian Limpach, Scott Bender, Christophe de Dinechin) and code in the
22 Carbon version by Yamamoto Mitsuharu. */
24 /* This should be the first include, as it may set up #defines affecting
25 interpretation of even the system includes. */
31 #include "character.h"
36 #include "blockinput.h"
38 #include "termhooks.h"
42 #define NSMENUPROFILE
0
45 #include
<sys
/timeb.h
>
46 #include
<sys
/types.h
>
49 #define MenuStagger
10.0
52 int menu_trace_num
= 0;
53 #define NSTRACE
(x
) fprintf (stderr
, "
%s:%d: [%d] " #x "\n", \
54 __FILE__
, __LINE__
, ++menu_trace_num
)
60 /* Include lisp -> C common menu parsing code */
61 #define ENCODE_MENU_STRING
(str
) ENCODE_UTF_8
(str
)
62 #include "nsmenu_common.c"
65 extern Lisp_Object Qundefined
, Qmenu_enable
, Qmenu_bar_update_hook
;
66 extern Lisp_Object QCtoggle
, QCradio
;
68 Lisp_Object Qdebug_on_next_call
;
69 extern Lisp_Object Qoverriding_local_map
, Qoverriding_terminal_local_map
;
71 extern
long context_menu_value
;
72 EmacsMenu
*mainMenu
, *svcsMenu
, *dockMenu
;
74 /* Nonzero means a menu is currently active. */
75 static int popup_activated_flag
;
76 static NSModalSession popupSession
;
78 /* Nonzero means we are tracking and updating menus. */
79 static int trackingMenu
;
82 /* NOTE: toolbar implementation is at end,
83 following complete menu implementation. */
86 /* ==========================================================================
88 Menu: Externally-called functions
90 ========================================================================== */
93 /* FIXME: not currently used, but should normalize with other terms. */
95 x_activate_menubar
(struct frame
*f
)
97 fprintf (stderr
, "XXX
: Received x_activate_menubar event.
\n"
);
101 /* Supposed to discard menubar and free storage. Since we share the
102 menubar among frames and update its context for the focused window,
103 there is nothing to do here. */
105 free_frame_menubar
(struct frame
*f
)
112 popup_activated
(void
)
114 return popup_activated_flag
;
118 /* --------------------------------------------------------------------------
119 Update menubar. Three cases:
120 1) deep_p = 0, submenu = nil: Fresh switch onto a frame -- either set up
121 just top-level menu strings (OS X), or goto case (2) (GNUstep).
122 2) deep_p = 1, submenu = nil: Recompute all submenus.
123 3) deep_p = 1, submenu = non-nil: Update contents of a single submenu.
124 -------------------------------------------------------------------------- */
126 ns_update_menubar
(struct frame
*f
, int deep_p
, EmacsMenu
*submenu
)
128 NSAutoreleasePool
*pool
;
129 id
menu = [NSApp mainMenu
];
130 static EmacsMenu
*last_submenu
= nil
;
132 const
char *submenuTitle
= [[submenu
title] UTF8String
];
133 extern int waiting_for_input
;
136 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
144 NSTRACE
(set_frame_menubar
);
146 if (f
!= SELECTED_FRAME
())
148 XSETFRAME
(Vmenu_updating_frame
, f
);
149 /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */
152 pool
= [[NSAutoreleasePool alloc
] init
];
154 /* Menu may have been created automatically; if so, discard it. */
155 if ([menu isKindOfClass
: [EmacsMenu
class]] == NO
)
163 menu = [[EmacsMenu alloc
] initWithTitle
: ns_app_name
];
167 { /* close up anything on there */
168 id attMenu
= [menu attachedMenu
];
175 t
= -(1000*tb.time
+tb.millitm
);
178 #ifdef NS_IMPL_GNUSTEP
179 deep_p
= 1; /* until GNUstep NSMenu implements the Panther delegation model */
184 /* Fully parse one or more of the submenus. */
186 int
*submenu_start
, *submenu_end
;
187 int
*submenu_top_level_items
, *submenu_n_panes
;
188 struct buffer
*prev
= current_buffer
;
190 ptrdiff_t specpdl_count
= SPECPDL_INDEX
();
191 int previous_menu_items_used
= f
->menu_bar_items_used
;
192 Lisp_Object
*previous_items
193 = alloca
(previous_menu_items_used
* sizeof
*previous_items
);
195 /* lisp preliminaries */
196 buffer
= XWINDOW
(FRAME_SELECTED_WINDOW
(f
))->buffer
;
197 specbind
(Qinhibit_quit
, Qt
);
198 specbind
(Qdebug_on_next_call
, Qnil
);
199 record_unwind_save_match_data
();
200 if (NILP
(Voverriding_local_map_menu_flag
))
202 specbind
(Qoverriding_terminal_local_map
, Qnil
);
203 specbind
(Qoverriding_local_map
, Qnil
);
205 set_buffer_internal_1
(XBUFFER
(buffer
));
207 /* TODO: for some reason this is not needed in other terms,
208 but some menu updates call Info-extract-pointer which causes
209 abort-on-error if waiting-for-input. Needs further investigation. */
210 owfi
= waiting_for_input
;
211 waiting_for_input
= 0;
213 /* lucid hook and possible reset */
214 safe_run_hooks
(Qactivate_menubar_hook
);
215 if (! NILP
(Vlucid_menu_bar_dirty_flag
))
216 call0
(Qrecompute_lucid_menubar
);
217 safe_run_hooks
(Qmenu_bar_update_hook
);
218 FRAME_MENU_BAR_ITEMS
(f
) = menu_bar_items
(FRAME_MENU_BAR_ITEMS
(f
));
220 /* Now ready to go */
221 items
= FRAME_MENU_BAR_ITEMS
(f
);
223 /* Save the frame's previous menu bar contents data */
224 if (previous_menu_items_used
)
225 memcpy
(previous_items
, &AREF
(f
->menu_bar_vector
, 0),
226 previous_menu_items_used
* sizeof
(Lisp_Object
));
228 /* parse stage 1: extract from lisp */
231 menu_items
= f
->menu_bar_vector
;
232 menu_items_allocated
= VECTORP
(menu_items
) ? ASIZE
(menu_items
) : 0;
233 submenu_start
= alloca
(ASIZE
(items
) * sizeof
*submenu_start
);
234 submenu_end
= alloca
(ASIZE
(items
) * sizeof
*submenu_end
);
235 submenu_n_panes
= alloca
(ASIZE
(items
) * sizeof
*submenu_n_panes
);
236 submenu_top_level_items
= alloca
(ASIZE
(items
)
237 * sizeof
*submenu_top_level_items
);
239 for (i
= 0; i
< ASIZE
(items
); i
+= 4)
241 Lisp_Object key
, string
, maps
;
243 key
= AREF
(items
, i
);
244 string
= AREF
(items
, i
+ 1);
245 maps
= AREF
(items
, i
+ 2);
249 /* FIXME: we'd like to only parse the needed submenu, but this
250 was causing crashes in the _common parsing code.. need to make
251 sure proper initialization done.. */
252 /* if (submenu && strcmp (submenuTitle, SDATA (string)))
255 submenu_start
[i
] = menu_items_used
;
257 menu_items_n_panes
= 0;
258 submenu_top_level_items
[i
] = parse_single_submenu
(key
, string
, maps
);
259 submenu_n_panes
[i
] = menu_items_n_panes
;
260 submenu_end
[i
] = menu_items_used
;
264 finish_menu_items
();
265 waiting_for_input
= owfi
;
268 if (submenu
&& n
== 0)
270 /* should have found a menu for this one but didn't */
271 fprintf (stderr
, "
ERROR: did not
find lisp
menu for submenu
'%s'.
\n"
,
273 discard_menu_items
();
274 unbind_to
(specpdl_count
, Qnil
);
280 /* parse stage 2: insert into lucid 'widget_value' structures
281 [comments in other terms say not to evaluate lisp code here] */
282 wv
= xmalloc_widget_value
();
283 wv
->name
= "menubar"
;
286 wv
->button_type
= BUTTON_TYPE_NONE
;
290 for (i
= 0; i
< 4*n
; i
+= 4)
292 menu_items_n_panes
= submenu_n_panes
[i
];
293 wv
= digest_single_submenu
(submenu_start
[i
], submenu_end
[i
],
294 submenu_top_level_items
[i
]);
298 first_wv
->contents
= wv
;
299 /* Don't set wv->name here; GC during the loop might relocate it. */
301 wv
->button_type
= BUTTON_TYPE_NONE
;
305 set_buffer_internal_1
(prev
);
307 /* Compare the new menu items with previous, and leave off if no change */
308 /* FIXME: following other terms here, but seems like this should be
309 done before parse stage 2 above, since its results aren't used */
310 if (previous_menu_items_used
311 && (!submenu ||
(submenu
&& submenu
== last_submenu
))
312 && menu_items_used
== previous_menu_items_used
)
314 for (i
= 0; i
< previous_menu_items_used
; i
++)
315 /* FIXME: this ALWAYS fails on Buffers menu items.. something
316 about their strings causes them to change every time, so we
317 double-check failures */
318 if (!EQ
(previous_items
[i
], AREF
(menu_items
, i
)))
319 if (!(STRINGP
(previous_items
[i
])
320 && STRINGP
(AREF
(menu_items
, i
))
321 && !strcmp (SDATA
(previous_items
[i
]),
322 SDATA
(AREF
(menu_items
, i
)))))
324 if (i
== previous_menu_items_used
)
330 t
+= 1000*tb.time
+tb.millitm
;
331 fprintf (stderr
, "NO CHANGE
! CUTTING OUT after
%ld msec.\n", t);
334 free_menubar_widget_value_tree
(first_wv
);
335 discard_menu_items
();
336 unbind_to
(specpdl_count
, Qnil
);
342 /* The menu items are different, so store them in the frame */
343 /* FIXME: this is not correct for single-submenu case */
344 f
->menu_bar_vector
= menu_items
;
345 f
->menu_bar_items_used
= menu_items_used
;
347 /* Calls restore_menu_items, etc., as they were outside */
348 unbind_to
(specpdl_count
, Qnil
);
350 /* Parse stage 2a: now GC cannot happen during the lifetime of the
351 widget_value, so it's safe to store data from a Lisp_String */
352 wv
= first_wv
->contents
;
353 for (i
= 0; i
< ASIZE
(items
); i
+= 4)
356 string
= AREF
(items
, i
+ 1);
359 /* if (submenu && strcmp (submenuTitle, SDATA (string)))
362 wv
->name
= SSDATA
(string
);
363 update_submenu_strings
(wv
->contents
);
367 /* Now, update the NS menu; if we have a submenu, use that, otherwise
368 create a new menu for each sub and fill it. */
371 for (wv
= first_wv
->contents
; wv
; wv
= wv
->next
)
373 if (!strcmp (submenuTitle
, wv
->name
))
375 [submenu fillWithWidgetValue
: wv
->contents
];
376 last_submenu
= submenu
;
383 [menu fillWithWidgetValue
: first_wv
->contents
];
389 static int n_previous_strings
= 0;
390 static
char previous_strings
[100][10];
391 static
struct frame
*last_f
= NULL;
395 wv
= xmalloc_widget_value
();
396 wv
->name
= "menubar"
;
399 wv
->button_type
= BUTTON_TYPE_NONE
;
403 /* Make widget-value tree w/ just the top level menu bar strings */
404 items
= FRAME_MENU_BAR_ITEMS
(f
);
407 free_menubar_widget_value_tree
(first_wv
);
414 /* check if no change.. this mechanism is a bit rough, but ready */
415 n
= ASIZE
(items
) / 4;
416 if (f
== last_f
&& n_previous_strings
== n
)
418 for (i
= 0; i
<n
; i
++)
420 string
= AREF
(items
, 4*i
+1);
422 if (EQ
(string
, make_number
(0))) // FIXME
: Why???
--Stef
425 if (previous_strings
[i
][0])
429 if (memcmp
(previous_strings
[i
], SDATA
(string
),
430 min (10, SBYTES
(string
) + 1)))
436 free_menubar_widget_value_tree
(first_wv
);
444 for (i
= 0; i
< ASIZE
(items
); i
+= 4)
446 string
= AREF
(items
, i
+ 1);
451 memcpy
(previous_strings
[i
/4], min (10, SBYTES
(string
) + 1),
454 wv
= xmalloc_widget_value
();
455 wv
->name
= SSDATA
(string
);
458 wv
->button_type
= BUTTON_TYPE_NONE
;
460 wv
->call_data
= (void
*) (intptr_t
) (-1);
463 /* we'll update the real copy under app menu when time comes */
464 if (!strcmp ("Services"
, wv
->name
))
466 /* but we need to make sure it will update on demand */
467 [svcsMenu setFrame
: f
];
471 [menu addSubmenuWithTitle
: wv
->name forFrame
: f
];
476 first_wv
->contents
= wv
;
482 n_previous_strings
= n
;
484 n_previous_strings
= 0;
487 free_menubar_widget_value_tree
(first_wv
);
492 t
+= 1000*tb.time
+tb.millitm
;
493 fprintf (stderr
, "
Menu update took
%ld msec.\n", t);
498 [NSApp setMainMenu
: menu];
506 /* Main emacs core entry point for menubar menus: called to indicate that the
507 frame's menus have changed, and the *step representation should be updated
510 set_frame_menubar
(struct frame
*f
, int first_time
, int deep_p
)
512 ns_update_menubar
(f
, deep_p
, nil
);
516 /* ==========================================================================
518 Menu: class implementation
520 ========================================================================== */
523 /* Menu that can define itself from Emacs "widget_value"s and will lazily
524 update itself when user clicked. Based on Carbon/AppKit implementation
525 by Yamamoto Mitsuharu. */
526 @implementation EmacsMenu
528 /* override designated initializer */
529 - initWithTitle
: (NSString
*)title
531 if (self
= [super initWithTitle
: title])
532 [self setAutoenablesItems
: NO
];
537 /* used for top-level */
538 - initWithTitle
: (NSString
*)title frame
: (struct frame
*)f
540 [self initWithTitle
: title];
543 [self setDelegate
: self
];
549 - (void
)setFrame
: (struct frame
*)f
555 #
if MAC_OS_X_VERSION_MAX_ALLOWED
< MAC_OS_X_VERSION_10_5
556 extern NSString
*NSMenuDidBeginTrackingNotification
;
561 -(void
)trackingNotification
:(NSNotification
*)notification
563 /* Update menu in menuNeedsUpdate only while tracking menus. */
564 trackingMenu
= ([notification name
] == NSMenuDidBeginTrackingNotification
569 /* delegate method called when a submenu is being opened: run a 'deep' call
570 to set_frame_menubar */
571 - (void
)menuNeedsUpdate
: (NSMenu
*)menu
573 if (!FRAME_LIVE_P
(frame
))
576 /* Cocoa/Carbon will request update on every keystroke
577 via IsMenuKeyEvent -> CheckMenusForKeyEvent. These are not needed
578 since key equivalents are handled through emacs.
579 On Leopard, even keystroke events generate SystemDefined event.
580 Third-party applications that enhance mouse / trackpad
581 interaction, or also VNC/Remote Desktop will send events
582 of type AppDefined rather than SysDefined.
583 Menus will fail to show up if they haven't been initialized.
584 AppDefined events may lack timing data.
586 Thus, we rely on the didBeginTrackingNotification notification
587 as above to indicate the need for updates.
588 From 10.6 on, we could also use -[NSMenu propertiesToUpdate]: In the
589 key press case, NSMenuPropertyItemImage (e.g.) won't be set.
591 if (trackingMenu
== 0
592 /* Also, don't try this if from an event picked up asynchronously,
593 as lots of lisp evaluation happens in ns_update_menubar. */
594 || handling_signal
!= 0)
596 /*fprintf (stderr, "Updating menu '%s'\n", [[self title] UTF8String]); NSLog (@"%@\n", event); */
597 ns_update_menubar
(frame
, 1, self
);
601 - (BOOL
)performKeyEquivalent
: (NSEvent
*)theEvent
603 if (SELECTED_FRAME
() && FRAME_NS_P
(SELECTED_FRAME
())
604 && FRAME_NS_VIEW
(SELECTED_FRAME
()))
605 [FRAME_NS_VIEW
(SELECTED_FRAME
()) keyDown
: theEvent
];
610 /* Parse a widget_value's key rep (examples: 's-p', 's-S', '(C-x C-s)', '<f13>')
611 into an accelerator string. We are only able to display a single character
612 for an accelerator, together with an optional modifier combination. (Under
613 Carbon more control was possible, but in Cocoa multi-char strings passed to
614 NSMenuItem get ignored. For now we try to display a super-single letter
615 combo, and return the others as strings to be appended to the item title.
616 (This is signaled by setting keyEquivModMask to 0 for now.) */
617 -(NSString
*)parseKeyEquiv
: (const
char *)key
619 const
char *tpos
= key
;
620 keyEquivModMask
= NSCommandKeyMask
;
622 if (!key ||
!strlen
(key
))
625 while (*tpos
== ' ' ||
*tpos
== '(')
627 if ((*tpos
== 's') && (*(tpos
+1) == '-'))
629 return [NSString stringWithFormat
: @"
%c", tpos[2]];
631 keyEquivModMask
= 0; /* signal */
632 return [NSString stringWithUTF8String
: tpos
];
636 - (NSMenuItem
*)addItemWithWidgetValue
: (void
*)wvptr
639 widget_value
*wv
= (widget_value
*)wvptr
;
641 if (menu_separator_name_p
(wv
->name
))
643 item
= [NSMenuItem separatorItem
];
644 [self addItem
: item
];
648 NSString
*title, *keyEq
;
649 title = [NSString stringWithUTF8String
: wv
->name
];
651 title = @"
< ?
>"
; /* (get out in the open so we know about it) */
653 keyEq
= [self parseKeyEquiv
: wv
->key
];
655 /* OS X just ignores modifier strings longer than one character */
656 if (keyEquivModMask
== 0)
657 title = [title stringByAppendingFormat
: @"
(%@)", keyEq];
660 item
= [self addItemWithTitle
: (NSString
*)title
661 action
: @selector
(menuDown
:)
662 keyEquivalent
: keyEq
];
663 [item setKeyEquivalentModifierMask
: keyEquivModMask
];
665 [item setEnabled
: wv
->enabled
];
667 /* Draw radio buttons and tickboxes */
668 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE ||
669 wv
->button_type
== BUTTON_TYPE_RADIO
))
670 [item setState
: NSOnState
];
672 [item setState
: NSOffState
];
674 [item setTag
: (NSInteger
)wv
->call_data
];
686 for (n
= [self numberOfItems
]-1; n
>= 0; n
--)
688 NSMenuItem
*item
= [self itemAtIndex
: n
];
689 NSString
*title = [item
title];
690 if (([title length] == 0 /* OSX 10.5 */
691 ||
[ns_app_name isEqualToString
: title] /* from 10.6 on */
692 ||
[@"Apple" isEqualToString
: title]) /* older */
693 && ![item isSeparatorItem
])
695 [self removeItemAtIndex
: n
];
700 - (void
)fillWithWidgetValue
: (void
*)wvptr
702 widget_value
*wv
= (widget_value
*)wvptr
;
704 /* clear existing contents */
705 [self setMenuChangedMessagesEnabled
: NO
];
708 /* add new contents */
709 for (; wv
!= NULL; wv
= wv
->next
)
711 NSMenuItem
*item
= [self addItemWithWidgetValue
: wv
];
715 EmacsMenu
*submenu
= [[EmacsMenu alloc
] initWithTitle
: [item
title]];
717 [self setSubmenu
: submenu forItem
: item
];
718 [submenu fillWithWidgetValue
: wv
->contents
];
720 [item setAction
: nil
];
724 [self setMenuChangedMessagesEnabled
: YES
];
725 #ifdef NS_IMPL_GNUSTEP
726 if ([[self window
] isVisible
])
729 #
if MAC_OS_X_VERSION_MAX_ALLOWED
< MAC_OS_X_VERSION_10_2
730 if ([self supermenu
] == nil
)
737 /* adds an empty submenu and returns it */
738 - (EmacsMenu
*)addSubmenuWithTitle
: (const
char *)title forFrame
: (struct frame
*)f
740 NSString
*titleStr
= [NSString stringWithUTF8String
: title];
741 NSMenuItem
*item
= [self addItemWithTitle
: titleStr
742 action
: nil
/*@selector (menuDown:) */
744 EmacsMenu
*submenu
= [[EmacsMenu alloc
] initWithTitle
: titleStr frame
: f
];
745 [self setSubmenu
: submenu forItem
: item
];
750 /* run a menu in popup mode */
751 - (Lisp_Object
)runMenuAt
: (NSPoint
)p forFrame
: (struct frame
*)f
752 keymaps
: (int
)keymaps
754 EmacsView
*view = FRAME_NS_VIEW
(f
);
758 /* p = [view convertPoint:p fromView: nil]; */
759 p.y
= NSHeight
([view frame
]) - p.y
;
760 e
= [[view window
] currentEvent
];
761 event
= [NSEvent mouseEventWithType
: NSRightMouseDown
764 timestamp
: [e timestamp
]
765 windowNumber
: [[view window
] windowNumber
]
767 eventNumber
: 0/*[e eventNumber] */
771 context_menu_value
= -1;
772 [NSMenu popUpContextMenu
: self withEvent
: event forView
: view];
773 retVal
= context_menu_value
;
774 context_menu_value
= 0;
776 ? find_and_return_menu_selection
(f
, keymaps
, (void
*)retVal
)
784 /* ==========================================================================
786 Context Menu: implementing functions
788 ========================================================================== */
791 ns_menu_show
(FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
792 Lisp_Object
title, const
char **error)
796 Lisp_Object window
, tem
, keymap
;
797 ptrdiff_t specpdl_count
= SPECPDL_INDEX
();
798 widget_value
*wv
, *first_wv
= 0;
802 /* now parse stage 2 as in ns_update_menubar */
803 wv
= xmalloc_widget_value
();
804 wv
->name
= "contextmenu"
;
807 wv
->button_type
= BUTTON_TYPE_NONE
;
812 /* FIXME: a couple of one-line differences prevent reuse */
813 wv
= digest_single_submenu
(0, menu_items_used
, Qnil
);
816 widget_value
*save_wv
= 0, *prev_wv
= 0;
817 widget_value
**submenu_stack
818 = alloca
(menu_items_used
* sizeof
*submenu_stack
);
819 /* Lisp_Object *subprefix_stack
820 = alloca (menu_items_used * sizeof *subprefix_stack); */
821 int submenu_depth
= 0;
825 /* Loop over all panes and items, filling in the tree. */
827 while (i
< menu_items_used
)
829 if (EQ
(AREF
(menu_items
, i
), Qnil
))
831 submenu_stack
[submenu_depth
++] = save_wv
;
837 else if (EQ
(AREF
(menu_items
, i
), Qlambda
))
840 save_wv
= submenu_stack
[--submenu_depth
];
844 else if (EQ
(AREF
(menu_items
, i
), Qt
)
845 && submenu_depth
!= 0)
846 i
+= MENU_ITEMS_PANE_LENGTH
;
847 /* Ignore a nil in the item list.
848 It's meaningful only for dialog boxes. */
849 else if (EQ
(AREF
(menu_items
, i
), Qquote
))
851 else if (EQ
(AREF
(menu_items
, i
), Qt
))
853 /* Create a new pane. */
854 Lisp_Object pane_name
, prefix
;
855 const
char *pane_string
;
857 pane_name
= AREF
(menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
858 prefix
= AREF
(menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
860 #ifndef HAVE_MULTILINGUAL_MENU
861 if (STRINGP
(pane_name
) && STRING_MULTIBYTE
(pane_name
))
863 pane_name
= ENCODE_MENU_STRING
(pane_name
);
864 ASET
(menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
867 pane_string
= (NILP
(pane_name
)
868 ? ""
: SSDATA
(pane_name
));
869 /* If there is just one top-level pane, put all its items directly
870 under the top-level menu. */
871 if (menu_items_n_panes
== 1)
874 /* If the pane has a meaningful name,
875 make the pane a top-level menu item
876 with its items as a submenu beneath it. */
877 if (!keymaps
&& strcmp (pane_string
, ""
))
879 wv
= xmalloc_widget_value
();
883 first_wv
->contents
= wv
;
884 wv
->name
= pane_string
;
885 if (keymaps
&& !NILP
(prefix
))
889 wv
->button_type
= BUTTON_TYPE_NONE
;
900 i
+= MENU_ITEMS_PANE_LENGTH
;
904 /* Create a new item within current pane. */
905 Lisp_Object item_name
, enable
, descrip
, def
, type, selected
, help;
906 item_name
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
907 enable
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
908 descrip
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
909 def
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
910 type = AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
911 selected
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
912 help = AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
914 #ifndef HAVE_MULTILINGUAL_MENU
915 if (STRINGP
(item_name
) && STRING_MULTIBYTE
(item_name
))
917 item_name
= ENCODE_MENU_STRING
(item_name
);
918 ASET
(menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
921 if (STRINGP
(descrip
) && STRING_MULTIBYTE
(descrip
))
923 descrip
= ENCODE_MENU_STRING
(descrip
);
924 ASET
(menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
926 #endif
/* not HAVE_MULTILINGUAL_MENU */
928 wv
= xmalloc_widget_value
();
932 save_wv
->contents
= wv
;
933 wv
->name
= SSDATA
(item_name
);
935 wv
->key
= SSDATA
(descrip
);
937 /* If this item has a null value,
938 make the call_data null so that it won't display a box
939 when the mouse is on it. */
941 = !NILP
(def
) ?
(void
*) &AREF
(menu_items
, i
) : 0;
942 wv
->enabled
= !NILP
(enable
);
945 wv
->button_type
= BUTTON_TYPE_NONE
;
946 else if (EQ
(type, QCtoggle
))
947 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
948 else if (EQ
(type, QCradio
))
949 wv
->button_type
= BUTTON_TYPE_RADIO
;
953 wv
->selected
= !NILP
(selected
);
955 if (! STRINGP
(help))
962 i
+= MENU_ITEMS_ITEM_LENGTH
;
970 widget_value
*wv_title
= xmalloc_widget_value
();
971 widget_value
*wv_sep
= xmalloc_widget_value
();
973 /* Maybe replace this separator with a bitmap or owner-draw item
974 so that it looks better. Having two separators looks odd. */
976 wv_sep
->next
= first_wv
->contents
;
979 #ifndef HAVE_MULTILINGUAL_MENU
980 if (STRING_MULTIBYTE
(title))
981 title = ENCODE_MENU_STRING
(title);
984 wv_title
->name
= SSDATA
(title);
985 wv_title
->enabled
= NO
;
986 wv_title
->button_type
= BUTTON_TYPE_NONE
;
987 wv_title
->help = Qnil
;
988 wv_title
->next
= wv_sep
;
989 first_wv
->contents
= wv_title
;
992 pmenu
= [[EmacsMenu alloc
] initWithTitle
:
993 [NSString stringWithUTF8String
: SDATA
(title)]];
994 [pmenu fillWithWidgetValue
: first_wv
->contents
];
995 free_menubar_widget_value_tree
(first_wv
);
996 unbind_to
(specpdl_count
, Qnil
);
998 popup_activated_flag
= 1;
999 tem
= [pmenu runMenuAt
: p forFrame
: f keymaps
: keymaps
];
1000 popup_activated_flag
= 0;
1001 [[FRAME_NS_VIEW
(SELECTED_FRAME
()) window
] makeKeyWindow
];
1007 /* ==========================================================================
1009 Toolbar: externally-called functions
1011 ========================================================================== */
1014 free_frame_tool_bar
(FRAME_PTR f
)
1015 /* --------------------------------------------------------------------------
1016 Under NS we just hide the toolbar until it might be needed again.
1017 -------------------------------------------------------------------------- */
1020 [[FRAME_NS_VIEW
(f
) toolbar
] setVisible
: NO
];
1021 FRAME_TOOLBAR_HEIGHT
(f
) = 0;
1026 update_frame_tool_bar
(FRAME_PTR f
)
1027 /* --------------------------------------------------------------------------
1028 Update toolbar contents
1029 -------------------------------------------------------------------------- */
1032 EmacsView
*view = FRAME_NS_VIEW
(f
);
1033 NSWindow
*window
= [view window
];
1034 EmacsToolbar
*toolbar
= [view toolbar
];
1037 [toolbar clearActive
];
1039 /* update EmacsToolbar as in GtkUtils, build items list */
1040 for (i
= 0; i
< f
->n_tool_bar_items
; ++i
)
1042 #define TOOLPROP
(IDX
) AREF
(f
->tool_bar_items
, \
1043 i
* TOOL_BAR_ITEM_NSLOTS
+ (IDX
))
1045 BOOL enabled_p
= !NILP
(TOOLPROP
(TOOL_BAR_ITEM_ENABLED_P
));
1046 BOOL selected_p
= !NILP
(TOOLPROP
(TOOL_BAR_ITEM_SELECTED_P
));
1051 Lisp_Object helpObj
;
1052 const
char *helpText
;
1054 /* If image is a vector, choose the image according to the
1056 image = TOOLPROP
(TOOL_BAR_ITEM_IMAGES
);
1057 if (VECTORP
(image))
1059 /* NS toolbar auto-computes disabled and selected images */
1060 idx
= TOOL_BAR_IMAGE_ENABLED_SELECTED
;
1061 eassert
(ASIZE
(image) >= idx
);
1062 image = AREF
(image, idx
);
1068 helpObj
= TOOLPROP
(TOOL_BAR_ITEM_HELP
);
1070 helpObj
= TOOLPROP
(TOOL_BAR_ITEM_CAPTION
);
1071 helpText
= NILP
(helpObj
) ? ""
: SSDATA
(helpObj
);
1073 /* Ignore invalid image specifications. */
1074 if (!valid_image_p
(image))
1076 /* Don't log anything, GNUS makes invalid images all the time. */
1080 img_id
= lookup_image
(f
, image);
1081 img
= IMAGE_FROM_ID
(f
, img_id
);
1082 prepare_image_for_display
(f
, img
);
1084 if (img
->load_failed_p || img
->pixmap
== nil
)
1086 NSLog
(@"Could not prepare toolbar
image for display."
);
1090 [toolbar addDisplayItemWithImage
: img
->pixmap idx
: i helpText
: helpText
1091 enabled
: enabled_p
];
1095 if (![toolbar isVisible
])
1096 [toolbar setVisible
: YES
];
1098 if ([toolbar changed
])
1100 /* inform app that toolbar has changed */
1101 NSDictionary
*dict
= [toolbar configurationDictionary
];
1102 NSMutableDictionary
*newDict
= [dict mutableCopy
];
1103 NSEnumerator
*keys
= [[dict allKeys
] objectEnumerator
];
1105 while ((key
= [keys nextObject
]) != nil
)
1107 NSObject
*val
= [dict objectForKey
: key
];
1108 if ([val isKindOfClass
: [NSArray
class]])
1111 [toolbar toolbarDefaultItemIdentifiers
: toolbar
]
1116 [toolbar setConfigurationFromDictionary
: newDict
];
1120 FRAME_TOOLBAR_HEIGHT
(f
) =
1121 NSHeight
([window frameRectForContentRect
: NSMakeRect
(0, 0, 0, 0)])
1122 - FRAME_NS_TITLEBAR_HEIGHT
(f
);
1127 /* ==========================================================================
1129 Toolbar: class implementation
1131 ========================================================================== */
1133 @implementation EmacsToolbar
1135 - initForView
: (EmacsView
*)view withIdentifier
: (NSString
*)identifier
1137 self
= [super initWithIdentifier
: identifier
];
1139 [self setDisplayMode
: NSToolbarDisplayModeIconOnly
];
1140 [self setSizeMode
: NSToolbarSizeModeSmall
];
1141 [self setDelegate
: self
];
1142 identifierToItem
= [[NSMutableDictionary alloc
] initWithCapacity
: 10];
1143 activeIdentifiers
= [[NSMutableArray alloc
] initWithCapacity
: 8];
1144 prevEnablement
= enablement
= 0L;
1150 [prevIdentifiers release
];
1151 [activeIdentifiers release
];
1152 [identifierToItem release
];
1156 - (void
) clearActive
1158 [prevIdentifiers release
];
1159 prevIdentifiers
= [activeIdentifiers copy
];
1160 [activeIdentifiers removeAllObjects
];
1161 prevEnablement
= enablement
;
1167 return [activeIdentifiers isEqualToArray
: prevIdentifiers
] &&
1168 enablement
== prevEnablement ? NO
: YES
;
1171 - (void
) addDisplayItemWithImage
: (EmacsImage
*)img idx
: (int
)idx
1172 helpText
: (const
char *)help enabled
: (BOOL
)enabled
1174 /* 1) come up w/identifier */
1175 NSString
*identifier
1176 = [NSString stringWithFormat
: @"
%u", [img hash]];
1178 /* 2) create / reuse item */
1179 NSToolbarItem
*item
= [identifierToItem objectForKey
: identifier
];
1182 item
= [[[NSToolbarItem alloc
] initWithItemIdentifier
: identifier
]
1184 [item setImage
: img
];
1185 [item setToolTip
: [NSString stringWithUTF8String
: help]];
1186 [item setTarget
: emacsView
];
1187 [item setAction
: @selector
(toolbarClicked
:)];
1191 [item setEnabled
: enabled
];
1193 /* 3) update state */
1194 [identifierToItem setObject
: item forKey
: identifier
];
1195 [activeIdentifiers addObject
: identifier
];
1196 enablement
= (enablement
<< 1) |
(enabled
== YES
);
1199 /* This overrides super's implementation, which automatically sets
1200 all items to enabled state (for some reason). */
1201 - (void
)validateVisibleItems
{ }
1204 /* delegate methods */
1206 - (NSToolbarItem
*)toolbar
: (NSToolbar
*)toolbar
1207 itemForItemIdentifier
: (NSString
*)itemIdentifier
1208 willBeInsertedIntoToolbar
: (BOOL
)flag
1210 /* look up NSToolbarItem by identifier and return... */
1211 return [identifierToItem objectForKey
: itemIdentifier
];
1214 - (NSArray
*)toolbarDefaultItemIdentifiers
: (NSToolbar
*)toolbar
1216 /* return entire set.. */
1217 return activeIdentifiers
;
1220 /* for configuration palette (not yet supported) */
1221 - (NSArray
*)toolbarAllowedItemIdentifiers
: (NSToolbar
*)toolbar
1223 /* return entire set... */
1224 return [identifierToItem allKeys
];
1227 /* optional and unneeded */
1228 /* - toolbarWillAddItem: (NSNotification *)notification { } */
1229 /* - toolbarDidRemoveItem: (NSNotification *)notification { } */
1230 /* - (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar */
1232 @
end /* EmacsToolbar */
1236 /* ==========================================================================
1238 Tooltip: class implementation
1240 ========================================================================== */
1242 /* Needed because NeXTstep does not provide enough control over tooltip
1244 @implementation EmacsTooltip
1248 NSColor
*col
= [NSColor colorWithCalibratedRed
: 1.0 green
: 1.0
1249 blue
: 0.792 alpha
: 0.95];
1250 NSFont
*font
= [NSFont toolTipsFontOfSize
: 0];
1251 NSFont
*sfont
= [font screenFont
];
1252 int height
= [sfont ascender
] - [sfont descender
];
1253 /*[font boundingRectForFont].size.height; */
1254 NSRect r
= NSMakeRect
(0, 0, 100, height
+6);
1256 textField
= [[NSTextField alloc
] initWithFrame
: r
];
1257 [textField setFont
: font
];
1258 [textField setBackgroundColor
: col
];
1260 [textField setEditable
: NO
];
1261 [textField setSelectable
: NO
];
1262 [textField setBordered
: NO
];
1263 [textField setBezeled
: NO
];
1264 [textField setDrawsBackground
: YES
];
1266 win
= [[NSWindow alloc
]
1267 initWithContentRect
: [textField frame
]
1269 backing
: NSBackingStoreBuffered
1271 [win setHasShadow
: YES
];
1272 [win setReleasedWhenClosed
: NO
];
1273 [win setDelegate
: self
];
1274 [[win contentView
] addSubview
: textField
];
1275 /* [win setBackgroundColor: col]; */
1276 [win setOpaque
: NO
];
1285 [textField release
];
1289 - (void
) setText
: (char *)text
1291 NSString
*str
= [NSString stringWithUTF8String
: text];
1292 NSRect r
= [textField frame
];
1295 [textField setStringValue
: str
];
1296 tooltipDims
= [[textField
cell] cellSize
];
1298 r.
size.width
= tooltipDims.width
;
1299 r.
size.height
= tooltipDims.height
;
1300 [textField setFrame
: r
];
1303 - (void
) showAtX
: (int
)x Y
: (int
)y
for: (int
)seconds
1305 NSRect wr
= [win frame
];
1307 wr.origin
= NSMakePoint
(x
, y
);
1308 wr.
size = [textField frame
].
size;
1310 [win setFrame
: wr display
: YES
];
1311 [win orderFront
: self
];
1313 timer
= [NSTimer scheduledTimerWithTimeInterval
: (float
)seconds target
: self
1314 selector
: @selector
(hide
)
1315 userInfo
: nil repeats
: NO
];
1324 if ([timer isValid
])
1333 return timer
!= nil
;
1338 return [textField frame
];
1341 @
end /* EmacsTooltip */
1345 /* ==========================================================================
1347 Popup Dialog: implementing functions
1349 ========================================================================== */
1353 pop_down_menu
(Lisp_Object arg
)
1355 struct Lisp_Save_Value
*p
= XSAVE_VALUE
(arg
);
1356 if (popup_activated_flag
)
1358 popup_activated_flag
= 0;
1360 [NSApp endModalSession
: popupSession
];
1361 [((EmacsDialogPanel
*) (p
->pointer
)) close];
1362 [[FRAME_NS_VIEW
(SELECTED_FRAME
()) window
] makeKeyWindow
];
1370 ns_popup_dialog
(Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
1373 Lisp_Object window
, tem
, title;
1378 NSTRACE
(x
-popup
-dialog);
1382 isQ
= NILP
(header
);
1384 if (EQ
(position
, Qt
)
1385 ||
(CONSP
(position
) && (EQ
(XCAR
(position
), Qmenu_bar
)
1386 || EQ
(XCAR
(position
), Qtool_bar
))))
1388 window
= selected_window
;
1390 else if (CONSP
(position
))
1393 tem
= Fcar
(position
);
1394 if (XTYPE
(tem
) == Lisp_Cons
)
1395 window
= Fcar
(Fcdr
(position
));
1398 tem
= Fcar
(Fcdr
(position
)); /* EVENT_START (position) */
1399 window
= Fcar
(tem
); /* POSN_WINDOW (tem) */
1402 else if (WINDOWP
(position
) || FRAMEP
(position
))
1409 if (FRAMEP
(window
))
1410 f
= XFRAME
(window
);
1411 else if (WINDOWP
(window
))
1413 CHECK_LIVE_WINDOW
(window
);
1414 f
= XFRAME
(WINDOW_FRAME
(XWINDOW
(window
)));
1417 CHECK_WINDOW
(window
);
1419 p.x
= (int
)f
->left_pos
+ ((int
)FRAME_COLUMN_WIDTH
(f
) * f
->text_cols
)/2;
1420 p.y
= (int
)f
->top_pos
+ (FRAME_LINE_HEIGHT
(f
) * f
->text_lines
)/2;
1422 title = Fcar
(contents
);
1423 CHECK_STRING
(title);
1425 if (NILP
(Fcar
(Fcdr
(contents
))))
1426 /* No buttons specified, add an "Ok" button so users can pop down
1428 contents
= Fcons
(title, Fcons
(Fcons
(build_string
("Ok"
), Qt
), Qnil
));
1431 dialog = [[EmacsDialogPanel alloc
] initFromContents
: contents
1434 ptrdiff_t specpdl_count
= SPECPDL_INDEX
();
1435 record_unwind_protect
(pop_down_menu
, make_save_value
(dialog, 0));
1436 popup_activated_flag
= 1;
1437 tem
= [dialog runDialogAt
: p
];
1438 unbind_to
(specpdl_count
, Qnil
); /* calls pop_down_menu */
1446 /* ==========================================================================
1448 Popup Dialog: class implementation
1450 ========================================================================== */
1452 @interface FlippedView
: NSView
1457 @implementation FlippedView
1464 @implementation EmacsDialogPanel
1467 #define ICONSIZE
64.0
1468 #define TEXTHEIGHT
20.0
1469 #define MINCELLWIDTH
90.0
1471 - initWithContentRect
: (NSRect
)contentRect styleMask
: (NSUInteger
)aStyle
1472 backing
: (NSBackingStoreType
)backingType defer
: (BOOL
)flag
1474 NSSize spacing
= {SPACER
, SPACER
};
1476 char this_cmd_name
[80];
1478 static NSImageView
*imgView
;
1479 static FlippedView
*contentView
;
1484 area.origin.x
= 3*SPACER
;
1485 area.origin.y
= 2*SPACER
;
1486 area.
size.width
= ICONSIZE
;
1487 area.
size.height
= ICONSIZE
;
1488 img
= [[NSImage imageNamed
: @"NSApplicationIcon"
] copy
];
1489 [img setScalesWhenResized
: YES
];
1490 [img setSize
: NSMakeSize
(ICONSIZE
, ICONSIZE
)];
1491 imgView
= [[NSImageView alloc
] initWithFrame
: area
];
1492 [imgView setImage
: img
];
1493 [imgView setEditable
: NO
];
1497 aStyle
= NSTitledWindowMask
;
1501 [super initWithContentRect
: contentRect styleMask
: aStyle
1502 backing
: backingType defer
: flag];
1503 contentView
= [[FlippedView alloc
] initWithFrame
: [[self contentView
] frame
]];
1504 [self setContentView
: contentView
];
1506 [[self contentView
] setAutoresizesSubviews
: YES
];
1508 [[self contentView
] addSubview
: imgView
];
1509 [self setTitle
: @""
];
1511 area.origin.x
+= ICONSIZE
+2*SPACER
;
1512 /* area.origin.y = TEXTHEIGHT; ICONSIZE/2-10+SPACER; */
1513 area.
size.width
= 400;
1514 area.
size.height
= TEXTHEIGHT
;
1515 command
= [[[NSTextField alloc
] initWithFrame
: area
] autorelease
];
1516 [[self contentView
] addSubview
: command
];
1517 [command setStringValue
: ns_app_name
];
1518 [command setDrawsBackground
: NO
];
1519 [command setBezeled
: NO
];
1520 [command setSelectable
: NO
];
1521 [command setFont
: [NSFont boldSystemFontOfSize
: 13.0]];
1523 /* area.origin.x = ICONSIZE+2*SPACER;
1524 area.origin.y = TEXTHEIGHT + 2*SPACER;
1525 area.size.width = 400;
1526 area.size.height= 2;
1527 tem = [[[NSBox alloc] initWithFrame: area] autorelease];
1528 [[self contentView] addSubview: tem];
1529 [tem setTitlePosition: NSNoTitle];
1530 [tem setAutoresizingMask: NSViewWidthSizable];*/
1532 /* area.origin.x = ICONSIZE+2*SPACER; */
1533 area.origin.y
+= TEXTHEIGHT
+SPACER
;
1534 area.
size.width
= 400;
1535 area.
size.height
= TEXTHEIGHT
;
1536 title = [[[NSTextField alloc
] initWithFrame
: area
] autorelease
];
1537 [[self contentView
] addSubview
: title];
1538 [title setDrawsBackground
: NO
];
1539 [title setBezeled
: NO
];
1540 [title setSelectable
: NO
];
1541 [title setFont
: [NSFont systemFontOfSize
: 11.0]];
1543 cell = [[[NSButtonCell alloc
] initTextCell
: @""
] autorelease
];
1544 [cell setBordered
: NO
];
1545 [cell setEnabled
: NO
];
1546 [cell setCellAttribute
: NSCellIsInsetButton to
: 8];
1547 [cell setBezelStyle
: NSRoundedBezelStyle
];
1549 matrix
= [[NSMatrix alloc
] initWithFrame
: contentRect
1550 mode
: NSHighlightModeMatrix
1553 numberOfColumns
: 1];
1554 [[self contentView
] addSubview
: matrix
];
1556 [matrix setFrameOrigin
: NSMakePoint
(area.origin.x
,
1557 area.origin.y
+ (TEXTHEIGHT
+3*SPACER
))];
1558 [matrix setIntercellSpacing
: spacing
];
1560 [self setOneShot
: YES
];
1561 [self setReleasedWhenClosed
: YES
];
1562 [self setHidesOnDeactivate
: YES
];
1567 - (BOOL
)windowShouldClose
: (id
)sender
1569 [NSApp stopModalWithCode
: XHASH
(Qnil
)]; // FIXME
: BIG UGLY HACK
!!
1574 void process_dialog
(id window
, Lisp_Object list
)
1579 for (; XTYPE
(list
) == Lisp_Cons
; list
= XCDR
(list
))
1582 if (XTYPE
(item
) == Lisp_String
)
1584 [window addString
: SDATA
(item
) row
: row
++];
1586 else if (XTYPE
(item
) == Lisp_Cons
)
1588 [window addButton
: SDATA
(XCAR
(item
))
1589 value
: XCDR
(item
) row
: row
++];
1591 else if (NILP
(item
))
1600 - addButton
: (char *)str value
: (Lisp_Object
)val row
: (int
)row
1609 cell = [matrix cellAtRow
: row column
: cols
-1];
1610 [cell setTarget
: self
];
1611 [cell setAction
: @selector
(clicked
: )];
1612 [cell setTitle
: [NSString stringWithUTF8String
: str
]];
1613 [cell setTag
: XHASH
(val
)]; // FIXME
: BIG UGLY HACK
!!
1614 [cell setBordered
: YES
];
1615 [cell setEnabled
: YES
];
1621 - addString
: (char *)str row
: (int
)row
1630 cell = [matrix cellAtRow
: row column
: cols
-1];
1631 [cell setTitle
: [NSString stringWithUTF8String
: str
]];
1632 [cell setBordered
: YES
];
1633 [cell setEnabled
: NO
];
1649 NSArray
*sellist
= nil
;
1652 sellist
= [sender selectedCells
];
1653 if ([sellist count
]<1)
1656 seltag
= [[sellist objectAtIndex
: 0] tag
];
1657 if (seltag
!= XHASH
(Qundefined
)) // FIXME
: BIG UGLY HACK
!!
1658 [NSApp stopModalWithCode
: seltag
];
1663 - initFromContents
: (Lisp_Object
)contents isQuestion
: (BOOL
)isQ
1668 if (XTYPE
(contents
) == Lisp_Cons
)
1670 head
= Fcar
(contents
);
1671 process_dialog
(self
, Fcdr
(contents
));
1676 if (XTYPE
(head
) == Lisp_String
)
1677 [title setStringValue
:
1678 [NSString stringWithUTF8String
: SDATA
(head
)]];
1679 else if (isQ
== YES
)
1680 [title setStringValue
: @"Question"
];
1682 [title setStringValue
: @"Information"
];
1688 if (cols
== 1 && rows
> 1) /* Never told where to split */
1691 for (i
= 0; i
<rows
/2; i
++)
1693 [matrix putCell
: [matrix cellAtRow
: (rows
+1)/2 column
: 0]
1694 atRow
: i column
: 1];
1695 [matrix removeRow
: (rows
+1)/2];
1701 NSSize csize
= [matrix cellSize
];
1702 if (csize.width
< MINCELLWIDTH
)
1704 csize.width
= MINCELLWIDTH
;
1705 [matrix setCellSize
: csize
];
1706 [matrix sizeToCells
];
1711 [command sizeToFit
];
1715 if (r.
size.width
+r.origin.x
> t.
size.width
+t.origin.x
)
1717 t.origin.x
= r.origin.x
;
1718 t.
size.width
= r.
size.width
;
1720 r
= [command frame
];
1721 if (r.
size.width
+r.origin.x
> t.
size.width
+t.origin.x
)
1723 t.origin.x
= r.origin.x
;
1724 t.
size.width
= r.
size.width
;
1728 s
= [(NSView
*)[self contentView
] frame
];
1729 r.
size.width
+= t.origin.x
+t.
size.width
+2*SPACER
-s.
size.width
;
1730 r.
size.height
+= t.origin.y
+t.
size.height
+SPACER
-s.
size.height
;
1731 [self setFrame
: r display
: NO
];
1740 { [super dealloc
]; return; };
1744 - (Lisp_Object
)runDialogAt
: (NSPoint
)p
1748 /* initiate a session that will be ended by pop_down_menu */
1749 popupSession
= [NSApp beginModalSessionForWindow
: self
];
1750 while (popup_activated_flag
1751 && (ret
= [NSApp runModalSession
: popupSession
])
1752 == NSRunContinuesResponse
)
1754 /* Run this for timers.el, indep of atimers; might not return.
1755 TODO: use return value to avoid calling every iteration. */
1757 [NSThread sleepUntilDate
: [NSDate dateWithTimeIntervalSinceNow
: 0.1]];
1760 { /* FIXME: BIG UGLY HACK!!! */
1762 *(EMACS_INT
*)(&tmp
) = ret
;
1770 /* ==========================================================================
1774 ========================================================================== */
1776 DEFUN
("ns
-reset-menu"
, Fns_reset_menu
, Sns_reset_menu
, 0, 0, 0,
1777 doc: /* Cause the NS menu to be re-calculated. */)
1780 set_frame_menubar
(SELECTED_FRAME
(), 1, 0);
1785 DEFUN
("x
-popup
-dialog"
, Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
1786 doc: /* Pop up a dialog box and return user's selection.
1787 POSITION specifies which frame to use.
1788 This is normally a mouse button event or a window or frame.
1789 If POSITION is t, it means to use the frame the mouse is on.
1790 The dialog box appears in the middle of the specified frame.
1792 CONTENTS specifies the alternatives to display in the dialog box.
1793 It is a list of the form (DIALOG ITEM1 ITEM2...).
1794 Each ITEM is a cons cell (STRING . VALUE).
1795 The return value is VALUE from the chosen item.
1797 An ITEM may also be just a string--that makes a nonselectable item.
1798 An ITEM may also be nil--that means to put all preceding items
1799 on the left of the dialog box and all following items on the right.
1800 \(By default, approximately half appear on each side.)
1802 If HEADER is non-nil, the frame title for the box is "Information",
1803 otherwise it is "Question".
1805 If the user gets rid of the dialog box without making a valid choice,
1806 for instance using the window manager, then this produces a quit and
1807 `x-popup-dialog' does not return. */)
1808 (Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
1810 return ns_popup_dialog
(position
, contents
, header
);
1813 DEFUN
("
menu-or
-popup
-active
-p"
, Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
1814 doc: /* Return t if a menu or popup dialog is active. */)
1817 return popup_activated
() ? Qt
: Qnil
;
1820 /* ==========================================================================
1822 Lisp interface declaration
1824 ========================================================================== */
1827 syms_of_nsmenu
(void
)
1829 #ifndef NS_IMPL_COCOA
1830 /* Don't know how to keep track of this in Next/Open/Gnustep. Always
1831 update menus there. */
1834 defsubr
(&Sx_popup_dialog
);
1835 defsubr
(&Sns_reset_menu
);
1836 defsubr
(&Smenu_or_popup_active_p
);
1838 Qdebug_on_next_call
= intern_c_string
("
debug-on
-next
-call"
);
1839 staticpro
(&Qdebug_on_next_call
);