1 /* NeXT/Open/GNUstep and MacOSX Cocoa menu and toolbar module.
2 Copyright (C) 2007, 2008, 2009, 2010 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. */
35 #include "blockinput.h"
37 #include "termhooks.h"
41 #define NSMENUPROFILE
0
44 #include
<sys
/timeb.h
>
45 #include
<sys
/types.h
>
48 #define MenuStagger
10.0
51 int menu_trace_num
= 0;
52 #define NSTRACE
(x
) fprintf (stderr
, "
%s:%d: [%d] " #x "\n", \
53 __FILE__
, __LINE__
, ++menu_trace_num
)
59 /* Include lisp -> C common menu parsing code */
60 #define ENCODE_MENU_STRING
(str
) ENCODE_UTF_8
(str
)
61 #include "nsmenu_common.c"
64 extern Lisp_Object Qundefined
, Qmenu_enable
, Qmenu_bar_update_hook
;
65 extern Lisp_Object QCtoggle
, QCradio
;
67 Lisp_Object Qdebug_on_next_call
;
68 extern Lisp_Object Voverriding_local_map
, Voverriding_local_map_menu_flag
,
69 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 /* NOTE: toolbar implementation is at end,
79 following complete menu implementation. */
82 /* ==========================================================================
84 Menu: Externally-called functions
86 ========================================================================== */
89 /* FIXME: not currently used, but should normalize with other terms. */
91 x_activate_menubar
(struct frame
*f
)
93 fprintf (stderr
, "XXX
: Received x_activate_menubar event.
\n"
);
97 /* Supposed to discard menubar and free storage. Since we share the
98 menubar among frames and update its context for the focused window,
99 there is nothing to do here. */
101 free_frame_menubar
(struct frame
*f
)
110 return popup_activated_flag
;
114 /* --------------------------------------------------------------------------
115 Update menubar. Three cases:
116 1) deep_p = 0, submenu = nil: Fresh switch onto a frame -- either set up
117 just top-level menu strings (OS X), or goto case (2) (GNUstep).
118 2) deep_p = 1, submenu = nil: Recompute all submenus.
119 3) deep_p = 1, submenu = non-nil: Update contents of a single submenu.
120 -------------------------------------------------------------------------- */
122 ns_update_menubar
(struct frame
*f
, int deep_p
, EmacsMenu
*submenu
)
124 NSAutoreleasePool
*pool
;
125 id
menu = [NSApp mainMenu
];
126 static EmacsMenu
*last_submenu
= nil
;
128 const
char *submenuTitle
= [[submenu
title] UTF8String
];
129 extern int waiting_for_input
;
132 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
140 NSTRACE
(set_frame_menubar
);
142 if (f
!= SELECTED_FRAME
())
144 XSETFRAME
(Vmenu_updating_frame
, f
);
145 /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */
148 pool
= [[NSAutoreleasePool alloc
] init
];
150 /* Menu may have been created automatically; if so, discard it. */
151 if ([menu isKindOfClass
: [EmacsMenu
class]] == NO
)
159 menu = [[EmacsMenu alloc
] initWithTitle
: ns_app_name
];
163 { /* close up anything on there */
164 id attMenu
= [menu attachedMenu
];
171 t
= -(1000*tb.time
+tb.millitm
);
174 #ifdef NS_IMPL_GNUSTEP
175 deep_p
= 1; /* until GNUstep NSMenu implements the Panther delegation model */
180 /* Fully parse one or more of the submenus. */
182 int
*submenu_start
, *submenu_end
;
183 int
*submenu_top_level_items
, *submenu_n_panes
;
184 struct buffer
*prev
= current_buffer
;
186 int specpdl_count
= SPECPDL_INDEX
();
187 int previous_menu_items_used
= f
->menu_bar_items_used
;
188 Lisp_Object
*previous_items
189 = (Lisp_Object
*) alloca
(previous_menu_items_used
190 * sizeof
(Lisp_Object
));
192 /* lisp preliminaries */
193 buffer
= XWINDOW
(FRAME_SELECTED_WINDOW
(f
))->buffer
;
194 specbind
(Qinhibit_quit
, Qt
);
195 specbind
(Qdebug_on_next_call
, Qnil
);
196 record_unwind_save_match_data
();
197 if (NILP
(Voverriding_local_map_menu_flag
))
199 specbind
(Qoverriding_terminal_local_map
, Qnil
);
200 specbind
(Qoverriding_local_map
, Qnil
);
202 set_buffer_internal_1
(XBUFFER
(buffer
));
204 /* TODO: for some reason this is not needed in other terms,
205 but some menu updates call Info-extract-pointer which causes
206 abort-on-error if waiting-for-input. Needs further investigation. */
207 owfi
= waiting_for_input
;
208 waiting_for_input
= 0;
210 /* lucid hook and possible reset */
211 safe_run_hooks
(Qactivate_menubar_hook
);
212 if (! NILP
(Vlucid_menu_bar_dirty_flag
))
213 call0
(Qrecompute_lucid_menubar
);
214 safe_run_hooks
(Qmenu_bar_update_hook
);
215 FRAME_MENU_BAR_ITEMS
(f
) = menu_bar_items
(FRAME_MENU_BAR_ITEMS
(f
));
217 /* Now ready to go */
218 items
= FRAME_MENU_BAR_ITEMS
(f
);
220 /* Save the frame's previous menu bar contents data */
221 if (previous_menu_items_used
)
222 bcopy
(XVECTOR
(f
->menu_bar_vector
)->contents
, previous_items
,
223 previous_menu_items_used
* sizeof
(Lisp_Object
));
225 /* parse stage 1: extract from lisp */
228 menu_items
= f
->menu_bar_vector
;
229 menu_items_allocated
= VECTORP
(menu_items
) ? ASIZE
(menu_items
) : 0;
230 submenu_start
= (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
*));
231 submenu_end
= (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
*));
232 submenu_n_panes
= (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
));
233 submenu_top_level_items
234 = (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
*));
236 for (i
= 0; i
< XVECTOR
(items
)->size; i
+= 4)
238 Lisp_Object key
, string
, maps
;
240 key
= XVECTOR
(items
)->contents
[i
];
241 string
= XVECTOR
(items
)->contents
[i
+ 1];
242 maps
= XVECTOR
(items
)->contents
[i
+ 2];
246 /* FIXME: we'd like to only parse the needed submenu, but this
247 was causing crashes in the _common parsing code.. need to make
248 sure proper initialization done.. */
249 /* if (submenu && strcmp (submenuTitle, SDATA (string)))
252 submenu_start
[i
] = menu_items_used
;
254 menu_items_n_panes
= 0;
255 submenu_top_level_items
[i
] = parse_single_submenu
(key
, string
, maps
);
256 submenu_n_panes
[i
] = menu_items_n_panes
;
257 submenu_end
[i
] = menu_items_used
;
261 finish_menu_items
();
262 waiting_for_input
= owfi
;
265 if (submenu
&& n
== 0)
267 /* should have found a menu for this one but didn't */
268 fprintf (stderr
, "
ERROR: did not
find lisp
menu for submenu
'%s'.
\n"
,
270 discard_menu_items
();
271 unbind_to
(specpdl_count
, Qnil
);
277 /* parse stage 2: insert into lucid 'widget_value' structures
278 [comments in other terms say not to evaluate lisp code here] */
279 wv
= xmalloc_widget_value
();
280 wv
->name
= "menubar"
;
283 wv
->button_type
= BUTTON_TYPE_NONE
;
287 for (i
= 0; i
< 4*n
; i
+= 4)
289 menu_items_n_panes
= submenu_n_panes
[i
];
290 wv
= digest_single_submenu
(submenu_start
[i
], submenu_end
[i
],
291 submenu_top_level_items
[i
]);
295 first_wv
->contents
= wv
;
296 /* Don't set wv->name here; GC during the loop might relocate it. */
298 wv
->button_type
= BUTTON_TYPE_NONE
;
302 set_buffer_internal_1
(prev
);
304 /* Compare the new menu items with previous, and leave off if no change */
305 /* FIXME: following other terms here, but seems like this should be
306 done before parse stage 2 above, since its results aren't used */
307 if (previous_menu_items_used
308 && (!submenu ||
(submenu
&& submenu
== last_submenu
))
309 && menu_items_used
== previous_menu_items_used
)
311 for (i
= 0; i
< previous_menu_items_used
; i
++)
312 /* FIXME: this ALWAYS fails on Buffers menu items.. something
313 about their strings causes them to change every time, so we
314 double-check failures */
315 if (!EQ
(previous_items
[i
], XVECTOR
(menu_items
)->contents
[i
]))
316 if (!(STRINGP
(previous_items
[i
])
317 && STRINGP
(XVECTOR
(menu_items
)->contents
[i
])
318 && !strcmp (SDATA
(previous_items
[i
]),
319 SDATA
(XVECTOR
(menu_items
)->contents
[i
]))))
321 if (i
== previous_menu_items_used
)
327 t
+= 1000*tb.time
+tb.millitm
;
328 fprintf (stderr
, "NO CHANGE
! CUTTING OUT after
%ld msec.\n", t);
331 free_menubar_widget_value_tree
(first_wv
);
332 discard_menu_items
();
333 unbind_to
(specpdl_count
, Qnil
);
339 /* The menu items are different, so store them in the frame */
340 /* FIXME: this is not correct for single-submenu case */
341 f
->menu_bar_vector
= menu_items
;
342 f
->menu_bar_items_used
= menu_items_used
;
344 /* Calls restore_menu_items, etc., as they were outside */
345 unbind_to
(specpdl_count
, Qnil
);
347 /* Parse stage 2a: now GC cannot happen during the lifetime of the
348 widget_value, so it's safe to store data from a Lisp_String */
349 wv
= first_wv
->contents
;
350 for (i
= 0; i
< XVECTOR
(items
)->size; i
+= 4)
353 string
= XVECTOR
(items
)->contents
[i
+ 1];
356 /* if (submenu && strcmp (submenuTitle, SDATA (string)))
359 wv
->name
= (char *) SDATA
(string
);
360 update_submenu_strings
(wv
->contents
);
364 /* Now, update the NS menu; if we have a submenu, use that, otherwise
365 create a new menu for each sub and fill it. */
368 for (wv
= first_wv
->contents
; wv
; wv
= wv
->next
)
370 if (!strcmp (submenuTitle
, wv
->name
))
372 [submenu fillWithWidgetValue
: wv
->contents
];
373 last_submenu
= submenu
;
380 [menu fillWithWidgetValue
: first_wv
->contents
];
386 static int n_previous_strings
= 0;
387 static
char previous_strings
[100][10];
388 static
struct frame
*last_f
= NULL;
392 wv
= xmalloc_widget_value
();
393 wv
->name
= "menubar"
;
396 wv
->button_type
= BUTTON_TYPE_NONE
;
400 /* Make widget-value tree w/ just the top level menu bar strings */
401 items
= FRAME_MENU_BAR_ITEMS
(f
);
410 /* check if no change.. this mechanism is a bit rough, but ready */
411 n
= XVECTOR
(items
)->size / 4;
412 if (f
== last_f
&& n_previous_strings
== n
)
414 for (i
= 0; i
<n
; i
++)
416 string
= AREF
(items
, 4*i
+1);
418 if (EQ
(string
, make_number
(0))) // FIXME
: Why???
--Stef
421 if (previous_strings
[i
][0])
425 if (strncmp
(previous_strings
[i
], SDATA
(string
), 10))
438 for (i
= 0; i
< XVECTOR
(items
)->size; i
+= 4)
440 string
= XVECTOR
(items
)->contents
[i
+ 1];
445 strncpy
(previous_strings
[i
/4], SDATA
(string
), 10);
447 wv
= xmalloc_widget_value
();
448 wv
->name
= (char *) SDATA
(string
);
451 wv
->button_type
= BUTTON_TYPE_NONE
;
453 wv
->call_data
= (void
*) (EMACS_INT
) (-1);
456 /* we'll update the real copy under app menu when time comes */
457 if (!strcmp ("Services"
, wv
->name
))
459 /* but we need to make sure it will update on demand */
460 [svcsMenu setFrame
: f
];
461 [svcsMenu setDelegate
: svcsMenu
];
465 [menu addSubmenuWithTitle
: wv
->name forFrame
: f
];
470 first_wv
->contents
= wv
;
476 n_previous_strings
= n
;
478 n_previous_strings
= 0;
481 free_menubar_widget_value_tree
(first_wv
);
486 t
+= 1000*tb.time
+tb.millitm
;
487 fprintf (stderr
, "
Menu update took
%ld msec.\n", t);
492 [NSApp setMainMenu
: menu];
500 /* Main emacs core entry point for menubar menus: called to indicate that the
501 frame's menus have changed, and the *step representation should be updated
504 set_frame_menubar
(struct frame
*f
, int first_time
, int deep_p
)
506 ns_update_menubar
(f
, deep_p
, nil
);
510 /* Utility (from macmenu.c): is this item a separator? */
512 name_is_separator
(name
)
515 const
char *start
= name
;
517 /* Check if name string consists of only dashes ('-'). */
518 while (*name
== '-') name
++;
519 /* Separators can also be of the form "--:TripleSuperMegaEtched"
520 or "--deep-shadow". We don't implement them yet, se we just treat
521 them like normal separators. */
522 return (*name
== '\0' || start
+ 2 == name
);
526 /* ==========================================================================
528 Menu: class implementation
530 ========================================================================== */
533 /* Menu that can define itself from Emacs "widget_value"s and will lazily
534 update itself when user clicked. Based on Carbon/AppKit implementation
535 by Yamamoto Mitsuharu. */
536 @implementation EmacsMenu
538 /* override designated initializer */
539 - initWithTitle
: (NSString
*)title
541 if (self
= [super initWithTitle
: title])
542 [self setAutoenablesItems
: NO
];
547 /* used for top-level */
548 - initWithTitle
: (NSString
*)title frame
: (struct frame
*)f
550 [self initWithTitle
: title];
553 [self setDelegate
: self
];
559 - (void
)setFrame
: (struct frame
*)f
565 /* delegate method called when a submenu is being opened: run a 'deep' call
566 to set_frame_menubar */
567 - (void
)menuNeedsUpdate
: (NSMenu
*)menu
570 if (!FRAME_LIVE_P
(frame
))
572 event
= [[FRAME_NS_VIEW
(frame
) window
] currentEvent
];
573 /* HACK: Cocoa/Carbon will request update on every keystroke
574 via IsMenuKeyEvent -> CheckMenusForKeyEvent. These are not needed
575 since key equivalents are handled through emacs.
576 On Leopard, even keystroke events generate SystemDefined events, but
577 their subtype is 8. */
578 if ([event
type] != NSSystemDefined ||
[event subtype
] == 8
579 /* Also, don't try this if from an event picked up asynchronously,
580 as lots of lisp evaluation happens in ns_update_menubar. */
581 || handling_signal
!= 0)
583 /*fprintf (stderr, "Updating menu '%s'\n", [[self title] UTF8String]); NSLog (@"%@\n", event); */
584 ns_update_menubar
(frame
, 1, self
);
588 - (BOOL
)performKeyEquivalent
: (NSEvent
*)theEvent
590 if (SELECTED_FRAME
() && FRAME_NS_P
(SELECTED_FRAME
())
591 && FRAME_NS_VIEW
(SELECTED_FRAME
()))
592 [FRAME_NS_VIEW
(SELECTED_FRAME
()) keyDown
: theEvent
];
597 /* Parse a widget_value's key rep (examples: 's-p', 's-S', '(C-x C-s)', '<f13>')
598 into an accelerator string. We are only able to display a single character
599 for an accelerator, together with an optional modifier combination. (Under
600 Carbon more control was possible, but in Cocoa multi-char strings passed to
601 NSMenuItem get ignored. For now we try to display a super-single letter
602 combo, and return the others as strings to be appended to the item title.
603 (This is signaled by setting keyEquivModMask to 0 for now.) */
604 -(NSString
*)parseKeyEquiv
: (char *)key
607 keyEquivModMask
= NSCommandKeyMask
;
609 if (!key ||
!strlen
(key
))
612 while (*tpos
== ' ' ||
*tpos
== '(')
614 if ((*tpos
== 's') && (*(tpos
+1) == '-'))
616 return [NSString stringWithFormat
: @"
%c", tpos[2]];
618 keyEquivModMask
= 0; /* signal */
619 return [NSString stringWithUTF8String
: tpos
];
623 - (NSMenuItem
*)addItemWithWidgetValue
: (void
*)wvptr
626 widget_value
*wv
= (widget_value
*)wvptr
;
628 if (name_is_separator
(wv
->name
))
630 item
= [NSMenuItem separatorItem
];
631 [self addItem
: item
];
635 NSString
*title, *keyEq
;
636 title = [NSString stringWithUTF8String
: wv
->name
];
638 title = @"
< ?
>"
; /* (get out in the open so we know about it) */
640 keyEq
= [self parseKeyEquiv
: wv
->key
];
642 /* OS X just ignores modifier strings longer than one character */
643 if (keyEquivModMask
== 0)
644 title = [title stringByAppendingFormat
: @"
(%@)", keyEq];
647 item
= [self addItemWithTitle
: (NSString
*)title
648 action
: @selector
(menuDown
:)
649 keyEquivalent
: keyEq
];
650 [item setKeyEquivalentModifierMask
: keyEquivModMask
];
652 [item setEnabled
: wv
->enabled
];
654 /* Draw radio buttons and tickboxes */
655 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE ||
656 wv
->button_type
== BUTTON_TYPE_RADIO
))
657 [item setState
: NSOnState
];
659 [item setState
: NSOffState
];
661 [item setTag
: (NSInteger
)wv
->call_data
];
673 for (n
= [self numberOfItems
]-1; n
>= 0; n
--)
675 NSMenuItem
*item
= [self itemAtIndex
: n
];
676 NSString
*title = [item
title];
677 if (([title length] == 0 /* OSX 10.5 */
678 ||
[ns_app_name isEqualToString
: title] /* from 10.6 on */
679 ||
[@"Apple" isEqualToString
: title]) /* older */
680 && ![item isSeparatorItem
])
682 [self removeItemAtIndex
: n
];
687 - (void
)fillWithWidgetValue
: (void
*)wvptr
689 widget_value
*wv
= (widget_value
*)wvptr
;
691 /* clear existing contents */
692 [self setMenuChangedMessagesEnabled
: NO
];
695 /* add new contents */
696 for (; wv
!= NULL; wv
= wv
->next
)
698 NSMenuItem
*item
= [self addItemWithWidgetValue
: wv
];
702 EmacsMenu
*submenu
= [[EmacsMenu alloc
] initWithTitle
: [item
title]];
704 [self setSubmenu
: submenu forItem
: item
];
705 [submenu fillWithWidgetValue
: wv
->contents
];
707 [item setAction
: nil
];
711 [self setMenuChangedMessagesEnabled
: YES
];
712 #ifdef NS_IMPL_GNUSTEP
713 if ([[self window
] isVisible
])
716 if ([self supermenu
] == nil
)
722 /* adds an empty submenu and returns it */
723 - (EmacsMenu
*)addSubmenuWithTitle
: (char *)title forFrame
: (struct frame
*)f
725 NSString
*titleStr
= [NSString stringWithUTF8String
: title];
726 NSMenuItem
*item
= [self addItemWithTitle
: titleStr
727 action
: nil
/*@selector (menuDown:) */
729 EmacsMenu
*submenu
= [[EmacsMenu alloc
] initWithTitle
: titleStr frame
: f
];
730 [self setSubmenu
: submenu forItem
: item
];
735 /* run a menu in popup mode */
736 - (Lisp_Object
)runMenuAt
: (NSPoint
)p forFrame
: (struct frame
*)f
737 keymaps
: (int
)keymaps
739 EmacsView
*view = FRAME_NS_VIEW
(f
);
740 /* p = [view convertPoint:p fromView: nil]; */
741 p.y
= NSHeight
([view frame
]) - p.y
;
742 NSEvent
*e
= [[view window
] currentEvent
];
743 NSEvent
*event
= [NSEvent mouseEventWithType
: NSRightMouseDown
746 timestamp
: [e timestamp
]
747 windowNumber
: [[view window
] windowNumber
]
749 eventNumber
: 0/*[e eventNumber] */
754 context_menu_value
= -1;
755 [NSMenu popUpContextMenu
: self withEvent
: event forView
: view];
756 retVal
= context_menu_value
;
757 context_menu_value
= 0;
759 ? find_and_return_menu_selection
(f
, keymaps
, (void
*)retVal
)
767 /* ==========================================================================
769 Context Menu: implementing functions
771 ========================================================================== */
774 ns_menu_show
(FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
775 Lisp_Object
title, char **error)
779 Lisp_Object window
, tem
, keymap
;
780 int specpdl_count
= SPECPDL_INDEX
();
781 widget_value
*wv
, *first_wv
= 0;
785 /* now parse stage 2 as in ns_update_menubar */
786 wv
= xmalloc_widget_value
();
787 wv
->name
= "contextmenu"
;
790 wv
->button_type
= BUTTON_TYPE_NONE
;
795 /* FIXME: a couple of one-line differences prevent reuse */
796 wv
= digest_single_submenu
(0, menu_items_used
, Qnil
);
799 widget_value
*save_wv
= 0, *prev_wv
= 0;
800 widget_value
**submenu_stack
801 = (widget_value
**) alloca
(menu_items_used
* sizeof
(widget_value
*));
802 /* Lisp_Object *subprefix_stack
803 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); */
804 int submenu_depth
= 0;
808 /* Loop over all panes and items, filling in the tree. */
810 while (i
< menu_items_used
)
812 if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qnil
))
814 submenu_stack
[submenu_depth
++] = save_wv
;
820 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qlambda
))
823 save_wv
= submenu_stack
[--submenu_depth
];
827 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qt
)
828 && submenu_depth
!= 0)
829 i
+= MENU_ITEMS_PANE_LENGTH
;
830 /* Ignore a nil in the item list.
831 It's meaningful only for dialog boxes. */
832 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qquote
))
834 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qt
))
836 /* Create a new pane. */
837 Lisp_Object pane_name
, prefix
;
840 pane_name
= AREF
(menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
841 prefix
= AREF
(menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
843 #ifndef HAVE_MULTILINGUAL_MENU
844 if (STRINGP
(pane_name
) && STRING_MULTIBYTE
(pane_name
))
846 pane_name
= ENCODE_MENU_STRING
(pane_name
);
847 ASET
(menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
850 pane_string
= (NILP
(pane_name
)
851 ? ""
: (char *) SDATA
(pane_name
));
852 /* If there is just one top-level pane, put all its items directly
853 under the top-level menu. */
854 if (menu_items_n_panes
== 1)
857 /* If the pane has a meaningful name,
858 make the pane a top-level menu item
859 with its items as a submenu beneath it. */
860 if (!keymaps
&& strcmp (pane_string
, ""
))
862 wv
= xmalloc_widget_value
();
866 first_wv
->contents
= wv
;
867 wv
->name
= pane_string
;
868 if (keymaps
&& !NILP
(prefix
))
872 wv
->button_type
= BUTTON_TYPE_NONE
;
883 i
+= MENU_ITEMS_PANE_LENGTH
;
887 /* Create a new item within current pane. */
888 Lisp_Object item_name
, enable
, descrip
, def
, type, selected
, help;
889 item_name
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
890 enable
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
891 descrip
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
892 def
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
893 type = AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
894 selected
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
895 help = AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
897 #ifndef HAVE_MULTILINGUAL_MENU
898 if (STRINGP
(item_name
) && STRING_MULTIBYTE
(item_name
))
900 item_name
= ENCODE_MENU_STRING
(item_name
);
901 ASET
(menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
904 if (STRINGP
(descrip
) && STRING_MULTIBYTE
(descrip
))
906 descrip
= ENCODE_MENU_STRING
(descrip
);
907 ASET
(menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
909 #endif
/* not HAVE_MULTILINGUAL_MENU */
911 wv
= xmalloc_widget_value
();
915 save_wv
->contents
= wv
;
916 wv
->name
= (char *) SDATA
(item_name
);
918 wv
->key
= (char *) SDATA
(descrip
);
920 /* If this item has a null value,
921 make the call_data null so that it won't display a box
922 when the mouse is on it. */
924 = !NILP
(def
) ?
(void
*) &XVECTOR
(menu_items
)->contents
[i
] : 0;
925 wv
->enabled
= !NILP
(enable
);
928 wv
->button_type
= BUTTON_TYPE_NONE
;
929 else if (EQ
(type, QCtoggle
))
930 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
931 else if (EQ
(type, QCradio
))
932 wv
->button_type
= BUTTON_TYPE_RADIO
;
936 wv
->selected
= !NILP
(selected
);
938 if (! STRINGP
(help))
945 i
+= MENU_ITEMS_ITEM_LENGTH
;
953 widget_value
*wv_title
= xmalloc_widget_value
();
954 widget_value
*wv_sep
= xmalloc_widget_value
();
956 /* Maybe replace this separator with a bitmap or owner-draw item
957 so that it looks better. Having two separators looks odd. */
959 wv_sep
->next
= first_wv
->contents
;
962 #ifndef HAVE_MULTILINGUAL_MENU
963 if (STRING_MULTIBYTE
(title))
964 title = ENCODE_MENU_STRING
(title);
967 wv_title
->name
= (char *) SDATA
(title);
968 wv_title
->enabled
= NO
;
969 wv_title
->button_type
= BUTTON_TYPE_NONE
;
970 wv_title
->help = Qnil
;
971 wv_title
->next
= wv_sep
;
972 first_wv
->contents
= wv_title
;
975 pmenu
= [[EmacsMenu alloc
] initWithTitle
:
976 [NSString stringWithUTF8String
: SDATA
(title)]];
977 [pmenu fillWithWidgetValue
: first_wv
->contents
];
978 free_menubar_widget_value_tree
(first_wv
);
979 unbind_to
(specpdl_count
, Qnil
);
981 popup_activated_flag
= 1;
982 tem
= [pmenu runMenuAt
: p forFrame
: f keymaps
: keymaps
];
983 popup_activated_flag
= 0;
984 [[FRAME_NS_VIEW
(SELECTED_FRAME
()) window
] makeKeyWindow
];
990 /* ==========================================================================
992 Toolbar: externally-called functions
994 ========================================================================== */
997 free_frame_tool_bar
(FRAME_PTR f
)
998 /* --------------------------------------------------------------------------
999 Under NS we just hide the toolbar until it might be needed again.
1000 -------------------------------------------------------------------------- */
1003 [[FRAME_NS_VIEW
(f
) toolbar
] setVisible
: NO
];
1008 update_frame_tool_bar
(FRAME_PTR f
)
1009 /* --------------------------------------------------------------------------
1010 Update toolbar contents
1011 -------------------------------------------------------------------------- */
1014 EmacsToolbar
*toolbar
= [FRAME_NS_VIEW
(f
) toolbar
];
1017 [toolbar clearActive
];
1019 /* update EmacsToolbar as in GtkUtils, build items list */
1020 for (i
= 0; i
< f
->n_tool_bar_items
; ++i
)
1022 #define TOOLPROP
(IDX
) AREF
(f
->tool_bar_items
, \
1023 i
* TOOL_BAR_ITEM_NSLOTS
+ (IDX
))
1025 BOOL enabled_p
= !NILP
(TOOLPROP
(TOOL_BAR_ITEM_ENABLED_P
));
1026 BOOL selected_p
= !NILP
(TOOLPROP
(TOOL_BAR_ITEM_SELECTED_P
));
1031 Lisp_Object helpObj
;
1034 /* If image is a vector, choose the image according to the
1036 image = TOOLPROP
(TOOL_BAR_ITEM_IMAGES
);
1037 if (VECTORP
(image))
1039 /* NS toolbar auto-computes disabled and selected images */
1040 idx
= TOOL_BAR_IMAGE_ENABLED_SELECTED
;
1041 xassert
(ASIZE
(image) >= idx
);
1042 image = AREF
(image, idx
);
1048 /* Ignore invalid image specifications. */
1049 if (!valid_image_p
(image))
1051 NSLog
(@"Invalid
image for toolbar item"
);
1055 img_id
= lookup_image
(f
, image);
1056 img
= IMAGE_FROM_ID
(f
, img_id
);
1057 prepare_image_for_display
(f
, img
);
1059 if (img
->load_failed_p || img
->pixmap
== nil
)
1061 NSLog
(@"Could not prepare toolbar
image for display."
);
1065 helpObj
= TOOLPROP
(TOOL_BAR_ITEM_HELP
);
1067 helpObj
= TOOLPROP
(TOOL_BAR_ITEM_CAPTION
);
1068 helpText
= NILP
(helpObj
) ? ""
: (char *)SDATA
(helpObj
);
1070 [toolbar addDisplayItemWithImage
: img
->pixmap idx
: i helpText
: helpText
1071 enabled
: enabled_p
];
1075 if (![toolbar isVisible
])
1076 [toolbar setVisible
: YES
];
1078 if ([toolbar changed
])
1080 /* inform app that toolbar has changed */
1081 NSDictionary
*dict
= [toolbar configurationDictionary
];
1082 NSMutableDictionary
*newDict
= [dict mutableCopy
];
1083 NSEnumerator
*keys
= [[dict allKeys
] objectEnumerator
];
1085 while ((key
= [keys nextObject
]) != nil
)
1087 NSObject
*val
= [dict objectForKey
: key
];
1088 if ([val isKindOfClass
: [NSArray
class]])
1091 [toolbar toolbarDefaultItemIdentifiers
: toolbar
]
1096 [toolbar setConfigurationFromDictionary
: newDict
];
1104 /* ==========================================================================
1106 Toolbar: class implementation
1108 ========================================================================== */
1110 @implementation EmacsToolbar
1112 - initForView
: (EmacsView
*)view withIdentifier
: (NSString
*)identifier
1114 self
= [super initWithIdentifier
: identifier
];
1116 [self setDisplayMode
: NSToolbarDisplayModeIconOnly
];
1117 [self setSizeMode
: NSToolbarSizeModeSmall
];
1118 [self setDelegate
: self
];
1119 identifierToItem
= [[NSMutableDictionary alloc
] initWithCapacity
: 10];
1120 activeIdentifiers
= [[NSMutableArray alloc
] initWithCapacity
: 8];
1121 prevEnablement
= enablement
= 0L;
1127 [prevIdentifiers release
];
1128 [activeIdentifiers release
];
1129 [identifierToItem release
];
1133 - (void
) clearActive
1135 [prevIdentifiers release
];
1136 prevIdentifiers
= [activeIdentifiers copy
];
1137 [activeIdentifiers removeAllObjects
];
1138 prevEnablement
= enablement
;
1144 return [activeIdentifiers isEqualToArray
: prevIdentifiers
] &&
1145 enablement
== prevEnablement ? NO
: YES
;
1148 - (void
) addDisplayItemWithImage
: (EmacsImage
*)img idx
: (int
)idx
1149 helpText
: (char *)help enabled
: (BOOL
)enabled
1151 /* 1) come up w/identifier */
1152 NSString
*identifier
1153 = [NSString stringWithFormat
: @"
%u", [img hash]];
1155 /* 2) create / reuse item */
1156 NSToolbarItem
*item
= [identifierToItem objectForKey
: identifier
];
1159 item
= [[[NSToolbarItem alloc
] initWithItemIdentifier
: identifier
]
1161 [item setImage
: img
];
1162 [item setToolTip
: [NSString stringWithUTF8String
: help]];
1163 [item setTarget
: emacsView
];
1164 [item setAction
: @selector
(toolbarClicked
:)];
1168 [item setEnabled
: enabled
];
1170 /* 3) update state */
1171 [identifierToItem setObject
: item forKey
: identifier
];
1172 [activeIdentifiers addObject
: identifier
];
1173 enablement
= (enablement
<< 1) |
(enabled
== YES
);
1176 /* This overrides super's implementation, which automatically sets
1177 all items to enabled state (for some reason). */
1178 - (void
)validateVisibleItems
{ }
1181 /* delegate methods */
1183 - (NSToolbarItem
*)toolbar
: (NSToolbar
*)toolbar
1184 itemForItemIdentifier
: (NSString
*)itemIdentifier
1185 willBeInsertedIntoToolbar
: (BOOL
)flag
1187 /* look up NSToolbarItem by identifier and return... */
1188 return [identifierToItem objectForKey
: itemIdentifier
];
1191 - (NSArray
*)toolbarDefaultItemIdentifiers
: (NSToolbar
*)toolbar
1193 /* return entire set.. */
1194 return activeIdentifiers
;
1197 /* for configuration palette (not yet supported) */
1198 - (NSArray
*)toolbarAllowedItemIdentifiers
: (NSToolbar
*)toolbar
1200 /* return entire set... */
1201 return [identifierToItem allKeys
];
1204 /* optional and unneeded */
1205 /* - toolbarWillAddItem: (NSNotification *)notification { } */
1206 /* - toolbarDidRemoveItem: (NSNotification *)notification { } */
1207 /* - (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar */
1209 @
end /* EmacsToolbar */
1213 /* ==========================================================================
1215 Tooltip: class implementation
1217 ========================================================================== */
1219 /* Needed because NeXTstep does not provide enough control over tooltip
1221 @implementation EmacsTooltip
1225 NSColor
*col
= [NSColor colorWithCalibratedRed
: 1.0 green
: 1.0
1226 blue
: 0.792 alpha
: 0.95];
1227 NSFont
*font
= [NSFont toolTipsFontOfSize
: 0];
1228 NSFont
*sfont
= [font screenFont
];
1229 int height
= [sfont ascender
] - [sfont descender
];
1230 /*[font boundingRectForFont].size.height; */
1231 NSRect r
= NSMakeRect
(0, 0, 100, height
+6);
1233 textField
= [[NSTextField alloc
] initWithFrame
: r
];
1234 [textField setFont
: font
];
1235 [textField setBackgroundColor
: col
];
1237 [textField setEditable
: NO
];
1238 [textField setSelectable
: NO
];
1239 [textField setBordered
: YES
];
1240 [textField setBezeled
: YES
];
1241 [textField setDrawsBackground
: YES
];
1243 win
= [[NSWindow alloc
]
1244 initWithContentRect
: [textField frame
]
1246 backing
: NSBackingStoreBuffered
1248 [win setReleasedWhenClosed
: NO
];
1249 [win setDelegate
: self
];
1250 [[win contentView
] addSubview
: textField
];
1251 /* [win setBackgroundColor: col]; */
1252 [win setOpaque
: NO
];
1261 [textField release
];
1265 - (void
) setText
: (char *)text
1267 NSString
*str
= [NSString stringWithUTF8String
: text];
1268 NSRect r
= [textField frame
];
1269 NSSize textSize
= [str sizeWithAttributes
:
1270 [NSDictionary dictionaryWithObject
: [[textField font
] screenFont
]
1271 forKey
: NSFontAttributeName
]];
1272 NSSize padSize
= [[[textField font
] screenFont
]
1273 boundingRectForFont
].
size;
1275 r.
size.width
= textSize.width
+ padSize.width
/2;
1276 r.
size.height
= textSize.height
+ padSize.height
/2;
1277 [textField setFrame
: r
];
1278 [textField setStringValue
: str
];
1281 - (void
) showAtX
: (int
)x Y
: (int
)y
for: (int
)seconds
1283 NSRect wr
= [win frame
];
1285 wr.origin
= NSMakePoint
(x
, y
);
1286 wr.
size = [textField frame
].
size;
1288 [win setFrame
: wr display
: YES
];
1289 [win orderFront
: self
];
1291 timer
= [NSTimer scheduledTimerWithTimeInterval
: (float
)seconds target
: self
1292 selector
: @selector
(hide
)
1293 userInfo
: nil repeats
: NO
];
1302 if ([timer isValid
])
1311 return timer
!= nil
;
1316 return [textField frame
];
1319 @
end /* EmacsTooltip */
1323 /* ==========================================================================
1325 Popup Dialog: implementing functions
1327 ========================================================================== */
1331 pop_down_menu
(Lisp_Object arg
)
1333 struct Lisp_Save_Value
*p
= XSAVE_VALUE
(arg
);
1334 if (popup_activated_flag
)
1336 popup_activated_flag
= 0;
1338 [NSApp endModalSession
: popupSession
];
1339 [((EmacsDialogPanel
*) (p
->pointer
)) close];
1340 [[FRAME_NS_VIEW
(SELECTED_FRAME
()) window
] makeKeyWindow
];
1348 ns_popup_dialog
(Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
1351 Lisp_Object window
, tem
;
1356 NSTRACE
(x
-popup
-dialog);
1360 isQ
= NILP
(header
);
1362 if (EQ
(position
, Qt
)
1363 ||
(CONSP
(position
) && (EQ
(XCAR
(position
), Qmenu_bar
)
1364 || EQ
(XCAR
(position
), Qtool_bar
))))
1366 window
= selected_window
;
1368 else if (CONSP
(position
))
1371 tem
= Fcar
(position
);
1372 if (XTYPE
(tem
) == Lisp_Cons
)
1373 window
= Fcar
(Fcdr
(position
));
1376 tem
= Fcar
(Fcdr
(position
)); /* EVENT_START (position) */
1377 window
= Fcar
(tem
); /* POSN_WINDOW (tem) */
1380 else if (WINDOWP
(position
) || FRAMEP
(position
))
1387 if (FRAMEP
(window
))
1388 f
= XFRAME
(window
);
1389 else if (WINDOWP
(window
))
1391 CHECK_LIVE_WINDOW
(window
);
1392 f
= XFRAME
(WINDOW_FRAME
(XWINDOW
(window
)));
1395 CHECK_WINDOW
(window
);
1397 p.x
= (int
)f
->left_pos
+ ((int
)FRAME_COLUMN_WIDTH
(f
) * f
->text_cols
)/2;
1398 p.y
= (int
)f
->top_pos
+ (FRAME_LINE_HEIGHT
(f
) * f
->text_lines
)/2;
1401 dialog = [[EmacsDialogPanel alloc
] initFromContents
: contents
1404 int specpdl_count
= SPECPDL_INDEX
();
1405 record_unwind_protect
(pop_down_menu
, make_save_value
(dialog, 0));
1406 popup_activated_flag
= 1;
1407 tem
= [dialog runDialogAt
: p
];
1408 unbind_to
(specpdl_count
, Qnil
); /* calls pop_down_menu */
1416 /* ==========================================================================
1418 Popup Dialog: class implementation
1420 ========================================================================== */
1422 @interface FlippedView
: NSView
1427 @implementation FlippedView
1434 @implementation EmacsDialogPanel
1437 #define ICONSIZE
64.0
1438 #define TEXTHEIGHT
20.0
1439 #define MINCELLWIDTH
90.0
1441 - initWithContentRect
: (NSRect
)contentRect styleMask
: (NSUInteger
)aStyle
1442 backing
: (NSBackingStoreType
)backingType defer
: (BOOL
)flag
1444 NSSize spacing
= {SPACER
, SPACER
};
1446 char this_cmd_name
[80];
1448 static NSImageView
*imgView
;
1449 static FlippedView
*contentView
;
1454 area.origin.x
= 3*SPACER
;
1455 area.origin.y
= 2*SPACER
;
1456 area.
size.width
= ICONSIZE
;
1457 area.
size.height
= ICONSIZE
;
1458 img
= [[NSImage imageNamed
: @"NSApplicationIcon"
] copy
];
1459 [img setScalesWhenResized
: YES
];
1460 [img setSize
: NSMakeSize
(ICONSIZE
, ICONSIZE
)];
1461 imgView
= [[NSImageView alloc
] initWithFrame
: area
];
1462 [imgView setImage
: img
];
1463 [imgView setEditable
: NO
];
1467 aStyle
= NSTitledWindowMask
;
1471 [super initWithContentRect
: contentRect styleMask
: aStyle
1472 backing
: backingType defer
: flag];
1473 contentView
= [[FlippedView alloc
] initWithFrame
: [[self contentView
] frame
]];
1474 [self setContentView
: contentView
];
1476 [[self contentView
] setAutoresizesSubviews
: YES
];
1478 [[self contentView
] addSubview
: imgView
];
1479 [self setTitle
: @""
];
1481 area.origin.x
+= ICONSIZE
+2*SPACER
;
1482 /* area.origin.y = TEXTHEIGHT; ICONSIZE/2-10+SPACER; */
1483 area.
size.width
= 400;
1484 area.
size.height
= TEXTHEIGHT
;
1485 command
= [[[NSTextField alloc
] initWithFrame
: area
] autorelease
];
1486 [[self contentView
] addSubview
: command
];
1487 [command setStringValue
: ns_app_name
];
1488 [command setDrawsBackground
: NO
];
1489 [command setBezeled
: NO
];
1490 [command setSelectable
: NO
];
1491 [command setFont
: [NSFont boldSystemFontOfSize
: 13.0]];
1493 /* area.origin.x = ICONSIZE+2*SPACER;
1494 area.origin.y = TEXTHEIGHT + 2*SPACER;
1495 area.size.width = 400;
1496 area.size.height= 2;
1497 tem = [[[NSBox alloc] initWithFrame: area] autorelease];
1498 [[self contentView] addSubview: tem];
1499 [tem setTitlePosition: NSNoTitle];
1500 [tem setAutoresizingMask: NSViewWidthSizable];*/
1502 /* area.origin.x = ICONSIZE+2*SPACER; */
1503 area.origin.y
+= TEXTHEIGHT
+SPACER
;
1504 area.
size.width
= 400;
1505 area.
size.height
= TEXTHEIGHT
;
1506 title = [[[NSTextField alloc
] initWithFrame
: area
] autorelease
];
1507 [[self contentView
] addSubview
: title];
1508 [title setDrawsBackground
: NO
];
1509 [title setBezeled
: NO
];
1510 [title setSelectable
: NO
];
1511 [title setFont
: [NSFont systemFontOfSize
: 11.0]];
1513 cell = [[[NSButtonCell alloc
] initTextCell
: @""
] autorelease
];
1514 [cell setBordered
: NO
];
1515 [cell setEnabled
: NO
];
1516 [cell setCellAttribute
: NSCellIsInsetButton to
: 8];
1517 [cell setBezelStyle
: NSRoundedBezelStyle
];
1519 matrix
= [[NSMatrix alloc
] initWithFrame
: contentRect
1520 mode
: NSHighlightModeMatrix
1523 numberOfColumns
: 1];
1524 [[self contentView
] addSubview
: matrix
];
1526 [matrix setFrameOrigin
: NSMakePoint
(area.origin.x
,
1527 area.origin.y
+ (TEXTHEIGHT
+3*SPACER
))];
1528 [matrix setIntercellSpacing
: spacing
];
1530 [self setOneShot
: YES
];
1531 [self setReleasedWhenClosed
: YES
];
1532 [self setHidesOnDeactivate
: YES
];
1537 - (BOOL
)windowShouldClose
: (id
)sender
1539 [NSApp stopModalWithCode
: XHASH
(Qnil
)]; // FIXME
: BIG UGLY HACK
!!
1544 void process_dialog
(id window
, Lisp_Object list
)
1549 for (; XTYPE
(list
) == Lisp_Cons
; list
= XCDR
(list
))
1552 if (XTYPE
(item
) == Lisp_String
)
1554 [window addString
: SDATA
(item
) row
: row
++];
1556 else if (XTYPE
(item
) == Lisp_Cons
)
1558 [window addButton
: SDATA
(XCAR
(item
))
1559 value
: XCDR
(item
) row
: row
++];
1561 else if (NILP
(item
))
1570 - addButton
: (char *)str value
: (Lisp_Object
)val row
: (int
)row
1579 cell = [matrix cellAtRow
: row column
: cols
-1];
1580 [cell setTarget
: self
];
1581 [cell setAction
: @selector
(clicked
: )];
1582 [cell setTitle
: [NSString stringWithUTF8String
: str
]];
1583 [cell setTag
: XHASH
(val
)]; // FIXME
: BIG UGLY HACK
!!
1584 [cell setBordered
: YES
];
1585 [cell setEnabled
: YES
];
1591 - addString
: (char *)str row
: (int
)row
1600 cell = [matrix cellAtRow
: row column
: cols
-1];
1601 [cell setTitle
: [NSString stringWithUTF8String
: str
]];
1602 [cell setBordered
: YES
];
1603 [cell setEnabled
: NO
];
1619 NSArray
*sellist
= nil
;
1622 sellist
= [sender selectedCells
];
1623 if ([sellist count
]<1)
1626 seltag
= [[sellist objectAtIndex
: 0] tag
];
1627 if (seltag
!= XHASH
(Qundefined
)) // FIXME
: BIG UGLY HACK
!!
1628 [NSApp stopModalWithCode
: seltag
];
1633 - initFromContents
: (Lisp_Object
)contents isQuestion
: (BOOL
)isQ
1638 if (XTYPE
(contents
) == Lisp_Cons
)
1640 head
= Fcar
(contents
);
1641 process_dialog
(self
, Fcdr
(contents
));
1646 if (XTYPE
(head
) == Lisp_String
)
1647 [title setStringValue
:
1648 [NSString stringWithUTF8String
: SDATA
(head
)]];
1649 else if (isQ
== YES
)
1650 [title setStringValue
: @"Question"
];
1652 [title setStringValue
: @"Information"
];
1658 if (cols
== 1 && rows
> 1) /* Never told where to split */
1661 for (i
= 0; i
<rows
/2; i
++)
1663 [matrix putCell
: [matrix cellAtRow
: (rows
+1)/2 column
: 0]
1664 atRow
: i column
: 1];
1665 [matrix removeRow
: (rows
+1)/2];
1671 NSSize csize
= [matrix cellSize
];
1672 if (csize.width
< MINCELLWIDTH
)
1674 csize.width
= MINCELLWIDTH
;
1675 [matrix setCellSize
: csize
];
1676 [matrix sizeToCells
];
1681 [command sizeToFit
];
1685 if (r.
size.width
+r.origin.x
> t.
size.width
+t.origin.x
)
1687 t.origin.x
= r.origin.x
;
1688 t.
size.width
= r.
size.width
;
1690 r
= [command frame
];
1691 if (r.
size.width
+r.origin.x
> t.
size.width
+t.origin.x
)
1693 t.origin.x
= r.origin.x
;
1694 t.
size.width
= r.
size.width
;
1698 s
= [(NSView
*)[self contentView
] frame
];
1699 r.
size.width
+= t.origin.x
+t.
size.width
+2*SPACER
-s.
size.width
;
1700 r.
size.height
+= t.origin.y
+t.
size.height
+SPACER
-s.
size.height
;
1701 [self setFrame
: r display
: NO
];
1710 { [super dealloc
]; return; };
1714 - (Lisp_Object
)runDialogAt
: (NSPoint
)p
1717 extern EMACS_TIME timer_check
(int do_it_now
); /* TODO: add to a header */
1719 /* initiate a session that will be ended by pop_down_menu */
1720 popupSession
= [NSApp beginModalSessionForWindow
: self
];
1721 while (popup_activated_flag
1722 && (ret
= [NSApp runModalSession
: popupSession
])
1723 == NSRunContinuesResponse
)
1725 /* Run this for timers.el, indep of atimers; might not return.
1726 TODO: use return value to avoid calling every iteration. */
1728 [NSThread sleepUntilDate
: [NSDate dateWithTimeIntervalSinceNow
: 0.1]];
1731 { /* FIXME: BIG UGLY HACK!!! */
1733 *(EMACS_INT
*)(&tmp
) = ret
;
1741 /* ==========================================================================
1745 ========================================================================== */
1747 DEFUN
("ns
-reset-menu"
, Fns_reset_menu
, Sns_reset_menu
, 0, 0, 0,
1748 doc: /* Cause the NS menu to be re-calculated. */)
1751 set_frame_menubar
(SELECTED_FRAME
(), 1, 0);
1756 DEFUN
("x
-popup
-dialog"
, Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
1757 doc: /* Pop up a dialog box and return user's selection.
1758 POSITION specifies which frame to use.
1759 This is normally a mouse button event or a window or frame.
1760 If POSITION is t, it means to use the frame the mouse is on.
1761 The dialog box appears in the middle of the specified frame.
1763 CONTENTS specifies the alternatives to display in the dialog box.
1764 It is a list of the form (DIALOG ITEM1 ITEM2...).
1765 Each ITEM is a cons cell (STRING . VALUE).
1766 The return value is VALUE from the chosen item.
1768 An ITEM may also be just a string--that makes a nonselectable item.
1769 An ITEM may also be nil--that means to put all preceding items
1770 on the left of the dialog box and all following items on the right.
1771 \(By default, approximately half appear on each side.)
1773 If HEADER is non-nil, the frame title for the box is "Information",
1774 otherwise it is "Question".
1776 If the user gets rid of the dialog box without making a valid choice,
1777 for instance using the window manager, then this produces a quit and
1778 `x-popup-dialog' does not return. */)
1779 (position
, contents
, header
)
1780 Lisp_Object position
, contents
, header
;
1782 return ns_popup_dialog
(position
, contents
, header
);
1785 DEFUN
("
menu-or
-popup
-active
-p"
, Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
1786 doc: /* Return t if a menu or popup dialog is active. */)
1789 return popup_activated
() ? Qt
: Qnil
;
1792 /* ==========================================================================
1794 Lisp interface declaration
1796 ========================================================================== */
1801 defsubr
(&Sx_popup_dialog
);
1802 defsubr
(&Sns_reset_menu
);
1803 defsubr
(&Smenu_or_popup_active_p
);
1805 Qdebug_on_next_call
= intern
("
debug-on
-next
-call"
);
1806 staticpro
(&Qdebug_on_next_call
);
1809 // arch
-tag
: 75773656-52e5
-4c44
-a398
-47bd87b32619