1 /* NeXT/Open/GNUstep and MacOSX Cocoa menu and toolbar module.
2 Copyright (C) 2007, 2008 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, or (at your option)
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; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
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. */
31 #include "blockinput.h"
33 #include "termhooks.h"
37 #include
<sys
/timeb.h
>
38 #include
<sys
/types.h
>
40 #define MenuStagger
10.0
43 int menu_trace_num
= 0;
44 #define NSTRACE
(x
) fprintf (stderr
, "
%s:%d: [%d] " #x "\n", \
45 __FILE__
, __LINE__
, ++menu_trace_num
)
51 /* Include lisp -> C common menu parsing code */
52 #define ENCODE_MENU_STRING
(str
) ENCODE_UTF_8
(str
)
53 #include "nsmenu_common.c"
56 extern
struct widget_value
;
58 extern Lisp_Object Qundefined
, Qmenu_enable
, Qmenu_bar_update_hook
;
59 extern Lisp_Object QCtoggle
, QCradio
;
61 extern Lisp_Object Vmenu_updating_frame
;
63 Lisp_Object Qdebug_on_next_call
;
64 extern Lisp_Object Voverriding_local_map
, Voverriding_local_map_menu_flag
,
65 Qoverriding_local_map
, Qoverriding_terminal_local_map
;
67 extern
long context_menu_value
;
68 EmacsMenu
*mainMenu
, *svcsMenu
;
70 /* NOTE: toolbar implementation is at end,
71 following complete menu implementation. */
74 /* ==========================================================================
76 Menu: Externally-called functions
78 ========================================================================== */
81 /*23: PENDING: not currently used, but should normalize with other terms. */
83 x_activate_menubar
(struct frame
*f
)
85 fprintf (stderr
, "XXX
: Received x_activate_menubar event.
\n"
);
89 /* Supposed to discard menubar and free storage. Since we share the
90 menubar among frames and update its context for the focused window,
91 there is nothing to do here. */
93 free_frame_menubar
(struct frame
*f
)
99 /* --------------------------------------------------------------------------
100 Update menubar. Three cases:
101 1) deep_p = 0, submenu = nil: Fresh switch onto a frame -- either set up
102 just top-level menu strings (OS X), or goto case (2) (GNUstep).
103 2) deep_p = 1, submenu = nil: Recompute all submenus.
104 3) deep_p = 1, submenu = non-nil: Update contents of a single submenu.
105 -------------------------------------------------------------------------- */
106 /*#define NSMENUPROFILE 1 */
108 ns_update_menubar
(struct frame
*f
, int deep_p
, EmacsMenu
*submenu
)
110 NSAutoreleasePool
*pool
;
111 id
menu = [NSApp mainMenu
];
112 static EmacsMenu
*last_submenu
= nil
;
114 const
char *submenuTitle
= [[submenu
title] UTF8String
];
115 extern int waiting_for_input
;
118 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
126 NSTRACE
(set_frame_menubar
);
128 if (f
!= SELECTED_FRAME
())
130 XSETFRAME
(Vmenu_updating_frame
, f
);
131 /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */
134 pool
= [[NSAutoreleasePool alloc
] init
];
136 /* Menu may have been created automatically; if so, discard it. */
137 if ([menu isKindOfClass
: [EmacsMenu
class]] == NO
)
145 menu = [[EmacsMenu alloc
] initWithTitle
: @"Emacs"
];
149 { /* close up anything on there */
150 id attMenu
= [menu attachedMenu
];
157 t
= -(1000*tb.time
+tb.millitm
);
160 /* widget_value is a straightforward object translation of emacs's
161 Byzantine lisp menu structures */
162 wv
= xmalloc_widget_value
();
166 wv
->button_type
= BUTTON_TYPE_NONE
;
170 #ifdef NS_IMPL_GNUSTEP
171 deep_p
= 1; /* until GNUstep NSMenu implements the Panther delegation model */
176 /* Fully parse one or more of the submenus. */
178 int
*submenu_start
, *submenu_end
;
179 int
*submenu_top_level_items
, *submenu_n_panes
;
180 struct buffer
*prev
= current_buffer
;
182 int specpdl_count
= SPECPDL_INDEX
();
183 int previous_menu_items_used
= f
->menu_bar_items_used
;
184 Lisp_Object
*previous_items
185 = (Lisp_Object
*) alloca
(previous_menu_items_used
186 * sizeof
(Lisp_Object
));
188 /* lisp preliminaries */
189 buffer
= XWINDOW
(FRAME_SELECTED_WINDOW
(f
))->buffer
;
190 specbind
(Qinhibit_quit
, Qt
);
191 specbind
(Qdebug_on_next_call
, Qnil
);
192 record_unwind_save_match_data
();
193 if (NILP
(Voverriding_local_map_menu_flag
))
195 specbind
(Qoverriding_terminal_local_map
, Qnil
);
196 specbind
(Qoverriding_local_map
, Qnil
);
198 set_buffer_internal_1
(XBUFFER
(buffer
));
200 /* PENDING: for some reason this is not needed in other terms,
201 but some menu updates call Info-extract-pointer which causes
202 abort-on-error if waiting-for-input. Needs further investigation. */
203 owfi
= waiting_for_input
;
204 waiting_for_input
= 0;
206 /* lucid hook and possible reset */
207 safe_run_hooks
(Qactivate_menubar_hook
);
208 if (! NILP
(Vlucid_menu_bar_dirty_flag
))
209 call0
(Qrecompute_lucid_menubar
);
210 safe_run_hooks
(Qmenu_bar_update_hook
);
211 FRAME_MENU_BAR_ITEMS
(f
) = menu_bar_items
(FRAME_MENU_BAR_ITEMS
(f
));
213 /* Now ready to go */
214 items
= FRAME_MENU_BAR_ITEMS
(f
);
216 /* Save the frame's previous menu bar contents data */
217 if (previous_menu_items_used
)
218 bcopy
(XVECTOR
(f
->menu_bar_vector
)->contents
, previous_items
,
219 previous_menu_items_used
* sizeof
(Lisp_Object
));
221 /* parse stage 1: extract from lisp */
224 menu_items
= f
->menu_bar_vector
;
225 menu_items_allocated
= VECTORP
(menu_items
) ? ASIZE
(menu_items
) : 0;
226 submenu_start
= (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
*));
227 submenu_end
= (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
*));
228 submenu_n_panes
= (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
));
229 submenu_top_level_items
230 = (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
*));
232 for (i
= 0; i
< XVECTOR
(items
)->size; i
+= 4)
234 Lisp_Object key
, string
, maps
;
236 key
= XVECTOR
(items
)->contents
[i
];
237 string
= XVECTOR
(items
)->contents
[i
+ 1];
238 maps
= XVECTOR
(items
)->contents
[i
+ 2];
242 /* PENDING: we'd like to only parse the needed submenu, but this
243 was causing crashes in the _common parsing code.. need to make
244 sure proper initialization done.. */
245 /* if (submenu && strcmp (submenuTitle, SDATA (string)))
248 submenu_start
[i
] = menu_items_used
;
250 menu_items_n_panes
= 0;
251 submenu_top_level_items
[i
] = parse_single_submenu
(key
, string
, maps
);
252 submenu_n_panes
[i
] = menu_items_n_panes
;
253 submenu_end
[i
] = menu_items_used
;
257 finish_menu_items
();
258 waiting_for_input
= owfi
;
261 if (submenu
&& n
== 0)
263 /* should have found a menu for this one but didn't */
264 fprintf (stderr
, "
ERROR: did not
find lisp
menu for submenu
'%s'.
\n"
,
266 discard_menu_items
();
267 unbind_to
(specpdl_count
, Qnil
);
273 /* parse stage 2: insert into lucid 'widget_value' structures
274 [comments in other terms say not to evaluate lisp code here] */
275 wv
= xmalloc_widget_value
();
276 wv
->name
= "menubar"
;
279 wv
->button_type
= BUTTON_TYPE_NONE
;
283 for (i
= 0; i
< 4*n
; i
+= 4)
285 menu_items_n_panes
= submenu_n_panes
[i
];
286 wv
= digest_single_submenu
(submenu_start
[i
], submenu_end
[i
],
287 submenu_top_level_items
[i
]);
291 first_wv
->contents
= wv
;
292 /* Don't set wv->name here; GC during the loop might relocate it. */
294 wv
->button_type
= BUTTON_TYPE_NONE
;
298 set_buffer_internal_1
(prev
);
300 /* Compare the new menu items with previous, and leave off if no change */
301 /* PENDING: following other terms here, but seems like this should be
302 done before parse stage 2 above, since its results aren't used */
303 if (previous_menu_items_used
304 && (!submenu ||
(submenu
&& submenu
== last_submenu
))
305 && menu_items_used
== previous_menu_items_used
)
307 for (i
= 0; i
< previous_menu_items_used
; i
++)
308 /* PENDING: this ALWAYS fails on Buffers menu items.. something
309 about their strings causes them to change every time, so we
310 double-check failures */
311 if (!EQ
(previous_items
[i
], XVECTOR
(menu_items
)->contents
[i
]))
312 if (!(STRINGP
(previous_items
[i
])
313 && STRINGP
(XVECTOR
(menu_items
)->contents
[i
])
314 && !strcmp (SDATA
(previous_items
[i
]),
315 SDATA
(XVECTOR
(menu_items
)->contents
[i
]))))
317 if (i
== previous_menu_items_used
)
323 t
+= 1000*tb.time
+tb.millitm
;
324 fprintf (stderr
, "NO CHANGE
! CUTTING OUT after
%ld msec.\n", t);
327 free_menubar_widget_value_tree
(first_wv
);
328 discard_menu_items
();
329 unbind_to
(specpdl_count
, Qnil
);
335 /* The menu items are different, so store them in the frame */
336 /* PENDING: this is not correct for single-submenu case */
337 f
->menu_bar_vector
= menu_items
;
338 f
->menu_bar_items_used
= menu_items_used
;
340 /* Calls restore_menu_items, etc., as they were outside */
341 unbind_to
(specpdl_count
, Qnil
);
343 /* Parse stage 2a: now GC cannot happen during the lifetime of the
344 widget_value, so it's safe to store data from a Lisp_String */
345 wv
= first_wv
->contents
;
346 for (i
= 0; i
< XVECTOR
(items
)->size; i
+= 4)
349 string
= XVECTOR
(items
)->contents
[i
+ 1];
352 /* if (submenu && strcmp (submenuTitle, SDATA (string)))
355 wv
->name
= (char *) SDATA
(string
);
356 update_submenu_strings
(wv
->contents
);
360 /* Now, update the NS menu; if we have a submenu, use that, otherwise
361 create a new menu for each sub and fill it. */
364 for (wv
= first_wv
->contents
; wv
; wv
= wv
->next
)
366 if (!strcmp (submenuTitle
, wv
->name
))
368 [submenu fillWithWidgetValue
: wv
->contents
];
369 last_submenu
= submenu
;
376 [menu fillWithWidgetValue
: first_wv
->contents
];
382 static int n_previous_strings
= 0;
383 static
char previous_strings
[100][10];
384 static
struct frame
*last_f
= NULL;
388 /* Make widget-value tree w/ just the top level menu bar strings */
389 items
= FRAME_MENU_BAR_ITEMS
(f
);
398 /* check if no change.. this mechanism is a bit rough, but ready */
399 n
= XVECTOR
(items
)->size / 4;
400 if (f
== last_f
&& n_previous_strings
== n
)
402 for (i
= 0; i
<n
; i
++)
404 string
= XVECTOR
(items
)->contents
[4*i
+1];
409 if (previous_strings
[i
][0])
413 if (strncmp
(previous_strings
[i
], SDATA
(string
), 10))
426 for (i
= 0; i
< XVECTOR
(items
)->size; i
+= 4)
428 string
= XVECTOR
(items
)->contents
[i
+ 1];
433 strncpy
(previous_strings
[i
/4], SDATA
(string
), 10);
435 wv
= xmalloc_widget_value
();
436 wv
->name
= (char *) SDATA
(string
);
439 wv
->button_type
= BUTTON_TYPE_NONE
;
441 wv
->call_data
= (void
*) (EMACS_INT
) (-1);
444 /* we'll update the real copy under app menu when time comes */
445 if (!strcmp ("Services"
, wv
->name
))
447 /* but we need to make sure it will update on demand */
448 [svcsMenu setFrame
: f
];
449 [svcsMenu setDelegate
: svcsMenu
];
453 [menu addSubmenuWithTitle
: wv
->name forFrame
: f
];
458 first_wv
->contents
= wv
;
464 n_previous_strings
= n
;
466 n_previous_strings
= 0;
469 free_menubar_widget_value_tree
(first_wv
);
474 t
+= 1000*tb.time
+tb.millitm
;
475 fprintf (stderr
, "
Menu update took
%ld msec.\n", t);
480 [NSApp setMainMenu
: menu];
488 /* Main emacs core entry point for menubar menus: called to indicate that the
489 frame's menus have changed, and the *step representation should be updated
492 set_frame_menubar
(struct frame
*f
, int first_time
, int deep_p
)
494 ns_update_menubar
(f
, deep_p
, nil
);
498 /* Utility (from macmenu.c): is this item a separator? */
500 name_is_separator
(name
)
503 const
char *start
= name
;
505 /* Check if name string consists of only dashes ('-'). */
506 while (*name
== '-') name
++;
507 /* Separators can also be of the form "--:TripleSuperMegaEtched"
508 or "--deep-shadow". We don't implement them yet, se we just treat
509 them like normal separators. */
510 return (*name
== '\0' || start
+ 2 == name
);
514 /* ==========================================================================
516 Menu: class implementation
518 ========================================================================== */
521 /* Menu that can define itself from Emacs "widget_value"s and will lazily
522 update itself when user clicked. Based on Carbon/AppKit implementation
523 by Yamamoto Mitsuharu. */
524 @implementation EmacsMenu
526 /* override designated initializer */
527 - initWithTitle
: (NSString
*)title
529 if (self
= [super initWithTitle
: title])
530 [self setAutoenablesItems
: NO
];
535 /* used for top-level */
536 - initWithTitle
: (NSString
*)title frame
: (struct frame
*)f
538 [self initWithTitle
: title];
541 [self setDelegate
: self
];
547 - (void
)setFrame
: (struct frame
*)f
553 /* delegate method called when a submenu is being opened: run a 'deep' call
554 to set_frame_menubar */
555 - (void
)menuNeedsUpdate
: (NSMenu
*)menu
557 NSEvent
*event
= [[FRAME_NS_VIEW
(frame
) window
] currentEvent
];
558 /* HACK: Cocoa/Carbon will request update on every keystroke
559 via IsMenuKeyEvent -> CheckMenusForKeyEvent. These are not needed
560 since key equivalents are handled through emacs.
561 On Leopard, even keystroke events generate SystemDefined events, but
562 their subtype is 8. */
563 if ([event
type] != NSSystemDefined ||
[event subtype
] == 8)
565 /*fprintf (stderr, "Updating menu '%s'\n", [[self title] UTF8String]); NSLog (@"%@\n", event); */
566 ns_update_menubar
(frame
, 1, self
);
570 - (BOOL
)performKeyEquivalent
: (NSEvent
*)theEvent
572 if (SELECTED_FRAME
() && FRAME_NS_P
(SELECTED_FRAME
())
573 && FRAME_NS_VIEW
(SELECTED_FRAME
()))
574 [FRAME_NS_VIEW
(SELECTED_FRAME
()) keyDown
: theEvent
];
579 /* parse a wdiget_value's key rep (examples: 's-p', 's-S', '(C-x C-s)', '<f13>')
580 into an accelerator string */
581 -(NSString
*)parseKeyEquiv
: (char *)key
585 /* currently we just parse 'super' combinations;
586 later we'll set keyEquivModMask */
587 if (!key ||
!strlen
(key
))
590 while (*tpos
== ' ' ||
*tpos
== '(')
592 if (*tpos
!= 's'/* || tpos[3] != ')'*/)
594 return [NSString stringWithFormat
: @"
%c", tpos[2]];
597 - (id
<NSMenuItem
>)addItemWithWidgetValue
: (void
*)wvptr
599 id
<NSMenuItem
> item
;
600 widget_value
*wv
= (widget_value
*)wvptr
;
602 if (name_is_separator
(wv
->name
))
604 item
= [NSMenuItem separatorItem
];
605 [self addItem
: item
];
609 NSString
*title, *keyEq
;
610 title = [NSString stringWithUTF8String
: wv
->name
];
612 title = @"
< ?
>"
; /* (get out in the open so we know about it) */
614 keyEq
= [self parseKeyEquiv
: wv
->key
];
616 item
= [self addItemWithTitle
: (NSString
*)title
617 action
: @selector
(menuDown
:)
618 keyEquivalent
: keyEq
];
620 [item setKeyEquivalentModifierMask
: keyEquivModMask
];
622 [item setEnabled
: wv
->enabled
];
624 /* Draw radio buttons and tickboxes */
625 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE ||
626 wv
->button_type
== BUTTON_TYPE_RADIO
))
627 [item setState
: NSOnState
];
629 [item setState
: NSOffState
];
631 [item setTag
: (int
)wv
->call_data
];
643 for (n
= [self numberOfItems
]-1; n
>= 0; n
--)
645 NSMenuItem
*item
= [self itemAtIndex
: n
];
646 NSString
*title = [item
title];
647 if (([title length] == 0 ||
[@"Apple" isEqualToString
: title])
648 && ![item isSeparatorItem
])
650 [self removeItemAtIndex
: n
];
655 - (void
)fillWithWidgetValue
: (void
*)wvptr
657 widget_value
*wv
= (widget_value
*)wvptr
;
659 /* clear existing contents */
660 [self setMenuChangedMessagesEnabled
: NO
];
663 /* add new contents */
664 for (; wv
!= NULL; wv
= wv
->next
)
666 id
<NSMenuItem
> item
= [self addItemWithWidgetValue
: wv
];
670 EmacsMenu
*submenu
= [[EmacsMenu alloc
] initWithTitle
: @"Submenu"
];
672 [self setSubmenu
: submenu forItem
: item
];
673 [submenu fillWithWidgetValue
: wv
->contents
];
675 [item setAction
: nil
];
679 [self setMenuChangedMessagesEnabled
: YES
];
680 #ifdef NS_IMPL_GNUSTEP
681 if ([[self window
] isVisible
])
684 if ([self supermenu
] == nil
)
690 /* adds an empty submenu and returns it */
691 - (EmacsMenu
*)addSubmenuWithTitle
: (char *)title forFrame
: (struct frame
*)f
693 NSString
*titleStr
= [NSString stringWithUTF8String
: title];
694 id
<NSMenuItem
> item
=
695 [self addItemWithTitle
: titleStr
696 action
: nil
/*@selector (menuDown:) */
698 EmacsMenu
*submenu
= [[EmacsMenu alloc
] initWithTitle
: titleStr frame
: f
];
699 [self setSubmenu
: submenu forItem
: item
];
704 /* run a menu in popup mode */
705 - (Lisp_Object
)runMenuAt
: (NSPoint
)p forFrame
: (struct frame
*)f
706 keymaps
: (int
)keymaps
708 EmacsView
*view = FRAME_NS_VIEW
(f
);
709 /* p = [view convertPoint:p fromView: nil]; */
710 p.y
= NSHeight
([view frame
]) - p.y
;
711 NSEvent
*e
= [[view window
] currentEvent
];
712 NSEvent
*event
= [NSEvent mouseEventWithType
: NSRightMouseDown
715 timestamp
: [e timestamp
]
716 windowNumber
: [[view window
] windowNumber
]
718 eventNumber
: 0/*[e eventNumber] */
723 context_menu_value
= -1;
724 [NSMenu popUpContextMenu
: self withEvent
: event forView
: view];
725 retVal
= context_menu_value
;
726 context_menu_value
= 0;
728 find_and_return_menu_selection
(f
, keymaps
, (void
*)retVal
) : Qnil
;
735 /* ==========================================================================
737 Context Menu: implementing functions
739 ========================================================================== */
742 cleanup_popup_menu
(Lisp_Object arg
)
744 discard_menu_items
();
750 ns_popup_menu
(Lisp_Object position
, Lisp_Object
menu)
753 struct frame
*f
= NULL;
755 Lisp_Object window
, x
, y
, tem
, keymap
, title;
757 int specpdl_count
= SPECPDL_INDEX
(), specpdl_count2
;
758 char *error_name
= NULL;
760 widget_value
*wv
, *first_wv
= 0;
762 NSTRACE
(ns_popup_menu
);
764 if (!NILP
(position
))
768 if (EQ
(position
, Qt
)
769 ||
(CONSP
(position
) && (EQ
(XCAR
(position
), Qmenu_bar
)
770 || EQ
(XCAR
(position
), Qtool_bar
))))
772 /* Use the mouse's current position. */
773 struct frame
*new_f
= SELECTED_FRAME
();
775 if (FRAME_TERMINAL
(new_f
)->mouse_position_hook
)
776 (*FRAME_TERMINAL
(new_f
)->mouse_position_hook
)
777 (&new_f
, 0, 0, 0, &x
, &y
, 0);
779 XSETFRAME
(window
, new_f
);
782 window
= selected_window
;
789 CHECK_CONS
(position
);
790 tem
= Fcar
(position
);
791 if (XTYPE
(tem
) == Lisp_Cons
)
793 window
= Fcar
(Fcdr
(position
));
795 y
= Fcar
(Fcdr
(tem
));
799 tem
= Fcar
(Fcdr
(position
));
801 tem
= Fcar
(Fcdr
(Fcdr
(tem
)));
819 struct window
*win
= XWINDOW
(window
);
820 CHECK_LIVE_WINDOW
(window
);
821 f
= XFRAME
(WINDOW_FRAME
(win
));
822 p.x
= FRAME_COLUMN_WIDTH
(f
) * WINDOW_LEFT_EDGE_COL
(win
);
823 p.y
= FRAME_LINE_HEIGHT
(f
) * WINDOW_TOP_EDGE_LINE
(win
);
826 p.x
+= XINT
(x
); p.y
+= XINT
(y
);
828 XSETFRAME
(Vmenu_updating_frame
, f
);
831 { /* no position given */
832 /* PENDING: if called during dump, we need to stop precomputation of
833 key equivalents (see below) because the keydefs in ns-win.el have
834 not been loaded yet. */
837 Vmenu_updating_frame
= Qnil
;
840 /* now parse the lisp menus */
841 record_unwind_protect
(unuse_menu_items
, Qnil
);
845 /* Decode the menu items from what was specified. */
847 keymap
= get_keymap
(menu, 0, 0);
850 /* We were given a keymap. Extract menu info from the keymap. */
853 /* Extract the detailed info to make one pane. */
854 keymap_panes
(&menu, 1, NILP
(position
));
856 /* Search for a string appearing directly as an element of the keymap.
857 That string is the title of the menu. */
858 prompt
= Fkeymap_prompt
(keymap
);
859 title = NILP
(prompt
) ? build_string
("Select"
) : prompt
;
861 /* Make that be the pane title of the first pane. */
862 if (!NILP
(prompt
) && menu_items_n_panes
>= 0)
863 XVECTOR
(menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = prompt
;
867 else if (CONSP
(menu) && KEYMAPP
(XCAR
(menu)))
869 /* We were given a list of keymaps. */
870 int nmaps
= XFASTINT
(Flength
(menu));
872 = (Lisp_Object
*) alloca
(nmaps
* sizeof
(Lisp_Object
));
877 /* The first keymap that has a prompt string
878 supplies the menu title. */
879 for (tem
= menu, i
= 0; CONSP
(tem
); tem
= XCDR
(tem
))
883 maps
[i
++] = keymap
= get_keymap
(XCAR
(tem
), 1, 0);
885 prompt
= Fkeymap_prompt
(keymap
);
886 if (NILP
(title) && !NILP
(prompt
))
890 /* Extract the detailed info to make one pane. */
891 keymap_panes
(maps
, nmaps
, NILP
(position
));
893 /* Make the title be the pane title of the first pane. */
894 if (!NILP
(title) && menu_items_n_panes
>= 0)
895 XVECTOR
(menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = title;
901 /* We were given an old-fashioned menu. */
903 CHECK_STRING
(title);
905 list_of_panes
(Fcdr
(menu));
910 unbind_to
(specpdl_count
, Qnil
);
912 /* If no position given, that was a signal to just precompute and cache
913 key equivalents, which was a side-effect of what we just did. */
916 discard_menu_items
();
921 record_unwind_protect
(cleanup_popup_menu
, Qnil
);
924 /* now parse stage 2 as in ns_update_menubar */
925 wv
= xmalloc_widget_value
();
926 wv
->name
= "contextmenu"
;
929 wv
->button_type
= BUTTON_TYPE_NONE
;
933 specpdl_count2
= SPECPDL_INDEX
();
936 /*PENDING: a couple of one-line differences prevent reuse */
937 wv
= digest_single_submenu
(0, menu_items_used
, Qnil
);
940 widget_value
*save_wv
= 0, *prev_wv
= 0;
941 widget_value
**submenu_stack
942 = (widget_value
**) alloca
(menu_items_used
* sizeof
(widget_value
*));
943 /* Lisp_Object *subprefix_stack
944 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); */
945 int submenu_depth
= 0;
949 /* Loop over all panes and items, filling in the tree. */
951 while (i
< menu_items_used
)
953 if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qnil
))
955 submenu_stack
[submenu_depth
++] = save_wv
;
961 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qlambda
))
964 save_wv
= submenu_stack
[--submenu_depth
];
968 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qt
)
969 && submenu_depth
!= 0)
970 i
+= MENU_ITEMS_PANE_LENGTH
;
971 /* Ignore a nil in the item list.
972 It's meaningful only for dialog boxes. */
973 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qquote
))
975 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qt
))
977 /* Create a new pane. */
978 Lisp_Object pane_name
, prefix
;
981 pane_name
= AREF
(menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
982 prefix
= AREF
(menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
984 #ifndef HAVE_MULTILINGUAL_MENU
985 if (STRINGP
(pane_name
) && STRING_MULTIBYTE
(pane_name
))
987 pane_name
= ENCODE_MENU_STRING
(pane_name
);
988 ASET
(menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
991 pane_string
= (NILP
(pane_name
)
992 ? ""
: (char *) SDATA
(pane_name
));
993 /* If there is just one top-level pane, put all its items directly
994 under the top-level menu. */
995 if (menu_items_n_panes
== 1)
998 /* If the pane has a meaningful name,
999 make the pane a top-level menu item
1000 with its items as a submenu beneath it. */
1001 if (!keymaps
&& strcmp (pane_string
, ""
))
1003 wv
= xmalloc_widget_value
();
1007 first_wv
->contents
= wv
;
1008 wv
->name
= pane_string
;
1009 if (keymaps
&& !NILP
(prefix
))
1013 wv
->button_type
= BUTTON_TYPE_NONE
;
1018 else if (first_pane
)
1024 i
+= MENU_ITEMS_PANE_LENGTH
;
1028 /* Create a new item within current pane. */
1029 Lisp_Object item_name
, enable
, descrip
, def
, type, selected
, help;
1030 item_name
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1031 enable
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1032 descrip
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1033 def
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1034 type = AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1035 selected
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1036 help = AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1038 #ifndef HAVE_MULTILINGUAL_MENU
1039 if (STRINGP
(item_name
) && STRING_MULTIBYTE
(item_name
))
1041 item_name
= ENCODE_MENU_STRING
(item_name
);
1042 ASET
(menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1045 if (STRINGP
(descrip
) && STRING_MULTIBYTE
(descrip
))
1047 descrip
= ENCODE_MENU_STRING
(descrip
);
1048 ASET
(menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1050 #endif
/* not HAVE_MULTILINGUAL_MENU */
1052 wv
= xmalloc_widget_value
();
1056 save_wv
->contents
= wv
;
1057 wv
->name
= (char *) SDATA
(item_name
);
1058 if (!NILP
(descrip
))
1059 wv
->key
= (char *) SDATA
(descrip
);
1061 /* If this item has a null value,
1062 make the call_data null so that it won't display a box
1063 when the mouse is on it. */
1065 !NILP
(def
) ?
(void
*) &XVECTOR
(menu_items
)->contents
[i
] : 0;
1066 wv
->enabled
= !NILP
(enable
);
1069 wv
->button_type
= BUTTON_TYPE_NONE
;
1070 else if (EQ
(type, QCtoggle
))
1071 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1072 else if (EQ
(type, QCradio
))
1073 wv
->button_type
= BUTTON_TYPE_RADIO
;
1077 wv
->selected
= !NILP
(selected
);
1079 if (! STRINGP
(help))
1086 i
+= MENU_ITEMS_ITEM_LENGTH
;
1094 widget_value
*wv_title
= xmalloc_widget_value
();
1095 widget_value
*wv_sep
= xmalloc_widget_value
();
1097 /* Maybe replace this separator with a bitmap or owner-draw item
1098 so that it looks better. Having two separators looks odd. */
1099 wv_sep
->name
= "
--"
;
1100 wv_sep
->next
= first_wv
->contents
;
1101 wv_sep
->help = Qnil
;
1103 #ifndef HAVE_MULTILINGUAL_MENU
1104 if (STRING_MULTIBYTE
(title))
1105 title = ENCODE_MENU_STRING
(title);
1108 wv_title
->name
= (char *) SDATA
(title);
1109 wv_title
->enabled
= NULL;
1110 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1111 wv_title
->help = Qnil
;
1112 wv_title
->next
= wv_sep
;
1113 first_wv
->contents
= wv_title
;
1116 pmenu
= [[EmacsMenu alloc
] initWithTitle
:
1117 [NSString stringWithUTF8String
: SDATA
(title)]];
1118 [pmenu fillWithWidgetValue
: first_wv
->contents
];
1119 free_menubar_widget_value_tree
(first_wv
);
1120 unbind_to
(specpdl_count2
, Qnil
);
1122 tem
= [pmenu runMenuAt
: p forFrame
: f keymaps
: keymaps
];
1123 [[FRAME_NS_VIEW
(SELECTED_FRAME
()) window
] makeKeyWindow
];
1126 unbind_to
(specpdl_count
, Qnil
);
1129 if (error_name
) error (error_name
);
1136 /* ==========================================================================
1138 Toolbar: externally-called functions
1140 ========================================================================== */
1143 free_frame_tool_bar
(FRAME_PTR f
)
1144 /* --------------------------------------------------------------------------
1145 Under NS we just hide the toolbar until it might be needed again.
1146 -------------------------------------------------------------------------- */
1148 [[FRAME_NS_VIEW
(f
) toolbar
] setVisible
: NO
];
1152 update_frame_tool_bar
(FRAME_PTR f
)
1153 /* --------------------------------------------------------------------------
1154 Update toolbar contents
1155 -------------------------------------------------------------------------- */
1158 EmacsToolbar
*toolbar
= [FRAME_NS_VIEW
(f
) toolbar
];
1160 if (NILP
(f
->tool_bar_lines
) ||
!INTEGERP
(f
->tool_bar_lines
))
1163 [toolbar clearActive
];
1165 /* update EmacsToolbar as in GtkUtils, build items list */
1166 for (i
= 0; i
< f
->n_tool_bar_items
; ++i
)
1168 #define TOOLPROP
(IDX
) AREF
(f
->tool_bar_items
, \
1169 i
* TOOL_BAR_ITEM_NSLOTS
+ (IDX
))
1171 BOOL enabled_p
= !NILP
(TOOLPROP
(TOOL_BAR_ITEM_ENABLED_P
));
1172 BOOL selected_p
= !NILP
(TOOLPROP
(TOOL_BAR_ITEM_SELECTED_P
));
1177 Lisp_Object helpObj
;
1180 /* If image is a vector, choose the image according to the
1182 image = TOOLPROP
(TOOL_BAR_ITEM_IMAGES
);
1183 if (VECTORP
(image))
1185 /* NS toolbar auto-computes disabled and selected images */
1186 idx
= TOOL_BAR_IMAGE_ENABLED_SELECTED
;
1187 xassert
(ASIZE
(image) >= idx
);
1188 image = AREF
(image, idx
);
1194 /* Ignore invalid image specifications. */
1195 if (!valid_image_p
(image))
1197 NSLog
(@"Invalid
image for toolbar item"
);
1201 img_id
= lookup_image
(f
, image);
1202 img
= IMAGE_FROM_ID
(f
, img_id
);
1203 prepare_image_for_display
(f
, img
);
1205 if (img
->load_failed_p || img
->pixmap
== nil
)
1207 NSLog
(@"Could not prepare toolbar
image for display."
);
1211 helpObj
= TOOLPROP
(TOOL_BAR_ITEM_HELP
);
1213 helpObj
= TOOLPROP
(TOOL_BAR_ITEM_CAPTION
);
1214 helpText
= NILP
(helpObj
) ? ""
: (char *)SDATA
(helpObj
);
1216 [toolbar addDisplayItemWithImage
: img
->pixmap idx
: i helpText
: helpText
1217 enabled
: enabled_p
];
1221 if (![toolbar isVisible
])
1222 [toolbar setVisible
: YES
];
1224 if ([toolbar changed
])
1226 /* inform app that toolbar has changed */
1227 NSDictionary
*dict
= [toolbar configurationDictionary
];
1228 NSMutableDictionary
*newDict
= [dict mutableCopy
];
1229 NSEnumerator
*keys
= [[dict allKeys
] objectEnumerator
];
1231 while ((key
= [keys nextObject
]) != nil
)
1233 NSObject
*val
= [dict objectForKey
: key
];
1234 if ([val isKindOfClass
: [NSArray
class]])
1237 [toolbar toolbarDefaultItemIdentifiers
: toolbar
]
1242 [toolbar setConfigurationFromDictionary
: newDict
];
1249 /* ==========================================================================
1251 Toolbar: class implementation
1253 ========================================================================== */
1255 @implementation EmacsToolbar
1257 - initForView
: (EmacsView
*)view withIdentifier
: (NSString
*)identifier
1259 self
= [super initWithIdentifier
: identifier
];
1261 [self setDisplayMode
: NSToolbarDisplayModeIconOnly
];
1262 [self setSizeMode
: NSToolbarSizeModeSmall
];
1263 [self setDelegate
: self
];
1264 identifierToItem
= [[NSMutableDictionary alloc
] initWithCapacity
: 10];
1265 activeIdentifiers
= [[NSMutableArray alloc
] initWithCapacity
: 8];
1266 prevEnablement
= enablement
= 0L;
1272 [prevIdentifiers release
];
1273 [activeIdentifiers release
];
1274 [identifierToItem release
];
1278 - (void
) clearActive
1280 [prevIdentifiers release
];
1281 prevIdentifiers
= [activeIdentifiers copy
];
1282 [activeIdentifiers removeAllObjects
];
1283 prevEnablement
= enablement
;
1289 return [activeIdentifiers isEqualToArray
: prevIdentifiers
] &&
1290 enablement
== prevEnablement ? NO
: YES
;
1293 - (void
) addDisplayItemWithImage
: (EmacsImage
*)img idx
: (int
)idx
1294 helpText
: (char *)help enabled
: (BOOL
)enabled
1296 /* 1) come up w/identifier */
1297 NSString
*identifier
=
1298 [NSString stringWithFormat
: @"
%u", [img hash]];
1300 /* 2) create / reuse item */
1301 NSToolbarItem
*item
= [identifierToItem objectForKey
: identifier
];
1304 item
= [[[NSToolbarItem alloc
] initWithItemIdentifier
: identifier
]
1306 [item setImage
: img
];
1307 [item setToolTip
: [NSString stringWithCString
: help]];
1308 [item setTarget
: emacsView
];
1309 [item setAction
: @selector
(toolbarClicked
:)];
1313 [item setEnabled
: enabled
];
1315 /* 3) update state */
1316 [identifierToItem setObject
: item forKey
: identifier
];
1317 [activeIdentifiers addObject
: identifier
];
1318 enablement
= (enablement
<< 1) |
(enabled
== YES
);
1321 /* This overrides super's implementation, which automatically sets
1322 all items to enabled state (for some reason). */
1323 - (void
)validateVisibleItems
{ }
1326 /* delegate methods */
1328 - (NSToolbarItem
*)toolbar
: (NSToolbar
*)toolbar
1329 itemForItemIdentifier
: (NSString
*)itemIdentifier
1330 willBeInsertedIntoToolbar
: (BOOL
)flag
1332 /* look up NSToolbarItem by identifier and return... */
1333 return [identifierToItem objectForKey
: itemIdentifier
];
1336 - (NSArray
*)toolbarDefaultItemIdentifiers
: (NSToolbar
*)toolbar
1338 /* return entire set.. */
1339 return activeIdentifiers
;
1342 /* for configuration palette (not yet supported) */
1343 - (NSArray
*)toolbarAllowedItemIdentifiers
: (NSToolbar
*)toolbar
1345 /* return entire set... */
1346 return [identifierToItem allKeys
];
1349 /* optional and unneeded */
1350 /* - toolbarWillAddItem: (NSNotification *)notification { } */
1351 /* - toolbarDidRemoveItem: (NSNotification *)notification { } */
1352 /* - (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar */
1354 @
end /* EmacsToolbar */
1358 /* ==========================================================================
1360 Tooltip: class implementation
1362 ========================================================================== */
1364 /* Needed because NeXTstep does not provide enough control over tooltip
1366 @implementation EmacsTooltip
1370 NSColor
*col
= [NSColor colorWithCalibratedRed
: 1.0 green
: 1.0
1371 blue
: 0.792 alpha
: 0.95];
1372 NSFont
*font
= [NSFont toolTipsFontOfSize
: 0];
1373 NSFont
*sfont
= [font screenFont
];
1374 int height
= [sfont ascender
] - [sfont descender
];
1375 /*[font boundingRectForFont].size.height; */
1376 NSRect r
= NSMakeRect
(0, 0, 100, height
+6);
1378 textField
= [[NSTextField alloc
] initWithFrame
: r
];
1379 [textField setFont
: font
];
1380 [textField setBackgroundColor
: col
];
1382 [textField setEditable
: NO
];
1383 [textField setSelectable
: NO
];
1384 [textField setBordered
: YES
];
1385 [textField setBezeled
: YES
];
1386 [textField setDrawsBackground
: YES
];
1388 win
= [[NSWindow alloc
]
1389 initWithContentRect
: [textField frame
]
1391 backing
: NSBackingStoreBuffered
1393 [win setReleasedWhenClosed
: NO
];
1394 [win setDelegate
: self
];
1395 [[win contentView
] addSubview
: textField
];
1396 /* [win setBackgroundColor: col]; */
1397 [win setOpaque
: NO
];
1406 [textField release
];
1410 - (void
) setText
: (char *)text
1412 NSString
*str
= [NSString stringWithUTF8String
: text];
1413 NSRect r
= [textField frame
];
1414 r.
size.width
= [[[textField font
] screenFont
] widthOfString
: str
] + 8;
1415 [textField setFrame
: r
];
1416 [textField setStringValue
: str
];
1419 - (void
) showAtX
: (int
)x Y
: (int
)y
for: (int
)seconds
1421 NSRect wr
= [win frame
];
1423 wr.origin
= NSMakePoint
(x
, y
);
1424 wr.
size = [textField frame
].
size;
1426 [win setFrame
: wr display
: YES
];
1427 [win orderFront
: self
];
1429 timer
= [NSTimer scheduledTimerWithTimeInterval
: (float
)seconds target
: self
1430 selector
: @selector
(hide
)
1431 userInfo
: nil repeats
: NO
];
1440 if ([timer isValid
])
1449 return timer
!= nil
;
1454 return [textField frame
];
1457 @
end /* EmacsTooltip */
1461 /* ==========================================================================
1463 Popup Dialog: implementing functions
1465 ========================================================================== */
1468 ns_popup_dialog
(Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
1471 Lisp_Object window
, tem
;
1476 NSTRACE
(x
-popup
-dialog);
1480 isQ
= NILP
(header
);
1482 if (EQ
(position
, Qt
))
1484 window
= selected_window
;
1486 else if (CONSP
(position
))
1489 tem
= Fcar
(position
);
1490 if (XTYPE
(tem
) == Lisp_Cons
)
1491 window
= Fcar
(Fcdr
(position
));
1494 tem
= Fcar
(Fcdr
(position
)); /* EVENT_START (position) */
1495 window
= Fcar
(tem
); /* POSN_WINDOW (tem) */
1498 else if (FRAMEP
(position
))
1504 CHECK_LIVE_WINDOW
(position
);
1508 if (FRAMEP
(window
))
1509 f
= XFRAME
(window
);
1512 CHECK_LIVE_WINDOW
(window
);
1513 f
= XFRAME
(WINDOW_FRAME
(XWINDOW
(window
)));
1515 p.x
= (int
)f
->left_pos
+ ((int
)FRAME_COLUMN_WIDTH
(f
) * f
->text_cols
)/2;
1516 p.y
= (int
)f
->top_pos
+ (FRAME_LINE_HEIGHT
(f
) * f
->text_lines
)/2;
1517 dialog = [[EmacsDialogPanel alloc
] initFromContents
: contents
1520 tem
= [dialog runDialogAt
: p
];
1524 [[FRAME_NS_VIEW
(SELECTED_FRAME
()) window
] makeKeyWindow
];
1529 /* ==========================================================================
1531 Popup Dialog: class implementation
1533 ========================================================================== */
1535 @interface FlippedView
: NSView
1540 @implementation FlippedView
1547 @implementation EmacsDialogPanel
1550 #define ICONSIZE
64.0
1551 #define TEXTHEIGHT
20.0
1552 #define MINCELLWIDTH
90.0
1554 - initWithContentRect
: (NSRect
)contentRect styleMask
: (unsigned int
)aStyle
1555 backing
: (NSBackingStoreType
)backingType defer
: (BOOL
)flag
1557 NSSize spacing
= {SPACER
, SPACER
};
1559 char this_cmd_name
[80];
1561 static NSImageView
*imgView
;
1562 static FlippedView
*contentView
;
1567 area.origin.x
= 3*SPACER
;
1568 area.origin.y
= 2*SPACER
;
1569 area.
size.width
= ICONSIZE
;
1570 area.
size.height
= ICONSIZE
;
1571 img
= [[NSImage imageNamed
: @"NSApplicationIcon"
] copy
];
1572 [img setScalesWhenResized
: YES
];
1573 [img setSize
: NSMakeSize
(ICONSIZE
, ICONSIZE
)];
1574 imgView
= [[NSImageView alloc
] initWithFrame
: area
];
1575 [imgView setImage
: img
];
1576 [imgView setEditable
: NO
];
1580 aStyle
= NSTitledWindowMask
;
1584 [super initWithContentRect
: contentRect styleMask
: aStyle
1585 backing
: backingType defer
: flag];
1586 contentView
= [[FlippedView alloc
] initWithFrame
: [[self contentView
] frame
]];
1587 [self setContentView
: contentView
];
1589 [[self contentView
] setAutoresizesSubviews
: YES
];
1591 [[self contentView
] addSubview
: imgView
];
1592 [self setTitle
: @""
];
1594 area.origin.x
+= ICONSIZE
+2*SPACER
;
1595 /* area.origin.y = TEXTHEIGHT; ICONSIZE/2-10+SPACER; */
1596 area.
size.width
= 400;
1597 area.
size.height
= TEXTHEIGHT
;
1598 command
= [[[NSTextField alloc
] initWithFrame
: area
] autorelease
];
1599 [[self contentView
] addSubview
: command
];
1600 [command setStringValue
: @"Emacs"
];
1601 [command setDrawsBackground
: NO
];
1602 [command setBezeled
: NO
];
1603 [command setSelectable
: NO
];
1604 [command setFont
: [NSFont boldSystemFontOfSize
: 13.0]];
1606 /* area.origin.x = ICONSIZE+2*SPACER;
1607 area.origin.y = TEXTHEIGHT + 2*SPACER;
1608 area.size.width = 400;
1609 area.size.height= 2;
1610 tem = [[[NSBox alloc] initWithFrame: area] autorelease];
1611 [[self contentView] addSubview: tem];
1612 [tem setTitlePosition: NSNoTitle];
1613 [tem setAutoresizingMask: NSViewWidthSizable];*/
1615 /* area.origin.x = ICONSIZE+2*SPACER; */
1616 area.origin.y
+= TEXTHEIGHT
+SPACER
;
1617 area.
size.width
= 400;
1618 area.
size.height
= TEXTHEIGHT
;
1619 title = [[[NSTextField alloc
] initWithFrame
: area
] autorelease
];
1620 [[self contentView
] addSubview
: title];
1621 [title setDrawsBackground
: NO
];
1622 [title setBezeled
: NO
];
1623 [title setSelectable
: NO
];
1624 [title setFont
: [NSFont systemFontOfSize
: 11.0]];
1626 cell = [[[NSButtonCell alloc
] initTextCell
: @""
] autorelease
];
1627 [cell setBordered
: NO
];
1628 [cell setEnabled
: NO
];
1629 [cell setCellAttribute
: NSCellIsInsetButton to
: 8];
1630 [cell setBezelStyle
: NSRoundedBezelStyle
];
1632 matrix
= [[NSMatrix alloc
] initWithFrame
: contentRect
1633 mode
: NSHighlightModeMatrix
1636 numberOfColumns
: 1];
1637 [[self contentView
] addSubview
: matrix
];
1639 [matrix setFrameOrigin
: NSMakePoint
(area.origin.x
,
1640 area.origin.y
+ (TEXTHEIGHT
+3*SPACER
))];
1641 [matrix setIntercellSpacing
: spacing
];
1643 [self setOneShot
: YES
];
1644 [self setReleasedWhenClosed
: YES
];
1645 [self setHidesOnDeactivate
: YES
];
1650 - (BOOL
)windowShouldClose
: (id
)sender
1652 [NSApp stopModalWithCode
: Qnil
];
1657 void process_dialog
(id window
, Lisp_Object list
)
1662 for (; XTYPE
(list
) == Lisp_Cons
; list
= XCDR
(list
))
1665 if (XTYPE
(item
) == Lisp_String
)
1667 [window addString
: XSTRING
(item
)->data row
: row
++];
1669 else if (XTYPE
(item
) == Lisp_Cons
)
1671 [window addButton
: XSTRING
(XCAR
(item
))->data
1672 value
: XCDR
(item
) row
: row
++];
1674 else if (NILP
(item
))
1683 - addButton
: (char *)str value
: (Lisp_Object
)val row
: (int
)row
1692 cell = [matrix cellAtRow
: row column
: cols
-1];
1693 [cell setTarget
: self
];
1694 [cell setAction
: @selector
(clicked
: )];
1695 [cell setTitle
: [NSString stringWithUTF8String
: str
]];
1696 [cell setTag
: (int
)val
];
1697 [cell setBordered
: YES
];
1698 [cell setEnabled
: YES
];
1704 - addString
: (char *)str row
: (int
)row
1713 cell = [matrix cellAtRow
: row column
: cols
-1];
1714 [cell setTitle
: [NSString stringWithUTF8String
: str
]];
1715 [cell setBordered
: YES
];
1716 [cell setEnabled
: NO
];
1732 NSArray
*sellist
= nil
;
1735 sellist
= [sender selectedCells
];
1736 if ([sellist count
]<1)
1739 seltag
= (Lisp_Object
)[[sellist objectAtIndex
: 0] tag
];
1740 if (! EQ
(seltag
, Qundefined
))
1741 [NSApp stopModalWithCode
: seltag
];
1746 - initFromContents
: (Lisp_Object
)contents isQuestion
: (BOOL
)isQ
1751 if (XTYPE
(contents
) == Lisp_Cons
)
1753 head
= Fcar
(contents
);
1754 process_dialog
(self
, Fcdr
(contents
));
1759 if (XTYPE
(head
) == Lisp_String
)
1760 [title setStringValue
:
1761 [NSString stringWithUTF8String
: XSTRING
(head
)->data
]];
1762 else if (isQ
== YES
)
1763 [title setStringValue
: @"Question"
];
1765 [title setStringValue
: @"Information"
];
1771 if (cols
== 1 && rows
> 1) /* Never told where to split */
1774 for (i
= 0; i
<rows
/2; i
++)
1776 [matrix putCell
: [matrix cellAtRow
: (rows
+1)/2 column
: 0]
1777 atRow
: i column
: 1];
1778 [matrix removeRow
: (rows
+1)/2];
1784 NSSize csize
= [matrix cellSize
];
1785 if (csize.width
< MINCELLWIDTH
)
1787 csize.width
= MINCELLWIDTH
;
1788 [matrix setCellSize
: csize
];
1789 [matrix sizeToCells
];
1794 [command sizeToFit
];
1798 if (r.
size.width
+r.origin.x
> t.
size.width
+t.origin.x
)
1800 t.origin.x
= r.origin.x
;
1801 t.
size.width
= r.
size.width
;
1803 r
= [command frame
];
1804 if (r.
size.width
+r.origin.x
> t.
size.width
+t.origin.x
)
1806 t.origin.x
= r.origin.x
;
1807 t.
size.width
= r.
size.width
;
1811 s
= [(NSView
*)[self contentView
] frame
];
1812 r.
size.width
+= t.origin.x
+t.
size.width
+2*SPACER
-s.
size.width
;
1813 r.
size.height
+= t.origin.y
+t.
size.height
+SPACER
-s.
size.height
;
1814 [self setFrame
: r display
: NO
];
1823 { [super dealloc
]; return; };
1827 - (Lisp_Object
)runDialogAt
: (NSPoint
)p
1830 NSModalSession session
;
1833 [self center
]; /*XXX p ignored? */
1834 [self orderFront
: NSApp
];
1836 session
= [NSApp beginModalSessionForWindow
: self
];
1837 while ((ret
= [NSApp runModalSession
: session
]) == NSRunContinuesResponse
)
1839 (e
= [NSApp nextEventMatchingMask
: NSAnyEventMask
1840 untilDate
: [NSDate distantFuture
]
1841 inMode
: NSEventTrackingRunLoopMode
1843 /*fprintf (stderr, "ret = %d\te = %p\n", ret, e); */
1845 [NSApp endModalSession
: session
];
1847 return (Lisp_Object
)ret
;
1854 /* ==========================================================================
1858 ========================================================================== */
1860 DEFUN
("ns
-reset-menu"
, Fns_reset_menu
, Sns_reset_menu
, 0, 0, 0,
1861 "Cause the NS
menu to be re
-calculated."
)
1864 set_frame_menubar
(SELECTED_FRAME
(), 1, 0);
1869 DEFUN
("x
-popup
-menu"
, Fx_popup_menu
, Sx_popup_menu
, 2, 2, 0,
1870 "Pop up a deck
-of
-cards
menu and
return user
's selection.\n\
1871 POSITION is a position specification. This is either a mouse button event\n\
1872 or a list ((XOFFSET YOFFSET) WINDOW)\n\
1873 where XOFFSET and YOFFSET are positions in pixels from the top left\n\
1874 corner of WINDOW's frame.
(WINDOW may be a frame object instead of a window.
)\n\
1875 This controls the position of the center of the first
line\n\
1876 in the first pane of the
menu, not the top left of the
menu as a whole.
\n\
1878 MENU is a specifier
for a
menu.
For the simplest
case, MENU is a keymap.
\n\
1879 The
menu items come from key bindings that have a
menu string as well as
\n\
1880 a definition
; actually
, the
\"definition
\" in such a key binding looks like
\n\
1881 \
(STRING .
REAL-DEFINITION
). To give the
menu a
title, put a string into
\n\
1882 the keymap as a top
-level element.
\n\n\
1883 You can also use a list of keymaps as
MENU.
\n\
1884 Then each keymap makes a separate pane.
\n\
1885 When
MENU is a keymap or a list of keymaps
, the
return value
\n\
1886 is a list of events.
\n\n\
1887 Alternatively
, you can specify a
menu of multiple panes
\n\
1888 with a list of the form
(TITLE PANE1 PANE2...
),\n\
1889 where each pane is a list of form
(TITLE ITEM1 ITEM2...
).
\n\
1890 Each ITEM is normally a cons
cell (STRING . VALUE
);\n\
1891 but a string can appear as an item
--that makes a nonselectable
line\n\
1893 With this form of
menu, the
return value is VALUE from the chosen item."
)
1895 Lisp_Object position
, menu;
1897 return ns_popup_menu
(position
, menu);
1901 DEFUN
("x
-popup
-dialog"
, Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
1902 doc: /* Pop up a dialog box and return user's selection.
1903 POSITION specifies which frame to use.
1904 This is normally a mouse button event or a window or frame.
1905 If POSITION is t, it means to use the frame the mouse is on.
1906 The dialog box appears in the middle of the specified frame.
1908 CONTENTS specifies the alternatives to display in the dialog box.
1909 It is a list of the form (DIALOG ITEM1 ITEM2...).
1910 Each ITEM is a cons cell (STRING . VALUE).
1911 The return value is VALUE from the chosen item.
1913 An ITEM may also be just a string--that makes a nonselectable item.
1914 An ITEM may also be nil--that means to put all preceding items
1915 on the left of the dialog box and all following items on the right.
1916 \(By default, approximately half appear on each side.)
1918 If HEADER is non-nil, the frame title for the box is "Information",
1919 otherwise it is "Question".
1921 If the user gets rid of the dialog box without making a valid choice,
1922 for instance using the window manager, then this produces a quit and
1923 `x-popup-dialog' does not return. */)
1924 (position
, contents
, header
)
1925 Lisp_Object position
, contents
, header
;
1927 return ns_popup_dialog
(position
, contents
, header
);
1931 /* ==========================================================================
1933 Lisp interface declaration
1935 ========================================================================== */
1940 defsubr
(&Sx_popup_menu
);
1941 defsubr
(&Sx_popup_dialog
);
1942 defsubr
(&Sns_reset_menu
);
1943 staticpro
(&menu_items
);
1946 Qdebug_on_next_call
= intern
("
debug-on
-next
-call"
);
1947 staticpro
(&Qdebug_on_next_call
);
1950 // arch
-tag
: 75773656-52e5
-4c44
-a398
-47bd87b32619