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 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. */
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
= AREF
(items
, 4*i
+1);
406 if (EQ
(string
, make_number
(0))) // FIXME
: Why???
--Stef
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];
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
)
736 /* ==========================================================================
738 Context Menu: implementing functions
740 ========================================================================== */
743 cleanup_popup_menu
(Lisp_Object arg
)
745 discard_menu_items
();
751 ns_popup_menu
(Lisp_Object position
, Lisp_Object
menu)
754 struct frame
*f
= NULL;
756 Lisp_Object window
, x
, y
, tem
, keymap
, title;
758 int specpdl_count
= SPECPDL_INDEX
(), specpdl_count2
;
759 char *error_name
= NULL;
761 widget_value
*wv
, *first_wv
= 0;
763 NSTRACE
(ns_popup_menu
);
765 if (!NILP
(position
))
769 if (EQ
(position
, Qt
)
770 ||
(CONSP
(position
) && (EQ
(XCAR
(position
), Qmenu_bar
)
771 || EQ
(XCAR
(position
), Qtool_bar
))))
773 /* Use the mouse's current position. */
774 struct frame
*new_f
= SELECTED_FRAME
();
776 if (FRAME_TERMINAL
(new_f
)->mouse_position_hook
)
777 (*FRAME_TERMINAL
(new_f
)->mouse_position_hook
)
778 (&new_f
, 0, 0, 0, &x
, &y
, 0);
780 XSETFRAME
(window
, new_f
);
783 window
= selected_window
;
790 CHECK_CONS
(position
);
791 tem
= Fcar
(position
);
792 if (XTYPE
(tem
) == Lisp_Cons
)
794 window
= Fcar
(Fcdr
(position
));
796 y
= Fcar
(Fcdr
(tem
));
800 tem
= Fcar
(Fcdr
(position
));
802 tem
= Fcar
(Fcdr
(Fcdr
(tem
)));
820 struct window
*win
= XWINDOW
(window
);
821 CHECK_LIVE_WINDOW
(window
);
822 f
= XFRAME
(WINDOW_FRAME
(win
));
823 p.x
= FRAME_COLUMN_WIDTH
(f
) * WINDOW_LEFT_EDGE_COL
(win
);
824 p.y
= FRAME_LINE_HEIGHT
(f
) * WINDOW_TOP_EDGE_LINE
(win
);
827 p.x
+= XINT
(x
); p.y
+= XINT
(y
);
829 XSETFRAME
(Vmenu_updating_frame
, f
);
832 { /* no position given */
833 /* PENDING: if called during dump, we need to stop precomputation of
834 key equivalents (see below) because the keydefs in ns-win.el have
835 not been loaded yet. */
838 Vmenu_updating_frame
= Qnil
;
841 /* now parse the lisp menus */
842 record_unwind_protect
(unuse_menu_items
, Qnil
);
846 /* Decode the menu items from what was specified. */
848 keymap
= get_keymap
(menu, 0, 0);
851 /* We were given a keymap. Extract menu info from the keymap. */
854 /* Extract the detailed info to make one pane. */
855 keymap_panes
(&menu, 1, NILP
(position
));
857 /* Search for a string appearing directly as an element of the keymap.
858 That string is the title of the menu. */
859 prompt
= Fkeymap_prompt
(keymap
);
860 title = NILP
(prompt
) ? build_string
("Select"
) : prompt
;
862 /* Make that be the pane title of the first pane. */
863 if (!NILP
(prompt
) && menu_items_n_panes
>= 0)
864 XVECTOR
(menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = prompt
;
868 else if (CONSP
(menu) && KEYMAPP
(XCAR
(menu)))
870 /* We were given a list of keymaps. */
871 int nmaps
= XFASTINT
(Flength
(menu));
873 = (Lisp_Object
*) alloca
(nmaps
* sizeof
(Lisp_Object
));
878 /* The first keymap that has a prompt string
879 supplies the menu title. */
880 for (tem
= menu, i
= 0; CONSP
(tem
); tem
= XCDR
(tem
))
884 maps
[i
++] = keymap
= get_keymap
(XCAR
(tem
), 1, 0);
886 prompt
= Fkeymap_prompt
(keymap
);
887 if (NILP
(title) && !NILP
(prompt
))
891 /* Extract the detailed info to make one pane. */
892 keymap_panes
(maps
, nmaps
, NILP
(position
));
894 /* Make the title be the pane title of the first pane. */
895 if (!NILP
(title) && menu_items_n_panes
>= 0)
896 XVECTOR
(menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = title;
902 /* We were given an old-fashioned menu. */
904 CHECK_STRING
(title);
906 list_of_panes
(Fcdr
(menu));
911 unbind_to
(specpdl_count
, Qnil
);
913 /* If no position given, that was a signal to just precompute and cache
914 key equivalents, which was a side-effect of what we just did. */
917 discard_menu_items
();
922 record_unwind_protect
(cleanup_popup_menu
, Qnil
);
925 /* now parse stage 2 as in ns_update_menubar */
926 wv
= xmalloc_widget_value
();
927 wv
->name
= "contextmenu"
;
930 wv
->button_type
= BUTTON_TYPE_NONE
;
934 specpdl_count2
= SPECPDL_INDEX
();
937 /*PENDING: a couple of one-line differences prevent reuse */
938 wv
= digest_single_submenu
(0, menu_items_used
, Qnil
);
941 widget_value
*save_wv
= 0, *prev_wv
= 0;
942 widget_value
**submenu_stack
943 = (widget_value
**) alloca
(menu_items_used
* sizeof
(widget_value
*));
944 /* Lisp_Object *subprefix_stack
945 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); */
946 int submenu_depth
= 0;
950 /* Loop over all panes and items, filling in the tree. */
952 while (i
< menu_items_used
)
954 if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qnil
))
956 submenu_stack
[submenu_depth
++] = save_wv
;
962 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qlambda
))
965 save_wv
= submenu_stack
[--submenu_depth
];
969 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qt
)
970 && submenu_depth
!= 0)
971 i
+= MENU_ITEMS_PANE_LENGTH
;
972 /* Ignore a nil in the item list.
973 It's meaningful only for dialog boxes. */
974 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qquote
))
976 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qt
))
978 /* Create a new pane. */
979 Lisp_Object pane_name
, prefix
;
982 pane_name
= AREF
(menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
983 prefix
= AREF
(menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
985 #ifndef HAVE_MULTILINGUAL_MENU
986 if (STRINGP
(pane_name
) && STRING_MULTIBYTE
(pane_name
))
988 pane_name
= ENCODE_MENU_STRING
(pane_name
);
989 ASET
(menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
992 pane_string
= (NILP
(pane_name
)
993 ? ""
: (char *) SDATA
(pane_name
));
994 /* If there is just one top-level pane, put all its items directly
995 under the top-level menu. */
996 if (menu_items_n_panes
== 1)
999 /* If the pane has a meaningful name,
1000 make the pane a top-level menu item
1001 with its items as a submenu beneath it. */
1002 if (!keymaps
&& strcmp (pane_string
, ""
))
1004 wv
= xmalloc_widget_value
();
1008 first_wv
->contents
= wv
;
1009 wv
->name
= pane_string
;
1010 if (keymaps
&& !NILP
(prefix
))
1014 wv
->button_type
= BUTTON_TYPE_NONE
;
1019 else if (first_pane
)
1025 i
+= MENU_ITEMS_PANE_LENGTH
;
1029 /* Create a new item within current pane. */
1030 Lisp_Object item_name
, enable
, descrip
, def
, type, selected
, help;
1031 item_name
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1032 enable
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1033 descrip
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1034 def
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1035 type = AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1036 selected
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1037 help = AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1039 #ifndef HAVE_MULTILINGUAL_MENU
1040 if (STRINGP
(item_name
) && STRING_MULTIBYTE
(item_name
))
1042 item_name
= ENCODE_MENU_STRING
(item_name
);
1043 ASET
(menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1046 if (STRINGP
(descrip
) && STRING_MULTIBYTE
(descrip
))
1048 descrip
= ENCODE_MENU_STRING
(descrip
);
1049 ASET
(menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1051 #endif
/* not HAVE_MULTILINGUAL_MENU */
1053 wv
= xmalloc_widget_value
();
1057 save_wv
->contents
= wv
;
1058 wv
->name
= (char *) SDATA
(item_name
);
1059 if (!NILP
(descrip
))
1060 wv
->key
= (char *) SDATA
(descrip
);
1062 /* If this item has a null value,
1063 make the call_data null so that it won't display a box
1064 when the mouse is on it. */
1066 = !NILP
(def
) ?
(void
*) &XVECTOR
(menu_items
)->contents
[i
] : 0;
1067 wv
->enabled
= !NILP
(enable
);
1070 wv
->button_type
= BUTTON_TYPE_NONE
;
1071 else if (EQ
(type, QCtoggle
))
1072 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1073 else if (EQ
(type, QCradio
))
1074 wv
->button_type
= BUTTON_TYPE_RADIO
;
1078 wv
->selected
= !NILP
(selected
);
1080 if (! STRINGP
(help))
1087 i
+= MENU_ITEMS_ITEM_LENGTH
;
1095 widget_value
*wv_title
= xmalloc_widget_value
();
1096 widget_value
*wv_sep
= xmalloc_widget_value
();
1098 /* Maybe replace this separator with a bitmap or owner-draw item
1099 so that it looks better. Having two separators looks odd. */
1100 wv_sep
->name
= "
--"
;
1101 wv_sep
->next
= first_wv
->contents
;
1102 wv_sep
->help = Qnil
;
1104 #ifndef HAVE_MULTILINGUAL_MENU
1105 if (STRING_MULTIBYTE
(title))
1106 title = ENCODE_MENU_STRING
(title);
1109 wv_title
->name
= (char *) SDATA
(title);
1110 wv_title
->enabled
= NULL;
1111 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1112 wv_title
->help = Qnil
;
1113 wv_title
->next
= wv_sep
;
1114 first_wv
->contents
= wv_title
;
1117 pmenu
= [[EmacsMenu alloc
] initWithTitle
:
1118 [NSString stringWithUTF8String
: SDATA
(title)]];
1119 [pmenu fillWithWidgetValue
: first_wv
->contents
];
1120 free_menubar_widget_value_tree
(first_wv
);
1121 unbind_to
(specpdl_count2
, Qnil
);
1123 tem
= [pmenu runMenuAt
: p forFrame
: f keymaps
: keymaps
];
1124 [[FRAME_NS_VIEW
(SELECTED_FRAME
()) window
] makeKeyWindow
];
1127 unbind_to
(specpdl_count
, Qnil
);
1130 if (error_name
) error (error_name
);
1137 /* ==========================================================================
1139 Toolbar: externally-called functions
1141 ========================================================================== */
1144 free_frame_tool_bar
(FRAME_PTR f
)
1145 /* --------------------------------------------------------------------------
1146 Under NS we just hide the toolbar until it might be needed again.
1147 -------------------------------------------------------------------------- */
1149 [[FRAME_NS_VIEW
(f
) toolbar
] setVisible
: NO
];
1153 update_frame_tool_bar
(FRAME_PTR f
)
1154 /* --------------------------------------------------------------------------
1155 Update toolbar contents
1156 -------------------------------------------------------------------------- */
1159 EmacsToolbar
*toolbar
= [FRAME_NS_VIEW
(f
) toolbar
];
1161 [toolbar clearActive
];
1163 /* update EmacsToolbar as in GtkUtils, build items list */
1164 for (i
= 0; i
< f
->n_tool_bar_items
; ++i
)
1166 #define TOOLPROP
(IDX
) AREF
(f
->tool_bar_items
, \
1167 i
* TOOL_BAR_ITEM_NSLOTS
+ (IDX
))
1169 BOOL enabled_p
= !NILP
(TOOLPROP
(TOOL_BAR_ITEM_ENABLED_P
));
1170 BOOL selected_p
= !NILP
(TOOLPROP
(TOOL_BAR_ITEM_SELECTED_P
));
1175 Lisp_Object helpObj
;
1178 /* If image is a vector, choose the image according to the
1180 image = TOOLPROP
(TOOL_BAR_ITEM_IMAGES
);
1181 if (VECTORP
(image))
1183 /* NS toolbar auto-computes disabled and selected images */
1184 idx
= TOOL_BAR_IMAGE_ENABLED_SELECTED
;
1185 xassert
(ASIZE
(image) >= idx
);
1186 image = AREF
(image, idx
);
1192 /* Ignore invalid image specifications. */
1193 if (!valid_image_p
(image))
1195 NSLog
(@"Invalid
image for toolbar item"
);
1199 img_id
= lookup_image
(f
, image);
1200 img
= IMAGE_FROM_ID
(f
, img_id
);
1201 prepare_image_for_display
(f
, img
);
1203 if (img
->load_failed_p || img
->pixmap
== nil
)
1205 NSLog
(@"Could not prepare toolbar
image for display."
);
1209 helpObj
= TOOLPROP
(TOOL_BAR_ITEM_HELP
);
1211 helpObj
= TOOLPROP
(TOOL_BAR_ITEM_CAPTION
);
1212 helpText
= NILP
(helpObj
) ? ""
: (char *)SDATA
(helpObj
);
1214 [toolbar addDisplayItemWithImage
: img
->pixmap idx
: i helpText
: helpText
1215 enabled
: enabled_p
];
1219 if (![toolbar isVisible
])
1220 [toolbar setVisible
: YES
];
1222 if ([toolbar changed
])
1224 /* inform app that toolbar has changed */
1225 NSDictionary
*dict
= [toolbar configurationDictionary
];
1226 NSMutableDictionary
*newDict
= [dict mutableCopy
];
1227 NSEnumerator
*keys
= [[dict allKeys
] objectEnumerator
];
1229 while ((key
= [keys nextObject
]) != nil
)
1231 NSObject
*val
= [dict objectForKey
: key
];
1232 if ([val isKindOfClass
: [NSArray
class]])
1235 [toolbar toolbarDefaultItemIdentifiers
: toolbar
]
1240 [toolbar setConfigurationFromDictionary
: newDict
];
1247 /* ==========================================================================
1249 Toolbar: class implementation
1251 ========================================================================== */
1253 @implementation EmacsToolbar
1255 - initForView
: (EmacsView
*)view withIdentifier
: (NSString
*)identifier
1257 self
= [super initWithIdentifier
: identifier
];
1259 [self setDisplayMode
: NSToolbarDisplayModeIconOnly
];
1260 [self setSizeMode
: NSToolbarSizeModeSmall
];
1261 [self setDelegate
: self
];
1262 identifierToItem
= [[NSMutableDictionary alloc
] initWithCapacity
: 10];
1263 activeIdentifiers
= [[NSMutableArray alloc
] initWithCapacity
: 8];
1264 prevEnablement
= enablement
= 0L;
1270 [prevIdentifiers release
];
1271 [activeIdentifiers release
];
1272 [identifierToItem release
];
1276 - (void
) clearActive
1278 [prevIdentifiers release
];
1279 prevIdentifiers
= [activeIdentifiers copy
];
1280 [activeIdentifiers removeAllObjects
];
1281 prevEnablement
= enablement
;
1287 return [activeIdentifiers isEqualToArray
: prevIdentifiers
] &&
1288 enablement
== prevEnablement ? NO
: YES
;
1291 - (void
) addDisplayItemWithImage
: (EmacsImage
*)img idx
: (int
)idx
1292 helpText
: (char *)help enabled
: (BOOL
)enabled
1294 /* 1) come up w/identifier */
1295 NSString
*identifier
1296 = [NSString stringWithFormat
: @"
%u", [img hash]];
1298 /* 2) create / reuse item */
1299 NSToolbarItem
*item
= [identifierToItem objectForKey
: identifier
];
1302 item
= [[[NSToolbarItem alloc
] initWithItemIdentifier
: identifier
]
1304 [item setImage
: img
];
1305 [item setToolTip
: [NSString stringWithCString
: help]];
1306 [item setTarget
: emacsView
];
1307 [item setAction
: @selector
(toolbarClicked
:)];
1311 [item setEnabled
: enabled
];
1313 /* 3) update state */
1314 [identifierToItem setObject
: item forKey
: identifier
];
1315 [activeIdentifiers addObject
: identifier
];
1316 enablement
= (enablement
<< 1) |
(enabled
== YES
);
1319 /* This overrides super's implementation, which automatically sets
1320 all items to enabled state (for some reason). */
1321 - (void
)validateVisibleItems
{ }
1324 /* delegate methods */
1326 - (NSToolbarItem
*)toolbar
: (NSToolbar
*)toolbar
1327 itemForItemIdentifier
: (NSString
*)itemIdentifier
1328 willBeInsertedIntoToolbar
: (BOOL
)flag
1330 /* look up NSToolbarItem by identifier and return... */
1331 return [identifierToItem objectForKey
: itemIdentifier
];
1334 - (NSArray
*)toolbarDefaultItemIdentifiers
: (NSToolbar
*)toolbar
1336 /* return entire set.. */
1337 return activeIdentifiers
;
1340 /* for configuration palette (not yet supported) */
1341 - (NSArray
*)toolbarAllowedItemIdentifiers
: (NSToolbar
*)toolbar
1343 /* return entire set... */
1344 return [identifierToItem allKeys
];
1347 /* optional and unneeded */
1348 /* - toolbarWillAddItem: (NSNotification *)notification { } */
1349 /* - toolbarDidRemoveItem: (NSNotification *)notification { } */
1350 /* - (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar */
1352 @
end /* EmacsToolbar */
1356 /* ==========================================================================
1358 Tooltip: class implementation
1360 ========================================================================== */
1362 /* Needed because NeXTstep does not provide enough control over tooltip
1364 @implementation EmacsTooltip
1368 NSColor
*col
= [NSColor colorWithCalibratedRed
: 1.0 green
: 1.0
1369 blue
: 0.792 alpha
: 0.95];
1370 NSFont
*font
= [NSFont toolTipsFontOfSize
: 0];
1371 NSFont
*sfont
= [font screenFont
];
1372 int height
= [sfont ascender
] - [sfont descender
];
1373 /*[font boundingRectForFont].size.height; */
1374 NSRect r
= NSMakeRect
(0, 0, 100, height
+6);
1376 textField
= [[NSTextField alloc
] initWithFrame
: r
];
1377 [textField setFont
: font
];
1378 [textField setBackgroundColor
: col
];
1380 [textField setEditable
: NO
];
1381 [textField setSelectable
: NO
];
1382 [textField setBordered
: YES
];
1383 [textField setBezeled
: YES
];
1384 [textField setDrawsBackground
: YES
];
1386 win
= [[NSWindow alloc
]
1387 initWithContentRect
: [textField frame
]
1389 backing
: NSBackingStoreBuffered
1391 [win setReleasedWhenClosed
: NO
];
1392 [win setDelegate
: self
];
1393 [[win contentView
] addSubview
: textField
];
1394 /* [win setBackgroundColor: col]; */
1395 [win setOpaque
: NO
];
1404 [textField release
];
1408 - (void
) setText
: (char *)text
1410 NSString
*str
= [NSString stringWithUTF8String
: text];
1411 NSRect r
= [textField frame
];
1412 r.
size.width
= [[[textField font
] screenFont
] widthOfString
: str
] + 8;
1413 [textField setFrame
: r
];
1414 [textField setStringValue
: str
];
1417 - (void
) showAtX
: (int
)x Y
: (int
)y
for: (int
)seconds
1419 NSRect wr
= [win frame
];
1421 wr.origin
= NSMakePoint
(x
, y
);
1422 wr.
size = [textField frame
].
size;
1424 [win setFrame
: wr display
: YES
];
1425 [win orderFront
: self
];
1427 timer
= [NSTimer scheduledTimerWithTimeInterval
: (float
)seconds target
: self
1428 selector
: @selector
(hide
)
1429 userInfo
: nil repeats
: NO
];
1438 if ([timer isValid
])
1447 return timer
!= nil
;
1452 return [textField frame
];
1455 @
end /* EmacsTooltip */
1459 /* ==========================================================================
1461 Popup Dialog: implementing functions
1463 ========================================================================== */
1466 ns_popup_dialog
(Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
1469 Lisp_Object window
, tem
;
1474 NSTRACE
(x
-popup
-dialog);
1478 isQ
= NILP
(header
);
1480 if (EQ
(position
, Qt
))
1482 window
= selected_window
;
1484 else if (CONSP
(position
))
1487 tem
= Fcar
(position
);
1488 if (XTYPE
(tem
) == Lisp_Cons
)
1489 window
= Fcar
(Fcdr
(position
));
1492 tem
= Fcar
(Fcdr
(position
)); /* EVENT_START (position) */
1493 window
= Fcar
(tem
); /* POSN_WINDOW (tem) */
1496 else if (FRAMEP
(position
))
1502 CHECK_LIVE_WINDOW
(position
);
1506 if (FRAMEP
(window
))
1507 f
= XFRAME
(window
);
1510 CHECK_LIVE_WINDOW
(window
);
1511 f
= XFRAME
(WINDOW_FRAME
(XWINDOW
(window
)));
1513 p.x
= (int
)f
->left_pos
+ ((int
)FRAME_COLUMN_WIDTH
(f
) * f
->text_cols
)/2;
1514 p.y
= (int
)f
->top_pos
+ (FRAME_LINE_HEIGHT
(f
) * f
->text_lines
)/2;
1515 dialog = [[EmacsDialogPanel alloc
] initFromContents
: contents
1518 tem
= [dialog runDialogAt
: p
];
1522 [[FRAME_NS_VIEW
(SELECTED_FRAME
()) window
] makeKeyWindow
];
1527 /* ==========================================================================
1529 Popup Dialog: class implementation
1531 ========================================================================== */
1533 @interface FlippedView
: NSView
1538 @implementation FlippedView
1545 @implementation EmacsDialogPanel
1548 #define ICONSIZE
64.0
1549 #define TEXTHEIGHT
20.0
1550 #define MINCELLWIDTH
90.0
1552 - initWithContentRect
: (NSRect
)contentRect styleMask
: (unsigned int
)aStyle
1553 backing
: (NSBackingStoreType
)backingType defer
: (BOOL
)flag
1555 NSSize spacing
= {SPACER
, SPACER
};
1557 char this_cmd_name
[80];
1559 static NSImageView
*imgView
;
1560 static FlippedView
*contentView
;
1565 area.origin.x
= 3*SPACER
;
1566 area.origin.y
= 2*SPACER
;
1567 area.
size.width
= ICONSIZE
;
1568 area.
size.height
= ICONSIZE
;
1569 img
= [[NSImage imageNamed
: @"NSApplicationIcon"
] copy
];
1570 [img setScalesWhenResized
: YES
];
1571 [img setSize
: NSMakeSize
(ICONSIZE
, ICONSIZE
)];
1572 imgView
= [[NSImageView alloc
] initWithFrame
: area
];
1573 [imgView setImage
: img
];
1574 [imgView setEditable
: NO
];
1578 aStyle
= NSTitledWindowMask
;
1582 [super initWithContentRect
: contentRect styleMask
: aStyle
1583 backing
: backingType defer
: flag];
1584 contentView
= [[FlippedView alloc
] initWithFrame
: [[self contentView
] frame
]];
1585 [self setContentView
: contentView
];
1587 [[self contentView
] setAutoresizesSubviews
: YES
];
1589 [[self contentView
] addSubview
: imgView
];
1590 [self setTitle
: @""
];
1592 area.origin.x
+= ICONSIZE
+2*SPACER
;
1593 /* area.origin.y = TEXTHEIGHT; ICONSIZE/2-10+SPACER; */
1594 area.
size.width
= 400;
1595 area.
size.height
= TEXTHEIGHT
;
1596 command
= [[[NSTextField alloc
] initWithFrame
: area
] autorelease
];
1597 [[self contentView
] addSubview
: command
];
1598 [command setStringValue
: @"Emacs"
];
1599 [command setDrawsBackground
: NO
];
1600 [command setBezeled
: NO
];
1601 [command setSelectable
: NO
];
1602 [command setFont
: [NSFont boldSystemFontOfSize
: 13.0]];
1604 /* area.origin.x = ICONSIZE+2*SPACER;
1605 area.origin.y = TEXTHEIGHT + 2*SPACER;
1606 area.size.width = 400;
1607 area.size.height= 2;
1608 tem = [[[NSBox alloc] initWithFrame: area] autorelease];
1609 [[self contentView] addSubview: tem];
1610 [tem setTitlePosition: NSNoTitle];
1611 [tem setAutoresizingMask: NSViewWidthSizable];*/
1613 /* area.origin.x = ICONSIZE+2*SPACER; */
1614 area.origin.y
+= TEXTHEIGHT
+SPACER
;
1615 area.
size.width
= 400;
1616 area.
size.height
= TEXTHEIGHT
;
1617 title = [[[NSTextField alloc
] initWithFrame
: area
] autorelease
];
1618 [[self contentView
] addSubview
: title];
1619 [title setDrawsBackground
: NO
];
1620 [title setBezeled
: NO
];
1621 [title setSelectable
: NO
];
1622 [title setFont
: [NSFont systemFontOfSize
: 11.0]];
1624 cell = [[[NSButtonCell alloc
] initTextCell
: @""
] autorelease
];
1625 [cell setBordered
: NO
];
1626 [cell setEnabled
: NO
];
1627 [cell setCellAttribute
: NSCellIsInsetButton to
: 8];
1628 [cell setBezelStyle
: NSRoundedBezelStyle
];
1630 matrix
= [[NSMatrix alloc
] initWithFrame
: contentRect
1631 mode
: NSHighlightModeMatrix
1634 numberOfColumns
: 1];
1635 [[self contentView
] addSubview
: matrix
];
1637 [matrix setFrameOrigin
: NSMakePoint
(area.origin.x
,
1638 area.origin.y
+ (TEXTHEIGHT
+3*SPACER
))];
1639 [matrix setIntercellSpacing
: spacing
];
1641 [self setOneShot
: YES
];
1642 [self setReleasedWhenClosed
: YES
];
1643 [self setHidesOnDeactivate
: YES
];
1648 - (BOOL
)windowShouldClose
: (id
)sender
1650 [NSApp stopModalWithCode
: XHASH
(Qnil
)]; // FIXME
: BIG UGLY HACK
!!
1655 void process_dialog
(id window
, Lisp_Object list
)
1660 for (; XTYPE
(list
) == Lisp_Cons
; list
= XCDR
(list
))
1663 if (XTYPE
(item
) == Lisp_String
)
1665 [window addString
: XSTRING
(item
)->data row
: row
++];
1667 else if (XTYPE
(item
) == Lisp_Cons
)
1669 [window addButton
: XSTRING
(XCAR
(item
))->data
1670 value
: XCDR
(item
) row
: row
++];
1672 else if (NILP
(item
))
1681 - addButton
: (char *)str value
: (Lisp_Object
)val row
: (int
)row
1690 cell = [matrix cellAtRow
: row column
: cols
-1];
1691 [cell setTarget
: self
];
1692 [cell setAction
: @selector
(clicked
: )];
1693 [cell setTitle
: [NSString stringWithUTF8String
: str
]];
1694 [cell setTag
: XHASH
(val
)]; // FIXME
: BIG UGLY HACK
!!
1695 [cell setBordered
: YES
];
1696 [cell setEnabled
: YES
];
1702 - addString
: (char *)str row
: (int
)row
1711 cell = [matrix cellAtRow
: row column
: cols
-1];
1712 [cell setTitle
: [NSString stringWithUTF8String
: str
]];
1713 [cell setBordered
: YES
];
1714 [cell setEnabled
: NO
];
1730 NSArray
*sellist
= nil
;
1733 sellist
= [sender selectedCells
];
1734 if ([sellist count
]<1)
1737 seltag
= [[sellist objectAtIndex
: 0] tag
];
1738 if (seltag
== XHASH
(Qundefined
)) // FIXME
: BIG UGLY HACK
!!
1739 [NSApp stopModalWithCode
: seltag
];
1744 - initFromContents
: (Lisp_Object
)contents isQuestion
: (BOOL
)isQ
1749 if (XTYPE
(contents
) == Lisp_Cons
)
1751 head
= Fcar
(contents
);
1752 process_dialog
(self
, Fcdr
(contents
));
1757 if (XTYPE
(head
) == Lisp_String
)
1758 [title setStringValue
:
1759 [NSString stringWithUTF8String
: XSTRING
(head
)->data
]];
1760 else if (isQ
== YES
)
1761 [title setStringValue
: @"Question"
];
1763 [title setStringValue
: @"Information"
];
1769 if (cols
== 1 && rows
> 1) /* Never told where to split */
1772 for (i
= 0; i
<rows
/2; i
++)
1774 [matrix putCell
: [matrix cellAtRow
: (rows
+1)/2 column
: 0]
1775 atRow
: i column
: 1];
1776 [matrix removeRow
: (rows
+1)/2];
1782 NSSize csize
= [matrix cellSize
];
1783 if (csize.width
< MINCELLWIDTH
)
1785 csize.width
= MINCELLWIDTH
;
1786 [matrix setCellSize
: csize
];
1787 [matrix sizeToCells
];
1792 [command sizeToFit
];
1796 if (r.
size.width
+r.origin.x
> t.
size.width
+t.origin.x
)
1798 t.origin.x
= r.origin.x
;
1799 t.
size.width
= r.
size.width
;
1801 r
= [command frame
];
1802 if (r.
size.width
+r.origin.x
> t.
size.width
+t.origin.x
)
1804 t.origin.x
= r.origin.x
;
1805 t.
size.width
= r.
size.width
;
1809 s
= [(NSView
*)[self contentView
] frame
];
1810 r.
size.width
+= t.origin.x
+t.
size.width
+2*SPACER
-s.
size.width
;
1811 r.
size.height
+= t.origin.y
+t.
size.height
+SPACER
-s.
size.height
;
1812 [self setFrame
: r display
: NO
];
1821 { [super dealloc
]; return; };
1825 - (Lisp_Object
)runDialogAt
: (NSPoint
)p
1828 NSModalSession session
;
1831 [self center
]; /*XXX p ignored? */
1832 [self orderFront
: NSApp
];
1834 session
= [NSApp beginModalSessionForWindow
: self
];
1835 while ((ret
= [NSApp runModalSession
: session
]) == NSRunContinuesResponse
)
1837 (e
= [NSApp nextEventMatchingMask
: NSAnyEventMask
1838 untilDate
: [NSDate distantFuture
]
1839 inMode
: NSEventTrackingRunLoopMode
1841 /*fprintf (stderr, "ret = %d\te = %p\n", ret, e); */
1843 [NSApp endModalSession
: session
];
1845 { // FIXME
: BIG UGLY HACK
!!!
1847 *(EMACS_INT
*)(&tmp
) = ret
;
1856 /* ==========================================================================
1860 ========================================================================== */
1862 DEFUN
("ns
-reset-menu"
, Fns_reset_menu
, Sns_reset_menu
, 0, 0, 0,
1863 "Cause the NS
menu to be re
-calculated."
)
1866 set_frame_menubar
(SELECTED_FRAME
(), 1, 0);
1871 DEFUN
("x
-popup
-menu"
, Fx_popup_menu
, Sx_popup_menu
, 2, 2, 0,
1872 "Pop up a deck
-of
-cards
menu and
return user
's selection.\n\
1873 POSITION is a position specification. This is either a mouse button event\n\
1874 or a list ((XOFFSET YOFFSET) WINDOW)\n\
1875 where XOFFSET and YOFFSET are positions in pixels from the top left\n\
1876 corner of WINDOW's frame.
(WINDOW may be a frame object instead of a window.
)\n\
1877 This controls the position of the center of the first
line\n\
1878 in the first pane of the
menu, not the top left of the
menu as a whole.
\n\
1880 MENU is a specifier
for a
menu.
For the simplest
case, MENU is a keymap.
\n\
1881 The
menu items come from key bindings that have a
menu string as well as
\n\
1882 a definition
; actually
, the
\"definition
\" in such a key binding looks like
\n\
1883 \
(STRING .
REAL-DEFINITION
). To give the
menu a
title, put a string into
\n\
1884 the keymap as a top
-level element.
\n\n\
1885 You can also use a list of keymaps as
MENU.
\n\
1886 Then each keymap makes a separate pane.
\n\
1887 When
MENU is a keymap or a list of keymaps
, the
return value
\n\
1888 is a list of events.
\n\n\
1889 Alternatively
, you can specify a
menu of multiple panes
\n\
1890 with a list of the form
(TITLE PANE1 PANE2...
),\n\
1891 where each pane is a list of form
(TITLE ITEM1 ITEM2...
).
\n\
1892 Each ITEM is normally a cons
cell (STRING . VALUE
);\n\
1893 but a string can appear as an item
--that makes a nonselectable
line\n\
1895 With this form of
menu, the
return value is VALUE from the chosen item."
)
1897 Lisp_Object position
, menu;
1899 return ns_popup_menu
(position
, menu);
1903 DEFUN
("x
-popup
-dialog"
, Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
1904 doc: /* Pop up a dialog box and return user's selection.
1905 POSITION specifies which frame to use.
1906 This is normally a mouse button event or a window or frame.
1907 If POSITION is t, it means to use the frame the mouse is on.
1908 The dialog box appears in the middle of the specified frame.
1910 CONTENTS specifies the alternatives to display in the dialog box.
1911 It is a list of the form (DIALOG ITEM1 ITEM2...).
1912 Each ITEM is a cons cell (STRING . VALUE).
1913 The return value is VALUE from the chosen item.
1915 An ITEM may also be just a string--that makes a nonselectable item.
1916 An ITEM may also be nil--that means to put all preceding items
1917 on the left of the dialog box and all following items on the right.
1918 \(By default, approximately half appear on each side.)
1920 If HEADER is non-nil, the frame title for the box is "Information",
1921 otherwise it is "Question".
1923 If the user gets rid of the dialog box without making a valid choice,
1924 for instance using the window manager, then this produces a quit and
1925 `x-popup-dialog' does not return. */)
1926 (position
, contents
, header
)
1927 Lisp_Object position
, contents
, header
;
1929 return ns_popup_dialog
(position
, contents
, header
);
1933 /* ==========================================================================
1935 Lisp interface declaration
1937 ========================================================================== */
1942 defsubr
(&Sx_popup_menu
);
1943 defsubr
(&Sx_popup_dialog
);
1944 defsubr
(&Sns_reset_menu
);
1945 staticpro
(&menu_items
);
1948 Qdebug_on_next_call
= intern
("
debug-on
-next
-call"
);
1949 staticpro
(&Qdebug_on_next_call
);
1952 // arch
-tag
: 75773656-52e5
-4c44
-a398
-47bd87b32619