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 Lisp_Object Qundefined
, Qmenu_enable
, Qmenu_bar_update_hook
;
57 extern Lisp_Object QCtoggle
, QCradio
;
59 extern Lisp_Object Vmenu_updating_frame
;
61 Lisp_Object Qdebug_on_next_call
;
62 extern Lisp_Object Voverriding_local_map
, Voverriding_local_map_menu_flag
,
63 Qoverriding_local_map
, Qoverriding_terminal_local_map
;
65 extern
long context_menu_value
;
66 EmacsMenu
*mainMenu
, *svcsMenu
;
68 /* NOTE: toolbar implementation is at end,
69 following complete menu implementation. */
72 /* ==========================================================================
74 Menu: Externally-called functions
76 ========================================================================== */
79 /*23: FIXME: not currently used, but should normalize with other terms. */
81 x_activate_menubar
(struct frame
*f
)
83 fprintf (stderr
, "XXX
: Received x_activate_menubar event.
\n"
);
87 /* Supposed to discard menubar and free storage. Since we share the
88 menubar among frames and update its context for the focused window,
89 there is nothing to do here. */
91 free_frame_menubar
(struct frame
*f
)
97 /* --------------------------------------------------------------------------
98 Update menubar. Three cases:
99 1) deep_p = 0, submenu = nil: Fresh switch onto a frame -- either set up
100 just top-level menu strings (OS X), or goto case (2) (GNUstep).
101 2) deep_p = 1, submenu = nil: Recompute all submenus.
102 3) deep_p = 1, submenu = non-nil: Update contents of a single submenu.
103 -------------------------------------------------------------------------- */
104 /*#define NSMENUPROFILE 1 */
106 ns_update_menubar
(struct frame
*f
, int deep_p
, EmacsMenu
*submenu
)
108 NSAutoreleasePool
*pool
;
109 id
menu = [NSApp mainMenu
];
110 static EmacsMenu
*last_submenu
= nil
;
112 const
char *submenuTitle
= [[submenu
title] UTF8String
];
113 extern int waiting_for_input
;
116 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
124 NSTRACE
(set_frame_menubar
);
126 if (f
!= SELECTED_FRAME
())
128 XSETFRAME
(Vmenu_updating_frame
, f
);
129 /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */
132 pool
= [[NSAutoreleasePool alloc
] init
];
134 /* Menu may have been created automatically; if so, discard it. */
135 if ([menu isKindOfClass
: [EmacsMenu
class]] == NO
)
143 menu = [[EmacsMenu alloc
] initWithTitle
: @"Emacs"
];
147 { /* close up anything on there */
148 id attMenu
= [menu attachedMenu
];
155 t
= -(1000*tb.time
+tb.millitm
);
158 /* widget_value is a straightforward object translation of emacs's
159 Byzantine lisp menu structures */
160 wv
= xmalloc_widget_value
();
164 wv
->button_type
= BUTTON_TYPE_NONE
;
168 #ifdef NS_IMPL_GNUSTEP
169 deep_p
= 1; /* until GNUstep NSMenu implements the Panther delegation model */
174 /* Fully parse one or more of the submenus. */
176 int
*submenu_start
, *submenu_end
;
177 int
*submenu_top_level_items
, *submenu_n_panes
;
178 struct buffer
*prev
= current_buffer
;
180 int specpdl_count
= SPECPDL_INDEX
();
181 int previous_menu_items_used
= f
->menu_bar_items_used
;
182 Lisp_Object
*previous_items
183 = (Lisp_Object
*) alloca
(previous_menu_items_used
184 * sizeof
(Lisp_Object
));
186 /* lisp preliminaries */
187 buffer
= XWINDOW
(FRAME_SELECTED_WINDOW
(f
))->buffer
;
188 specbind
(Qinhibit_quit
, Qt
);
189 specbind
(Qdebug_on_next_call
, Qnil
);
190 record_unwind_save_match_data
();
191 if (NILP
(Voverriding_local_map_menu_flag
))
193 specbind
(Qoverriding_terminal_local_map
, Qnil
);
194 specbind
(Qoverriding_local_map
, Qnil
);
196 set_buffer_internal_1
(XBUFFER
(buffer
));
198 /* TODO: for some reason this is not needed in other terms,
199 but some menu updates call Info-extract-pointer which causes
200 abort-on-error if waiting-for-input. Needs further investigation. */
201 owfi
= waiting_for_input
;
202 waiting_for_input
= 0;
204 /* lucid hook and possible reset */
205 safe_run_hooks
(Qactivate_menubar_hook
);
206 if (! NILP
(Vlucid_menu_bar_dirty_flag
))
207 call0
(Qrecompute_lucid_menubar
);
208 safe_run_hooks
(Qmenu_bar_update_hook
);
209 FRAME_MENU_BAR_ITEMS
(f
) = menu_bar_items
(FRAME_MENU_BAR_ITEMS
(f
));
211 /* Now ready to go */
212 items
= FRAME_MENU_BAR_ITEMS
(f
);
214 /* Save the frame's previous menu bar contents data */
215 if (previous_menu_items_used
)
216 bcopy
(XVECTOR
(f
->menu_bar_vector
)->contents
, previous_items
,
217 previous_menu_items_used
* sizeof
(Lisp_Object
));
219 /* parse stage 1: extract from lisp */
222 menu_items
= f
->menu_bar_vector
;
223 menu_items_allocated
= VECTORP
(menu_items
) ? ASIZE
(menu_items
) : 0;
224 submenu_start
= (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
*));
225 submenu_end
= (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
*));
226 submenu_n_panes
= (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
));
227 submenu_top_level_items
228 = (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
*));
230 for (i
= 0; i
< XVECTOR
(items
)->size; i
+= 4)
232 Lisp_Object key
, string
, maps
;
234 key
= XVECTOR
(items
)->contents
[i
];
235 string
= XVECTOR
(items
)->contents
[i
+ 1];
236 maps
= XVECTOR
(items
)->contents
[i
+ 2];
240 /* FIXME: we'd like to only parse the needed submenu, but this
241 was causing crashes in the _common parsing code.. need to make
242 sure proper initialization done.. */
243 /* if (submenu && strcmp (submenuTitle, SDATA (string)))
246 submenu_start
[i
] = menu_items_used
;
248 menu_items_n_panes
= 0;
249 submenu_top_level_items
[i
] = parse_single_submenu
(key
, string
, maps
);
250 submenu_n_panes
[i
] = menu_items_n_panes
;
251 submenu_end
[i
] = menu_items_used
;
255 finish_menu_items
();
256 waiting_for_input
= owfi
;
259 if (submenu
&& n
== 0)
261 /* should have found a menu for this one but didn't */
262 fprintf (stderr
, "
ERROR: did not
find lisp
menu for submenu
'%s'.
\n"
,
264 discard_menu_items
();
265 unbind_to
(specpdl_count
, Qnil
);
271 /* parse stage 2: insert into lucid 'widget_value' structures
272 [comments in other terms say not to evaluate lisp code here] */
273 wv
= xmalloc_widget_value
();
274 wv
->name
= "menubar"
;
277 wv
->button_type
= BUTTON_TYPE_NONE
;
281 for (i
= 0; i
< 4*n
; i
+= 4)
283 menu_items_n_panes
= submenu_n_panes
[i
];
284 wv
= digest_single_submenu
(submenu_start
[i
], submenu_end
[i
],
285 submenu_top_level_items
[i
]);
289 first_wv
->contents
= wv
;
290 /* Don't set wv->name here; GC during the loop might relocate it. */
292 wv
->button_type
= BUTTON_TYPE_NONE
;
296 set_buffer_internal_1
(prev
);
298 /* Compare the new menu items with previous, and leave off if no change */
299 /* FIXME: following other terms here, but seems like this should be
300 done before parse stage 2 above, since its results aren't used */
301 if (previous_menu_items_used
302 && (!submenu ||
(submenu
&& submenu
== last_submenu
))
303 && menu_items_used
== previous_menu_items_used
)
305 for (i
= 0; i
< previous_menu_items_used
; i
++)
306 /* FIXME: this ALWAYS fails on Buffers menu items.. something
307 about their strings causes them to change every time, so we
308 double-check failures */
309 if (!EQ
(previous_items
[i
], XVECTOR
(menu_items
)->contents
[i
]))
310 if (!(STRINGP
(previous_items
[i
])
311 && STRINGP
(XVECTOR
(menu_items
)->contents
[i
])
312 && !strcmp (SDATA
(previous_items
[i
]),
313 SDATA
(XVECTOR
(menu_items
)->contents
[i
]))))
315 if (i
== previous_menu_items_used
)
321 t
+= 1000*tb.time
+tb.millitm
;
322 fprintf (stderr
, "NO CHANGE
! CUTTING OUT after
%ld msec.\n", t);
325 free_menubar_widget_value_tree
(first_wv
);
326 discard_menu_items
();
327 unbind_to
(specpdl_count
, Qnil
);
333 /* The menu items are different, so store them in the frame */
334 /* FIXME: this is not correct for single-submenu case */
335 f
->menu_bar_vector
= menu_items
;
336 f
->menu_bar_items_used
= menu_items_used
;
338 /* Calls restore_menu_items, etc., as they were outside */
339 unbind_to
(specpdl_count
, Qnil
);
341 /* Parse stage 2a: now GC cannot happen during the lifetime of the
342 widget_value, so it's safe to store data from a Lisp_String */
343 wv
= first_wv
->contents
;
344 for (i
= 0; i
< XVECTOR
(items
)->size; i
+= 4)
347 string
= XVECTOR
(items
)->contents
[i
+ 1];
350 /* if (submenu && strcmp (submenuTitle, SDATA (string)))
353 wv
->name
= (char *) SDATA
(string
);
354 update_submenu_strings
(wv
->contents
);
358 /* Now, update the NS menu; if we have a submenu, use that, otherwise
359 create a new menu for each sub and fill it. */
362 for (wv
= first_wv
->contents
; wv
; wv
= wv
->next
)
364 if (!strcmp (submenuTitle
, wv
->name
))
366 [submenu fillWithWidgetValue
: wv
->contents
];
367 last_submenu
= submenu
;
374 [menu fillWithWidgetValue
: first_wv
->contents
];
380 static int n_previous_strings
= 0;
381 static
char previous_strings
[100][10];
382 static
struct frame
*last_f
= NULL;
386 /* Make widget-value tree w/ just the top level menu bar strings */
387 items
= FRAME_MENU_BAR_ITEMS
(f
);
396 /* check if no change.. this mechanism is a bit rough, but ready */
397 n
= XVECTOR
(items
)->size / 4;
398 if (f
== last_f
&& n_previous_strings
== n
)
400 for (i
= 0; i
<n
; i
++)
402 string
= AREF
(items
, 4*i
+1);
404 if (EQ
(string
, make_number
(0))) // FIXME
: Why???
--Stef
407 if (previous_strings
[i
][0])
411 if (strncmp
(previous_strings
[i
], SDATA
(string
), 10))
424 for (i
= 0; i
< XVECTOR
(items
)->size; i
+= 4)
426 string
= XVECTOR
(items
)->contents
[i
+ 1];
431 strncpy
(previous_strings
[i
/4], SDATA
(string
), 10);
433 wv
= xmalloc_widget_value
();
434 wv
->name
= (char *) SDATA
(string
);
437 wv
->button_type
= BUTTON_TYPE_NONE
;
439 wv
->call_data
= (void
*) (EMACS_INT
) (-1);
442 /* we'll update the real copy under app menu when time comes */
443 if (!strcmp ("Services"
, wv
->name
))
445 /* but we need to make sure it will update on demand */
446 [svcsMenu setFrame
: f
];
447 [svcsMenu setDelegate
: svcsMenu
];
451 [menu addSubmenuWithTitle
: wv
->name forFrame
: f
];
456 first_wv
->contents
= wv
;
462 n_previous_strings
= n
;
464 n_previous_strings
= 0;
467 free_menubar_widget_value_tree
(first_wv
);
472 t
+= 1000*tb.time
+tb.millitm
;
473 fprintf (stderr
, "
Menu update took
%ld msec.\n", t);
478 [NSApp setMainMenu
: menu];
486 /* Main emacs core entry point for menubar menus: called to indicate that the
487 frame's menus have changed, and the *step representation should be updated
490 set_frame_menubar
(struct frame
*f
, int first_time
, int deep_p
)
492 ns_update_menubar
(f
, deep_p
, nil
);
496 /* Utility (from macmenu.c): is this item a separator? */
498 name_is_separator
(name
)
501 const
char *start
= name
;
503 /* Check if name string consists of only dashes ('-'). */
504 while (*name
== '-') name
++;
505 /* Separators can also be of the form "--:TripleSuperMegaEtched"
506 or "--deep-shadow". We don't implement them yet, se we just treat
507 them like normal separators. */
508 return (*name
== '\0' || start
+ 2 == name
);
512 /* ==========================================================================
514 Menu: class implementation
516 ========================================================================== */
519 /* Menu that can define itself from Emacs "widget_value"s and will lazily
520 update itself when user clicked. Based on Carbon/AppKit implementation
521 by Yamamoto Mitsuharu. */
522 @implementation EmacsMenu
524 /* override designated initializer */
525 - initWithTitle
: (NSString
*)title
527 if (self
= [super initWithTitle
: title])
528 [self setAutoenablesItems
: NO
];
533 /* used for top-level */
534 - initWithTitle
: (NSString
*)title frame
: (struct frame
*)f
536 [self initWithTitle
: title];
539 [self setDelegate
: self
];
545 - (void
)setFrame
: (struct frame
*)f
551 /* delegate method called when a submenu is being opened: run a 'deep' call
552 to set_frame_menubar */
553 - (void
)menuNeedsUpdate
: (NSMenu
*)menu
555 NSEvent
*event
= [[FRAME_NS_VIEW
(frame
) window
] currentEvent
];
556 /* HACK: Cocoa/Carbon will request update on every keystroke
557 via IsMenuKeyEvent -> CheckMenusForKeyEvent. These are not needed
558 since key equivalents are handled through emacs.
559 On Leopard, even keystroke events generate SystemDefined events, but
560 their subtype is 8. */
561 if ([event
type] != NSSystemDefined ||
[event subtype
] == 8)
563 /*fprintf (stderr, "Updating menu '%s'\n", [[self title] UTF8String]); NSLog (@"%@\n", event); */
564 ns_update_menubar
(frame
, 1, self
);
568 - (BOOL
)performKeyEquivalent
: (NSEvent
*)theEvent
570 if (SELECTED_FRAME
() && FRAME_NS_P
(SELECTED_FRAME
())
571 && FRAME_NS_VIEW
(SELECTED_FRAME
()))
572 [FRAME_NS_VIEW
(SELECTED_FRAME
()) keyDown
: theEvent
];
577 /* parse a wdiget_value's key rep (examples: 's-p', 's-S', '(C-x C-s)', '<f13>')
578 into an accelerator string */
579 -(NSString
*)parseKeyEquiv
: (char *)key
583 /* currently we just parse 'super' combinations;
584 later we'll set keyEquivModMask */
585 if (!key ||
!strlen
(key
))
588 while (*tpos
== ' ' ||
*tpos
== '(')
590 if (*tpos
!= 's'/* || tpos[3] != ')'*/)
592 return [NSString stringWithFormat
: @"
%c", tpos[2]];
595 - (NSMenuItem
*)addItemWithWidgetValue
: (void
*)wvptr
598 widget_value
*wv
= (widget_value
*)wvptr
;
600 if (name_is_separator
(wv
->name
))
602 item
= [NSMenuItem separatorItem
];
603 [self addItem
: item
];
607 NSString
*title, *keyEq
;
608 title = [NSString stringWithUTF8String
: wv
->name
];
610 title = @"
< ?
>"
; /* (get out in the open so we know about it) */
612 keyEq
= [self parseKeyEquiv
: wv
->key
];
614 item
= [self addItemWithTitle
: (NSString
*)title
615 action
: @selector
(menuDown
:)
616 keyEquivalent
: keyEq
];
618 [item setKeyEquivalentModifierMask
: keyEquivModMask
];
620 [item setEnabled
: wv
->enabled
];
622 /* Draw radio buttons and tickboxes */
623 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE ||
624 wv
->button_type
== BUTTON_TYPE_RADIO
))
625 [item setState
: NSOnState
];
627 [item setState
: NSOffState
];
629 [item setTag
: (int
)wv
->call_data
];
641 for (n
= [self numberOfItems
]-1; n
>= 0; n
--)
643 NSMenuItem
*item
= [self itemAtIndex
: n
];
644 NSString
*title = [item
title];
645 if (([title length] == 0 ||
[@"Apple" isEqualToString
: title])
646 && ![item isSeparatorItem
])
648 [self removeItemAtIndex
: n
];
653 - (void
)fillWithWidgetValue
: (void
*)wvptr
655 widget_value
*wv
= (widget_value
*)wvptr
;
657 /* clear existing contents */
658 [self setMenuChangedMessagesEnabled
: NO
];
661 /* add new contents */
662 for (; wv
!= NULL; wv
= wv
->next
)
664 NSMenuItem
*item
= [self addItemWithWidgetValue
: wv
];
668 EmacsMenu
*submenu
= [[EmacsMenu alloc
] initWithTitle
: @"Submenu"
];
670 [self setSubmenu
: submenu forItem
: item
];
671 [submenu fillWithWidgetValue
: wv
->contents
];
673 [item setAction
: nil
];
677 [self setMenuChangedMessagesEnabled
: YES
];
678 #ifdef NS_IMPL_GNUSTEP
679 if ([[self window
] isVisible
])
682 if ([self supermenu
] == nil
)
688 /* adds an empty submenu and returns it */
689 - (EmacsMenu
*)addSubmenuWithTitle
: (char *)title forFrame
: (struct frame
*)f
691 NSString
*titleStr
= [NSString stringWithUTF8String
: title];
692 NSMenuItem
*item
= [self addItemWithTitle
: titleStr
693 action
: nil
/*@selector (menuDown:) */
695 EmacsMenu
*submenu
= [[EmacsMenu alloc
] initWithTitle
: titleStr frame
: f
];
696 [self setSubmenu
: submenu forItem
: item
];
701 /* run a menu in popup mode */
702 - (Lisp_Object
)runMenuAt
: (NSPoint
)p forFrame
: (struct frame
*)f
703 keymaps
: (int
)keymaps
705 EmacsView
*view = FRAME_NS_VIEW
(f
);
706 /* p = [view convertPoint:p fromView: nil]; */
707 p.y
= NSHeight
([view frame
]) - p.y
;
708 NSEvent
*e
= [[view window
] currentEvent
];
709 NSEvent
*event
= [NSEvent mouseEventWithType
: NSRightMouseDown
712 timestamp
: [e timestamp
]
713 windowNumber
: [[view window
] windowNumber
]
715 eventNumber
: 0/*[e eventNumber] */
720 context_menu_value
= -1;
721 [NSMenu popUpContextMenu
: self withEvent
: event forView
: view];
722 retVal
= context_menu_value
;
723 context_menu_value
= 0;
725 ? find_and_return_menu_selection
(f
, keymaps
, (void
*)retVal
)
733 /* ==========================================================================
735 Context Menu: implementing functions
737 ========================================================================== */
740 cleanup_popup_menu
(Lisp_Object arg
)
742 discard_menu_items
();
748 ns_popup_menu
(Lisp_Object position
, Lisp_Object
menu)
751 struct frame
*f
= NULL;
753 Lisp_Object window
, x
, y
, tem
, keymap
, title;
755 int specpdl_count
= SPECPDL_INDEX
(), specpdl_count2
;
756 char *error_name
= NULL;
758 widget_value
*wv
, *first_wv
= 0;
760 NSTRACE
(ns_popup_menu
);
762 if (!NILP
(position
))
766 if (EQ
(position
, Qt
)
767 ||
(CONSP
(position
) && (EQ
(XCAR
(position
), Qmenu_bar
)
768 || EQ
(XCAR
(position
), Qtool_bar
))))
770 /* Use the mouse's current position. */
771 struct frame
*new_f
= SELECTED_FRAME
();
773 if (FRAME_TERMINAL
(new_f
)->mouse_position_hook
)
774 (*FRAME_TERMINAL
(new_f
)->mouse_position_hook
)
775 (&new_f
, 0, 0, 0, &x
, &y
, 0);
777 XSETFRAME
(window
, new_f
);
780 window
= selected_window
;
787 CHECK_CONS
(position
);
788 tem
= Fcar
(position
);
789 if (XTYPE
(tem
) == Lisp_Cons
)
791 window
= Fcar
(Fcdr
(position
));
793 y
= Fcar
(Fcdr
(tem
));
797 tem
= Fcar
(Fcdr
(position
));
799 tem
= Fcar
(Fcdr
(Fcdr
(tem
)));
817 struct window
*win
= XWINDOW
(window
);
818 CHECK_LIVE_WINDOW
(window
);
819 f
= XFRAME
(WINDOW_FRAME
(win
));
820 p.x
= FRAME_COLUMN_WIDTH
(f
) * WINDOW_LEFT_EDGE_COL
(win
);
821 p.y
= FRAME_LINE_HEIGHT
(f
) * WINDOW_TOP_EDGE_LINE
(win
);
824 p.x
+= XINT
(x
); p.y
+= XINT
(y
);
826 XSETFRAME
(Vmenu_updating_frame
, f
);
829 { /* no position given */
830 /* FIXME: if called during dump, we need to stop precomputation of
831 key equivalents (see below) because the keydefs in ns-win.el have
832 not been loaded yet. */
835 Vmenu_updating_frame
= Qnil
;
838 /* now parse the lisp menus */
839 record_unwind_protect
(unuse_menu_items
, Qnil
);
843 /* Decode the menu items from what was specified. */
845 keymap
= get_keymap
(menu, 0, 0);
848 /* We were given a keymap. Extract menu info from the keymap. */
851 /* Extract the detailed info to make one pane. */
852 keymap_panes
(&menu, 1, NILP
(position
));
854 /* Search for a string appearing directly as an element of the keymap.
855 That string is the title of the menu. */
856 prompt
= Fkeymap_prompt
(keymap
);
857 title = NILP
(prompt
) ? build_string
("Select"
) : prompt
;
859 /* Make that be the pane title of the first pane. */
860 if (!NILP
(prompt
) && menu_items_n_panes
>= 0)
861 XVECTOR
(menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = prompt
;
865 else if (CONSP
(menu) && KEYMAPP
(XCAR
(menu)))
867 /* We were given a list of keymaps. */
868 int nmaps
= XFASTINT
(Flength
(menu));
870 = (Lisp_Object
*) alloca
(nmaps
* sizeof
(Lisp_Object
));
875 /* The first keymap that has a prompt string
876 supplies the menu title. */
877 for (tem
= menu, i
= 0; CONSP
(tem
); tem
= XCDR
(tem
))
881 maps
[i
++] = keymap
= get_keymap
(XCAR
(tem
), 1, 0);
883 prompt
= Fkeymap_prompt
(keymap
);
884 if (NILP
(title) && !NILP
(prompt
))
888 /* Extract the detailed info to make one pane. */
889 keymap_panes
(maps
, nmaps
, NILP
(position
));
891 /* Make the title be the pane title of the first pane. */
892 if (!NILP
(title) && menu_items_n_panes
>= 0)
893 XVECTOR
(menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = title;
899 /* We were given an old-fashioned menu. */
901 CHECK_STRING
(title);
903 list_of_panes
(Fcdr
(menu));
908 unbind_to
(specpdl_count
, Qnil
);
910 /* If no position given, that was a signal to just precompute and cache
911 key equivalents, which was a side-effect of what we just did. */
914 discard_menu_items
();
919 record_unwind_protect
(cleanup_popup_menu
, Qnil
);
922 /* now parse stage 2 as in ns_update_menubar */
923 wv
= xmalloc_widget_value
();
924 wv
->name
= "contextmenu"
;
927 wv
->button_type
= BUTTON_TYPE_NONE
;
931 specpdl_count2
= SPECPDL_INDEX
();
934 /* FIXME: a couple of one-line differences prevent reuse */
935 wv
= digest_single_submenu
(0, menu_items_used
, Qnil
);
938 widget_value
*save_wv
= 0, *prev_wv
= 0;
939 widget_value
**submenu_stack
940 = (widget_value
**) alloca
(menu_items_used
* sizeof
(widget_value
*));
941 /* Lisp_Object *subprefix_stack
942 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); */
943 int submenu_depth
= 0;
947 /* Loop over all panes and items, filling in the tree. */
949 while (i
< menu_items_used
)
951 if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qnil
))
953 submenu_stack
[submenu_depth
++] = save_wv
;
959 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qlambda
))
962 save_wv
= submenu_stack
[--submenu_depth
];
966 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qt
)
967 && submenu_depth
!= 0)
968 i
+= MENU_ITEMS_PANE_LENGTH
;
969 /* Ignore a nil in the item list.
970 It's meaningful only for dialog boxes. */
971 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qquote
))
973 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qt
))
975 /* Create a new pane. */
976 Lisp_Object pane_name
, prefix
;
979 pane_name
= AREF
(menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
980 prefix
= AREF
(menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
982 #ifndef HAVE_MULTILINGUAL_MENU
983 if (STRINGP
(pane_name
) && STRING_MULTIBYTE
(pane_name
))
985 pane_name
= ENCODE_MENU_STRING
(pane_name
);
986 ASET
(menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
989 pane_string
= (NILP
(pane_name
)
990 ? ""
: (char *) SDATA
(pane_name
));
991 /* If there is just one top-level pane, put all its items directly
992 under the top-level menu. */
993 if (menu_items_n_panes
== 1)
996 /* If the pane has a meaningful name,
997 make the pane a top-level menu item
998 with its items as a submenu beneath it. */
999 if (!keymaps
&& strcmp (pane_string
, ""
))
1001 wv
= xmalloc_widget_value
();
1005 first_wv
->contents
= wv
;
1006 wv
->name
= pane_string
;
1007 if (keymaps
&& !NILP
(prefix
))
1011 wv
->button_type
= BUTTON_TYPE_NONE
;
1016 else if (first_pane
)
1022 i
+= MENU_ITEMS_PANE_LENGTH
;
1026 /* Create a new item within current pane. */
1027 Lisp_Object item_name
, enable
, descrip
, def
, type, selected
, help;
1028 item_name
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1029 enable
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1030 descrip
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1031 def
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1032 type = AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1033 selected
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1034 help = AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1036 #ifndef HAVE_MULTILINGUAL_MENU
1037 if (STRINGP
(item_name
) && STRING_MULTIBYTE
(item_name
))
1039 item_name
= ENCODE_MENU_STRING
(item_name
);
1040 ASET
(menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1043 if (STRINGP
(descrip
) && STRING_MULTIBYTE
(descrip
))
1045 descrip
= ENCODE_MENU_STRING
(descrip
);
1046 ASET
(menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1048 #endif
/* not HAVE_MULTILINGUAL_MENU */
1050 wv
= xmalloc_widget_value
();
1054 save_wv
->contents
= wv
;
1055 wv
->name
= (char *) SDATA
(item_name
);
1056 if (!NILP
(descrip
))
1057 wv
->key
= (char *) SDATA
(descrip
);
1059 /* If this item has a null value,
1060 make the call_data null so that it won't display a box
1061 when the mouse is on it. */
1063 = !NILP
(def
) ?
(void
*) &XVECTOR
(menu_items
)->contents
[i
] : 0;
1064 wv
->enabled
= !NILP
(enable
);
1067 wv
->button_type
= BUTTON_TYPE_NONE
;
1068 else if (EQ
(type, QCtoggle
))
1069 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1070 else if (EQ
(type, QCradio
))
1071 wv
->button_type
= BUTTON_TYPE_RADIO
;
1075 wv
->selected
= !NILP
(selected
);
1077 if (! STRINGP
(help))
1084 i
+= MENU_ITEMS_ITEM_LENGTH
;
1092 widget_value
*wv_title
= xmalloc_widget_value
();
1093 widget_value
*wv_sep
= xmalloc_widget_value
();
1095 /* Maybe replace this separator with a bitmap or owner-draw item
1096 so that it looks better. Having two separators looks odd. */
1097 wv_sep
->name
= "
--"
;
1098 wv_sep
->next
= first_wv
->contents
;
1099 wv_sep
->help = Qnil
;
1101 #ifndef HAVE_MULTILINGUAL_MENU
1102 if (STRING_MULTIBYTE
(title))
1103 title = ENCODE_MENU_STRING
(title);
1106 wv_title
->name
= (char *) SDATA
(title);
1107 wv_title
->enabled
= NO
;
1108 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1109 wv_title
->help = Qnil
;
1110 wv_title
->next
= wv_sep
;
1111 first_wv
->contents
= wv_title
;
1114 pmenu
= [[EmacsMenu alloc
] initWithTitle
:
1115 [NSString stringWithUTF8String
: SDATA
(title)]];
1116 [pmenu fillWithWidgetValue
: first_wv
->contents
];
1117 free_menubar_widget_value_tree
(first_wv
);
1118 unbind_to
(specpdl_count2
, Qnil
);
1120 tem
= [pmenu runMenuAt
: p forFrame
: f keymaps
: keymaps
];
1121 [[FRAME_NS_VIEW
(SELECTED_FRAME
()) window
] makeKeyWindow
];
1124 unbind_to
(specpdl_count
, Qnil
);
1127 if (error_name
) error (error_name
);
1134 /* ==========================================================================
1136 Toolbar: externally-called functions
1138 ========================================================================== */
1141 free_frame_tool_bar
(FRAME_PTR f
)
1142 /* --------------------------------------------------------------------------
1143 Under NS we just hide the toolbar until it might be needed again.
1144 -------------------------------------------------------------------------- */
1146 [[FRAME_NS_VIEW
(f
) toolbar
] setVisible
: NO
];
1150 update_frame_tool_bar
(FRAME_PTR f
)
1151 /* --------------------------------------------------------------------------
1152 Update toolbar contents
1153 -------------------------------------------------------------------------- */
1156 EmacsToolbar
*toolbar
= [FRAME_NS_VIEW
(f
) toolbar
];
1158 [toolbar clearActive
];
1160 /* update EmacsToolbar as in GtkUtils, build items list */
1161 for (i
= 0; i
< f
->n_tool_bar_items
; ++i
)
1163 #define TOOLPROP
(IDX
) AREF
(f
->tool_bar_items
, \
1164 i
* TOOL_BAR_ITEM_NSLOTS
+ (IDX
))
1166 BOOL enabled_p
= !NILP
(TOOLPROP
(TOOL_BAR_ITEM_ENABLED_P
));
1167 BOOL selected_p
= !NILP
(TOOLPROP
(TOOL_BAR_ITEM_SELECTED_P
));
1172 Lisp_Object helpObj
;
1175 /* If image is a vector, choose the image according to the
1177 image = TOOLPROP
(TOOL_BAR_ITEM_IMAGES
);
1178 if (VECTORP
(image))
1180 /* NS toolbar auto-computes disabled and selected images */
1181 idx
= TOOL_BAR_IMAGE_ENABLED_SELECTED
;
1182 xassert
(ASIZE
(image) >= idx
);
1183 image = AREF
(image, idx
);
1189 /* Ignore invalid image specifications. */
1190 if (!valid_image_p
(image))
1192 NSLog
(@"Invalid
image for toolbar item"
);
1196 img_id
= lookup_image
(f
, image);
1197 img
= IMAGE_FROM_ID
(f
, img_id
);
1198 prepare_image_for_display
(f
, img
);
1200 if (img
->load_failed_p || img
->pixmap
== nil
)
1202 NSLog
(@"Could not prepare toolbar
image for display."
);
1206 helpObj
= TOOLPROP
(TOOL_BAR_ITEM_HELP
);
1208 helpObj
= TOOLPROP
(TOOL_BAR_ITEM_CAPTION
);
1209 helpText
= NILP
(helpObj
) ? ""
: (char *)SDATA
(helpObj
);
1211 [toolbar addDisplayItemWithImage
: img
->pixmap idx
: i helpText
: helpText
1212 enabled
: enabled_p
];
1216 if (![toolbar isVisible
])
1217 [toolbar setVisible
: YES
];
1219 if ([toolbar changed
])
1221 /* inform app that toolbar has changed */
1222 NSDictionary
*dict
= [toolbar configurationDictionary
];
1223 NSMutableDictionary
*newDict
= [dict mutableCopy
];
1224 NSEnumerator
*keys
= [[dict allKeys
] objectEnumerator
];
1226 while ((key
= [keys nextObject
]) != nil
)
1228 NSObject
*val
= [dict objectForKey
: key
];
1229 if ([val isKindOfClass
: [NSArray
class]])
1232 [toolbar toolbarDefaultItemIdentifiers
: toolbar
]
1237 [toolbar setConfigurationFromDictionary
: newDict
];
1244 /* ==========================================================================
1246 Toolbar: class implementation
1248 ========================================================================== */
1250 @implementation EmacsToolbar
1252 - initForView
: (EmacsView
*)view withIdentifier
: (NSString
*)identifier
1254 self
= [super initWithIdentifier
: identifier
];
1256 [self setDisplayMode
: NSToolbarDisplayModeIconOnly
];
1257 [self setSizeMode
: NSToolbarSizeModeSmall
];
1258 [self setDelegate
: self
];
1259 identifierToItem
= [[NSMutableDictionary alloc
] initWithCapacity
: 10];
1260 activeIdentifiers
= [[NSMutableArray alloc
] initWithCapacity
: 8];
1261 prevEnablement
= enablement
= 0L;
1267 [prevIdentifiers release
];
1268 [activeIdentifiers release
];
1269 [identifierToItem release
];
1273 - (void
) clearActive
1275 [prevIdentifiers release
];
1276 prevIdentifiers
= [activeIdentifiers copy
];
1277 [activeIdentifiers removeAllObjects
];
1278 prevEnablement
= enablement
;
1284 return [activeIdentifiers isEqualToArray
: prevIdentifiers
] &&
1285 enablement
== prevEnablement ? NO
: YES
;
1288 - (void
) addDisplayItemWithImage
: (EmacsImage
*)img idx
: (int
)idx
1289 helpText
: (char *)help enabled
: (BOOL
)enabled
1291 /* 1) come up w/identifier */
1292 NSString
*identifier
1293 = [NSString stringWithFormat
: @"
%u", [img hash]];
1295 /* 2) create / reuse item */
1296 NSToolbarItem
*item
= [identifierToItem objectForKey
: identifier
];
1299 item
= [[[NSToolbarItem alloc
] initWithItemIdentifier
: identifier
]
1301 [item setImage
: img
];
1302 [item setToolTip
: [NSString stringWithCString
: help]];
1303 [item setTarget
: emacsView
];
1304 [item setAction
: @selector
(toolbarClicked
:)];
1308 [item setEnabled
: enabled
];
1310 /* 3) update state */
1311 [identifierToItem setObject
: item forKey
: identifier
];
1312 [activeIdentifiers addObject
: identifier
];
1313 enablement
= (enablement
<< 1) |
(enabled
== YES
);
1316 /* This overrides super's implementation, which automatically sets
1317 all items to enabled state (for some reason). */
1318 - (void
)validateVisibleItems
{ }
1321 /* delegate methods */
1323 - (NSToolbarItem
*)toolbar
: (NSToolbar
*)toolbar
1324 itemForItemIdentifier
: (NSString
*)itemIdentifier
1325 willBeInsertedIntoToolbar
: (BOOL
)flag
1327 /* look up NSToolbarItem by identifier and return... */
1328 return [identifierToItem objectForKey
: itemIdentifier
];
1331 - (NSArray
*)toolbarDefaultItemIdentifiers
: (NSToolbar
*)toolbar
1333 /* return entire set.. */
1334 return activeIdentifiers
;
1337 /* for configuration palette (not yet supported) */
1338 - (NSArray
*)toolbarAllowedItemIdentifiers
: (NSToolbar
*)toolbar
1340 /* return entire set... */
1341 return [identifierToItem allKeys
];
1344 /* optional and unneeded */
1345 /* - toolbarWillAddItem: (NSNotification *)notification { } */
1346 /* - toolbarDidRemoveItem: (NSNotification *)notification { } */
1347 /* - (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar */
1349 @
end /* EmacsToolbar */
1353 /* ==========================================================================
1355 Tooltip: class implementation
1357 ========================================================================== */
1359 /* Needed because NeXTstep does not provide enough control over tooltip
1361 @implementation EmacsTooltip
1365 NSColor
*col
= [NSColor colorWithCalibratedRed
: 1.0 green
: 1.0
1366 blue
: 0.792 alpha
: 0.95];
1367 NSFont
*font
= [NSFont toolTipsFontOfSize
: 0];
1368 NSFont
*sfont
= [font screenFont
];
1369 int height
= [sfont ascender
] - [sfont descender
];
1370 /*[font boundingRectForFont].size.height; */
1371 NSRect r
= NSMakeRect
(0, 0, 100, height
+6);
1373 textField
= [[NSTextField alloc
] initWithFrame
: r
];
1374 [textField setFont
: font
];
1375 [textField setBackgroundColor
: col
];
1377 [textField setEditable
: NO
];
1378 [textField setSelectable
: NO
];
1379 [textField setBordered
: YES
];
1380 [textField setBezeled
: YES
];
1381 [textField setDrawsBackground
: YES
];
1383 win
= [[NSWindow alloc
]
1384 initWithContentRect
: [textField frame
]
1386 backing
: NSBackingStoreBuffered
1388 [win setReleasedWhenClosed
: NO
];
1389 [win setDelegate
: self
];
1390 [[win contentView
] addSubview
: textField
];
1391 /* [win setBackgroundColor: col]; */
1392 [win setOpaque
: NO
];
1401 [textField release
];
1405 - (void
) setText
: (char *)text
1407 NSString
*str
= [NSString stringWithUTF8String
: text];
1408 NSRect r
= [textField frame
];
1409 r.
size.width
= [[[textField font
] screenFont
] widthOfString
: str
] + 8;
1410 [textField setFrame
: r
];
1411 [textField setStringValue
: str
];
1414 - (void
) showAtX
: (int
)x Y
: (int
)y
for: (int
)seconds
1416 NSRect wr
= [win frame
];
1418 wr.origin
= NSMakePoint
(x
, y
);
1419 wr.
size = [textField frame
].
size;
1421 [win setFrame
: wr display
: YES
];
1422 [win orderFront
: self
];
1424 timer
= [NSTimer scheduledTimerWithTimeInterval
: (float
)seconds target
: self
1425 selector
: @selector
(hide
)
1426 userInfo
: nil repeats
: NO
];
1435 if ([timer isValid
])
1444 return timer
!= nil
;
1449 return [textField frame
];
1452 @
end /* EmacsTooltip */
1456 /* ==========================================================================
1458 Popup Dialog: implementing functions
1460 ========================================================================== */
1463 ns_popup_dialog
(Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
1466 Lisp_Object window
, tem
;
1471 NSTRACE
(x
-popup
-dialog);
1475 isQ
= NILP
(header
);
1477 if (EQ
(position
, Qt
))
1479 window
= selected_window
;
1481 else if (CONSP
(position
))
1484 tem
= Fcar
(position
);
1485 if (XTYPE
(tem
) == Lisp_Cons
)
1486 window
= Fcar
(Fcdr
(position
));
1489 tem
= Fcar
(Fcdr
(position
)); /* EVENT_START (position) */
1490 window
= Fcar
(tem
); /* POSN_WINDOW (tem) */
1493 else if (FRAMEP
(position
))
1499 CHECK_LIVE_WINDOW
(position
);
1503 if (FRAMEP
(window
))
1504 f
= XFRAME
(window
);
1507 CHECK_LIVE_WINDOW
(window
);
1508 f
= XFRAME
(WINDOW_FRAME
(XWINDOW
(window
)));
1510 p.x
= (int
)f
->left_pos
+ ((int
)FRAME_COLUMN_WIDTH
(f
) * f
->text_cols
)/2;
1511 p.y
= (int
)f
->top_pos
+ (FRAME_LINE_HEIGHT
(f
) * f
->text_lines
)/2;
1512 dialog = [[EmacsDialogPanel alloc
] initFromContents
: contents
1515 tem
= [dialog runDialogAt
: p
];
1519 [[FRAME_NS_VIEW
(SELECTED_FRAME
()) window
] makeKeyWindow
];
1524 /* ==========================================================================
1526 Popup Dialog: class implementation
1528 ========================================================================== */
1530 @interface FlippedView
: NSView
1535 @implementation FlippedView
1542 @implementation EmacsDialogPanel
1545 #define ICONSIZE
64.0
1546 #define TEXTHEIGHT
20.0
1547 #define MINCELLWIDTH
90.0
1549 - initWithContentRect
: (NSRect
)contentRect styleMask
: (unsigned int
)aStyle
1550 backing
: (NSBackingStoreType
)backingType defer
: (BOOL
)flag
1552 NSSize spacing
= {SPACER
, SPACER
};
1554 char this_cmd_name
[80];
1556 static NSImageView
*imgView
;
1557 static FlippedView
*contentView
;
1562 area.origin.x
= 3*SPACER
;
1563 area.origin.y
= 2*SPACER
;
1564 area.
size.width
= ICONSIZE
;
1565 area.
size.height
= ICONSIZE
;
1566 img
= [[NSImage imageNamed
: @"NSApplicationIcon"
] copy
];
1567 [img setScalesWhenResized
: YES
];
1568 [img setSize
: NSMakeSize
(ICONSIZE
, ICONSIZE
)];
1569 imgView
= [[NSImageView alloc
] initWithFrame
: area
];
1570 [imgView setImage
: img
];
1571 [imgView setEditable
: NO
];
1575 aStyle
= NSTitledWindowMask
;
1579 [super initWithContentRect
: contentRect styleMask
: aStyle
1580 backing
: backingType defer
: flag];
1581 contentView
= [[FlippedView alloc
] initWithFrame
: [[self contentView
] frame
]];
1582 [self setContentView
: contentView
];
1584 [[self contentView
] setAutoresizesSubviews
: YES
];
1586 [[self contentView
] addSubview
: imgView
];
1587 [self setTitle
: @""
];
1589 area.origin.x
+= ICONSIZE
+2*SPACER
;
1590 /* area.origin.y = TEXTHEIGHT; ICONSIZE/2-10+SPACER; */
1591 area.
size.width
= 400;
1592 area.
size.height
= TEXTHEIGHT
;
1593 command
= [[[NSTextField alloc
] initWithFrame
: area
] autorelease
];
1594 [[self contentView
] addSubview
: command
];
1595 [command setStringValue
: @"Emacs"
];
1596 [command setDrawsBackground
: NO
];
1597 [command setBezeled
: NO
];
1598 [command setSelectable
: NO
];
1599 [command setFont
: [NSFont boldSystemFontOfSize
: 13.0]];
1601 /* area.origin.x = ICONSIZE+2*SPACER;
1602 area.origin.y = TEXTHEIGHT + 2*SPACER;
1603 area.size.width = 400;
1604 area.size.height= 2;
1605 tem = [[[NSBox alloc] initWithFrame: area] autorelease];
1606 [[self contentView] addSubview: tem];
1607 [tem setTitlePosition: NSNoTitle];
1608 [tem setAutoresizingMask: NSViewWidthSizable];*/
1610 /* area.origin.x = ICONSIZE+2*SPACER; */
1611 area.origin.y
+= TEXTHEIGHT
+SPACER
;
1612 area.
size.width
= 400;
1613 area.
size.height
= TEXTHEIGHT
;
1614 title = [[[NSTextField alloc
] initWithFrame
: area
] autorelease
];
1615 [[self contentView
] addSubview
: title];
1616 [title setDrawsBackground
: NO
];
1617 [title setBezeled
: NO
];
1618 [title setSelectable
: NO
];
1619 [title setFont
: [NSFont systemFontOfSize
: 11.0]];
1621 cell = [[[NSButtonCell alloc
] initTextCell
: @""
] autorelease
];
1622 [cell setBordered
: NO
];
1623 [cell setEnabled
: NO
];
1624 [cell setCellAttribute
: NSCellIsInsetButton to
: 8];
1625 [cell setBezelStyle
: NSRoundedBezelStyle
];
1627 matrix
= [[NSMatrix alloc
] initWithFrame
: contentRect
1628 mode
: NSHighlightModeMatrix
1631 numberOfColumns
: 1];
1632 [[self contentView
] addSubview
: matrix
];
1634 [matrix setFrameOrigin
: NSMakePoint
(area.origin.x
,
1635 area.origin.y
+ (TEXTHEIGHT
+3*SPACER
))];
1636 [matrix setIntercellSpacing
: spacing
];
1638 [self setOneShot
: YES
];
1639 [self setReleasedWhenClosed
: YES
];
1640 [self setHidesOnDeactivate
: YES
];
1645 - (BOOL
)windowShouldClose
: (id
)sender
1647 [NSApp stopModalWithCode
: XHASH
(Qnil
)]; // FIXME
: BIG UGLY HACK
!!
1652 void process_dialog
(id window
, Lisp_Object list
)
1657 for (; XTYPE
(list
) == Lisp_Cons
; list
= XCDR
(list
))
1660 if (XTYPE
(item
) == Lisp_String
)
1662 [window addString
: XSTRING
(item
)->data row
: row
++];
1664 else if (XTYPE
(item
) == Lisp_Cons
)
1666 [window addButton
: XSTRING
(XCAR
(item
))->data
1667 value
: XCDR
(item
) row
: row
++];
1669 else if (NILP
(item
))
1678 - addButton
: (char *)str value
: (Lisp_Object
)val row
: (int
)row
1687 cell = [matrix cellAtRow
: row column
: cols
-1];
1688 [cell setTarget
: self
];
1689 [cell setAction
: @selector
(clicked
: )];
1690 [cell setTitle
: [NSString stringWithUTF8String
: str
]];
1691 [cell setTag
: XHASH
(val
)]; // FIXME
: BIG UGLY HACK
!!
1692 [cell setBordered
: YES
];
1693 [cell setEnabled
: YES
];
1699 - addString
: (char *)str row
: (int
)row
1708 cell = [matrix cellAtRow
: row column
: cols
-1];
1709 [cell setTitle
: [NSString stringWithUTF8String
: str
]];
1710 [cell setBordered
: YES
];
1711 [cell setEnabled
: NO
];
1727 NSArray
*sellist
= nil
;
1730 sellist
= [sender selectedCells
];
1731 if ([sellist count
]<1)
1734 seltag
= [[sellist objectAtIndex
: 0] tag
];
1735 if (seltag
== XHASH
(Qundefined
)) // FIXME
: BIG UGLY HACK
!!
1736 [NSApp stopModalWithCode
: seltag
];
1741 - initFromContents
: (Lisp_Object
)contents isQuestion
: (BOOL
)isQ
1746 if (XTYPE
(contents
) == Lisp_Cons
)
1748 head
= Fcar
(contents
);
1749 process_dialog
(self
, Fcdr
(contents
));
1754 if (XTYPE
(head
) == Lisp_String
)
1755 [title setStringValue
:
1756 [NSString stringWithUTF8String
: XSTRING
(head
)->data
]];
1757 else if (isQ
== YES
)
1758 [title setStringValue
: @"Question"
];
1760 [title setStringValue
: @"Information"
];
1766 if (cols
== 1 && rows
> 1) /* Never told where to split */
1769 for (i
= 0; i
<rows
/2; i
++)
1771 [matrix putCell
: [matrix cellAtRow
: (rows
+1)/2 column
: 0]
1772 atRow
: i column
: 1];
1773 [matrix removeRow
: (rows
+1)/2];
1779 NSSize csize
= [matrix cellSize
];
1780 if (csize.width
< MINCELLWIDTH
)
1782 csize.width
= MINCELLWIDTH
;
1783 [matrix setCellSize
: csize
];
1784 [matrix sizeToCells
];
1789 [command sizeToFit
];
1793 if (r.
size.width
+r.origin.x
> t.
size.width
+t.origin.x
)
1795 t.origin.x
= r.origin.x
;
1796 t.
size.width
= r.
size.width
;
1798 r
= [command frame
];
1799 if (r.
size.width
+r.origin.x
> t.
size.width
+t.origin.x
)
1801 t.origin.x
= r.origin.x
;
1802 t.
size.width
= r.
size.width
;
1806 s
= [(NSView
*)[self contentView
] frame
];
1807 r.
size.width
+= t.origin.x
+t.
size.width
+2*SPACER
-s.
size.width
;
1808 r.
size.height
+= t.origin.y
+t.
size.height
+SPACER
-s.
size.height
;
1809 [self setFrame
: r display
: NO
];
1818 { [super dealloc
]; return; };
1822 - (Lisp_Object
)runDialogAt
: (NSPoint
)p
1825 NSModalSession session
;
1828 [self center
]; /*XXX p ignored? */
1829 [self orderFront
: NSApp
];
1831 session
= [NSApp beginModalSessionForWindow
: self
];
1832 while ((ret
= [NSApp runModalSession
: session
]) == NSRunContinuesResponse
)
1834 (e
= [NSApp nextEventMatchingMask
: NSAnyEventMask
1835 untilDate
: [NSDate distantFuture
]
1836 inMode
: NSEventTrackingRunLoopMode
1838 /*fprintf (stderr, "ret = %d\te = %p\n", ret, e); */
1840 [NSApp endModalSession
: session
];
1842 { // FIXME
: BIG UGLY HACK
!!!
1844 *(EMACS_INT
*)(&tmp
) = ret
;
1853 /* ==========================================================================
1857 ========================================================================== */
1859 DEFUN
("ns
-reset-menu"
, Fns_reset_menu
, Sns_reset_menu
, 0, 0, 0,
1860 doc: /* Cause the NS menu to be re-calculated. */)
1863 set_frame_menubar
(SELECTED_FRAME
(), 1, 0);
1868 DEFUN
("x
-popup
-menu"
, Fx_popup_menu
, Sx_popup_menu
, 2, 2, 0,
1869 doc: /* Pop up a deck-of-cards menu and return user's selection.
1870 POSITION is a position specification. This is either a mouse button event
1871 or a list ((XOFFSET YOFFSET) WINDOW)
1872 where XOFFSET and YOFFSET are positions in pixels from the top left
1873 corner of WINDOW. (WINDOW may be a window or a frame object.)
1874 This controls the position of the top left of the menu as a whole.
1875 If POSITION is t, it means to use the current mouse position.
1877 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
1878 The menu items come from key bindings that have a menu string as well as
1879 a definition; actually, the \"definition\" in such a key binding looks like
1880 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
1881 the keymap as a top-level element.
1883 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
1884 Otherwise, REAL-DEFINITION should be a valid key binding definition.
1886 You can also use a list of keymaps as MENU.
1887 Then each keymap makes a separate pane.
1889 When MENU is a keymap or a list of keymaps, the return value is the
1890 list of events corresponding to the user's choice. Note that
1891 `x-popup-menu' does not actually execute the command bound to that
1894 Alternatively, you can specify a menu of multiple panes
1895 with a list of the form (TITLE PANE1 PANE2...),
1896 where each pane is a list of form (TITLE ITEM1 ITEM2...).
1897 Each ITEM is normally a cons cell (STRING . VALUE);
1898 but a string can appear as an item--that makes a nonselectable line
1900 With this form of menu, the return value is VALUE from the chosen item. */)
1902 Lisp_Object position
, menu;
1904 return ns_popup_menu
(position
, menu);
1908 DEFUN
("x
-popup
-dialog"
, Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
1909 doc: /* Pop up a dialog box and return user's selection.
1910 POSITION specifies which frame to use.
1911 This is normally a mouse button event or a window or frame.
1912 If POSITION is t, it means to use the frame the mouse is on.
1913 The dialog box appears in the middle of the specified frame.
1915 CONTENTS specifies the alternatives to display in the dialog box.
1916 It is a list of the form (DIALOG ITEM1 ITEM2...).
1917 Each ITEM is a cons cell (STRING . VALUE).
1918 The return value is VALUE from the chosen item.
1920 An ITEM may also be just a string--that makes a nonselectable item.
1921 An ITEM may also be nil--that means to put all preceding items
1922 on the left of the dialog box and all following items on the right.
1923 \(By default, approximately half appear on each side.)
1925 If HEADER is non-nil, the frame title for the box is "Information",
1926 otherwise it is "Question".
1928 If the user gets rid of the dialog box without making a valid choice,
1929 for instance using the window manager, then this produces a quit and
1930 `x-popup-dialog' does not return. */)
1931 (position
, contents
, header
)
1932 Lisp_Object position
, contents
, header
;
1934 return ns_popup_dialog
(position
, contents
, header
);
1938 /* ==========================================================================
1940 Lisp interface declaration
1942 ========================================================================== */
1947 defsubr
(&Sx_popup_menu
);
1948 defsubr
(&Sx_popup_dialog
);
1949 defsubr
(&Sns_reset_menu
);
1950 staticpro
(&menu_items
);
1953 Qdebug_on_next_call
= intern
("
debug-on
-next
-call"
);
1954 staticpro
(&Qdebug_on_next_call
);
1957 // arch
-tag
: 75773656-52e5
-4c44
-a398
-47bd87b32619