1 /* NeXT/Open/GNUstep and MacOSX Cocoa menu and toolbar module.
2 Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 By Adrian Robert, based on code from original nsmenu.m (Carl Edman,
21 Christian Limpach, Scott Bender, Christophe de Dinechin) and code in the
22 Carbon version by Yamamoto Mitsuharu. */
24 /* This should be the first include, as it may set up #defines affecting
25 interpretation of even the system includes. */
34 #include "blockinput.h"
36 #include "termhooks.h"
39 #define NSMENUPROFILE
0
42 #include
<sys
/timeb.h
>
43 #include
<sys
/types.h
>
46 #define MenuStagger
10.0
49 int menu_trace_num
= 0;
50 #define NSTRACE
(x
) fprintf (stderr
, "
%s:%d: [%d] " #x "\n", \
51 __FILE__
, __LINE__
, ++menu_trace_num
)
57 /* Include lisp -> C common menu parsing code */
58 #define ENCODE_MENU_STRING
(str
) ENCODE_UTF_8
(str
)
59 #include "nsmenu_common.c"
62 extern Lisp_Object Qundefined
, Qmenu_enable
, Qmenu_bar_update_hook
;
63 extern Lisp_Object QCtoggle
, QCradio
;
65 extern Lisp_Object Vmenu_updating_frame
;
67 Lisp_Object Qdebug_on_next_call
;
68 extern Lisp_Object Voverriding_local_map
, Voverriding_local_map_menu_flag
,
69 Qoverriding_local_map
, Qoverriding_terminal_local_map
;
71 extern
long context_menu_value
;
72 EmacsMenu
*mainMenu
, *svcsMenu
, *dockMenu
;
74 /* Nonzero means a menu is currently active. */
75 static int popup_activated_flag
;
77 /* NOTE: toolbar implementation is at end,
78 following complete menu implementation. */
81 /* ==========================================================================
83 Menu: Externally-called functions
85 ========================================================================== */
88 /* FIXME: not currently used, but should normalize with other terms. */
90 x_activate_menubar
(struct frame
*f
)
92 fprintf (stderr
, "XXX
: Received x_activate_menubar event.
\n"
);
96 /* Supposed to discard menubar and free storage. Since we share the
97 menubar among frames and update its context for the focused window,
98 there is nothing to do here. */
100 free_frame_menubar
(struct frame
*f
)
109 return popup_activated_flag
;
113 /* --------------------------------------------------------------------------
114 Update menubar. Three cases:
115 1) deep_p = 0, submenu = nil: Fresh switch onto a frame -- either set up
116 just top-level menu strings (OS X), or goto case (2) (GNUstep).
117 2) deep_p = 1, submenu = nil: Recompute all submenus.
118 3) deep_p = 1, submenu = non-nil: Update contents of a single submenu.
119 -------------------------------------------------------------------------- */
121 ns_update_menubar
(struct frame
*f
, int deep_p
, EmacsMenu
*submenu
)
123 NSAutoreleasePool
*pool
;
124 id
menu = [NSApp mainMenu
];
125 static EmacsMenu
*last_submenu
= nil
;
127 const
char *submenuTitle
= [[submenu
title] UTF8String
];
128 extern int waiting_for_input
;
131 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
139 NSTRACE
(set_frame_menubar
);
141 if (f
!= SELECTED_FRAME
())
143 XSETFRAME
(Vmenu_updating_frame
, f
);
144 /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */
147 pool
= [[NSAutoreleasePool alloc
] init
];
149 /* Menu may have been created automatically; if so, discard it. */
150 if ([menu isKindOfClass
: [EmacsMenu
class]] == NO
)
158 menu = [[EmacsMenu alloc
] initWithTitle
: @"Emacs"
];
162 { /* close up anything on there */
163 id attMenu
= [menu attachedMenu
];
170 t
= -(1000*tb.time
+tb.millitm
);
173 /* widget_value is a straightforward object translation of emacs's
174 Byzantine lisp menu structures */
175 wv
= xmalloc_widget_value
();
179 wv
->button_type
= BUTTON_TYPE_NONE
;
183 #ifdef NS_IMPL_GNUSTEP
184 deep_p
= 1; /* until GNUstep NSMenu implements the Panther delegation model */
189 /* Fully parse one or more of the submenus. */
191 int
*submenu_start
, *submenu_end
;
192 int
*submenu_top_level_items
, *submenu_n_panes
;
193 struct buffer
*prev
= current_buffer
;
195 int specpdl_count
= SPECPDL_INDEX
();
196 int previous_menu_items_used
= f
->menu_bar_items_used
;
197 Lisp_Object
*previous_items
198 = (Lisp_Object
*) alloca
(previous_menu_items_used
199 * sizeof
(Lisp_Object
));
201 /* lisp preliminaries */
202 buffer
= XWINDOW
(FRAME_SELECTED_WINDOW
(f
))->buffer
;
203 specbind
(Qinhibit_quit
, Qt
);
204 specbind
(Qdebug_on_next_call
, Qnil
);
205 record_unwind_save_match_data
();
206 if (NILP
(Voverriding_local_map_menu_flag
))
208 specbind
(Qoverriding_terminal_local_map
, Qnil
);
209 specbind
(Qoverriding_local_map
, Qnil
);
211 set_buffer_internal_1
(XBUFFER
(buffer
));
213 /* TODO: for some reason this is not needed in other terms,
214 but some menu updates call Info-extract-pointer which causes
215 abort-on-error if waiting-for-input. Needs further investigation. */
216 owfi
= waiting_for_input
;
217 waiting_for_input
= 0;
219 /* lucid hook and possible reset */
220 safe_run_hooks
(Qactivate_menubar_hook
);
221 if (! NILP
(Vlucid_menu_bar_dirty_flag
))
222 call0
(Qrecompute_lucid_menubar
);
223 safe_run_hooks
(Qmenu_bar_update_hook
);
224 FRAME_MENU_BAR_ITEMS
(f
) = menu_bar_items
(FRAME_MENU_BAR_ITEMS
(f
));
226 /* Now ready to go */
227 items
= FRAME_MENU_BAR_ITEMS
(f
);
229 /* Save the frame's previous menu bar contents data */
230 if (previous_menu_items_used
)
231 bcopy
(XVECTOR
(f
->menu_bar_vector
)->contents
, previous_items
,
232 previous_menu_items_used
* sizeof
(Lisp_Object
));
234 /* parse stage 1: extract from lisp */
237 menu_items
= f
->menu_bar_vector
;
238 menu_items_allocated
= VECTORP
(menu_items
) ? ASIZE
(menu_items
) : 0;
239 submenu_start
= (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
*));
240 submenu_end
= (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
*));
241 submenu_n_panes
= (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
));
242 submenu_top_level_items
243 = (int
*) alloca
(XVECTOR
(items
)->size * sizeof
(int
*));
245 for (i
= 0; i
< XVECTOR
(items
)->size; i
+= 4)
247 Lisp_Object key
, string
, maps
;
249 key
= XVECTOR
(items
)->contents
[i
];
250 string
= XVECTOR
(items
)->contents
[i
+ 1];
251 maps
= XVECTOR
(items
)->contents
[i
+ 2];
255 /* FIXME: we'd like to only parse the needed submenu, but this
256 was causing crashes in the _common parsing code.. need to make
257 sure proper initialization done.. */
258 /* if (submenu && strcmp (submenuTitle, SDATA (string)))
261 submenu_start
[i
] = menu_items_used
;
263 menu_items_n_panes
= 0;
264 submenu_top_level_items
[i
] = parse_single_submenu
(key
, string
, maps
);
265 submenu_n_panes
[i
] = menu_items_n_panes
;
266 submenu_end
[i
] = menu_items_used
;
270 finish_menu_items
();
271 waiting_for_input
= owfi
;
274 if (submenu
&& n
== 0)
276 /* should have found a menu for this one but didn't */
277 fprintf (stderr
, "
ERROR: did not
find lisp
menu for submenu
'%s'.
\n"
,
279 discard_menu_items
();
280 unbind_to
(specpdl_count
, Qnil
);
286 /* parse stage 2: insert into lucid 'widget_value' structures
287 [comments in other terms say not to evaluate lisp code here] */
288 wv
= xmalloc_widget_value
();
289 wv
->name
= "menubar"
;
292 wv
->button_type
= BUTTON_TYPE_NONE
;
296 for (i
= 0; i
< 4*n
; i
+= 4)
298 menu_items_n_panes
= submenu_n_panes
[i
];
299 wv
= digest_single_submenu
(submenu_start
[i
], submenu_end
[i
],
300 submenu_top_level_items
[i
]);
304 first_wv
->contents
= wv
;
305 /* Don't set wv->name here; GC during the loop might relocate it. */
307 wv
->button_type
= BUTTON_TYPE_NONE
;
311 set_buffer_internal_1
(prev
);
313 /* Compare the new menu items with previous, and leave off if no change */
314 /* FIXME: following other terms here, but seems like this should be
315 done before parse stage 2 above, since its results aren't used */
316 if (previous_menu_items_used
317 && (!submenu ||
(submenu
&& submenu
== last_submenu
))
318 && menu_items_used
== previous_menu_items_used
)
320 for (i
= 0; i
< previous_menu_items_used
; i
++)
321 /* FIXME: this ALWAYS fails on Buffers menu items.. something
322 about their strings causes them to change every time, so we
323 double-check failures */
324 if (!EQ
(previous_items
[i
], XVECTOR
(menu_items
)->contents
[i
]))
325 if (!(STRINGP
(previous_items
[i
])
326 && STRINGP
(XVECTOR
(menu_items
)->contents
[i
])
327 && !strcmp (SDATA
(previous_items
[i
]),
328 SDATA
(XVECTOR
(menu_items
)->contents
[i
]))))
330 if (i
== previous_menu_items_used
)
336 t
+= 1000*tb.time
+tb.millitm
;
337 fprintf (stderr
, "NO CHANGE
! CUTTING OUT after
%ld msec.\n", t);
340 free_menubar_widget_value_tree
(first_wv
);
341 discard_menu_items
();
342 unbind_to
(specpdl_count
, Qnil
);
348 /* The menu items are different, so store them in the frame */
349 /* FIXME: this is not correct for single-submenu case */
350 f
->menu_bar_vector
= menu_items
;
351 f
->menu_bar_items_used
= menu_items_used
;
353 /* Calls restore_menu_items, etc., as they were outside */
354 unbind_to
(specpdl_count
, Qnil
);
356 /* Parse stage 2a: now GC cannot happen during the lifetime of the
357 widget_value, so it's safe to store data from a Lisp_String */
358 wv
= first_wv
->contents
;
359 for (i
= 0; i
< XVECTOR
(items
)->size; i
+= 4)
362 string
= XVECTOR
(items
)->contents
[i
+ 1];
365 /* if (submenu && strcmp (submenuTitle, SDATA (string)))
368 wv
->name
= (char *) SDATA
(string
);
369 update_submenu_strings
(wv
->contents
);
373 /* Now, update the NS menu; if we have a submenu, use that, otherwise
374 create a new menu for each sub and fill it. */
377 for (wv
= first_wv
->contents
; wv
; wv
= wv
->next
)
379 if (!strcmp (submenuTitle
, wv
->name
))
381 [submenu fillWithWidgetValue
: wv
->contents
];
382 last_submenu
= submenu
;
389 [menu fillWithWidgetValue
: first_wv
->contents
];
395 static int n_previous_strings
= 0;
396 static
char previous_strings
[100][10];
397 static
struct frame
*last_f
= NULL;
401 /* Make widget-value tree w/ just the top level menu bar strings */
402 items
= FRAME_MENU_BAR_ITEMS
(f
);
411 /* check if no change.. this mechanism is a bit rough, but ready */
412 n
= XVECTOR
(items
)->size / 4;
413 if (f
== last_f
&& n_previous_strings
== n
)
415 for (i
= 0; i
<n
; i
++)
417 string
= AREF
(items
, 4*i
+1);
419 if (EQ
(string
, make_number
(0))) // FIXME
: Why???
--Stef
422 if (previous_strings
[i
][0])
426 if (strncmp
(previous_strings
[i
], SDATA
(string
), 10))
439 for (i
= 0; i
< XVECTOR
(items
)->size; i
+= 4)
441 string
= XVECTOR
(items
)->contents
[i
+ 1];
446 strncpy
(previous_strings
[i
/4], SDATA
(string
), 10);
448 wv
= xmalloc_widget_value
();
449 wv
->name
= (char *) SDATA
(string
);
452 wv
->button_type
= BUTTON_TYPE_NONE
;
454 wv
->call_data
= (void
*) (EMACS_INT
) (-1);
457 /* we'll update the real copy under app menu when time comes */
458 if (!strcmp ("Services"
, wv
->name
))
460 /* but we need to make sure it will update on demand */
461 [svcsMenu setFrame
: f
];
462 [svcsMenu setDelegate
: svcsMenu
];
466 [menu addSubmenuWithTitle
: wv
->name forFrame
: f
];
471 first_wv
->contents
= wv
;
477 n_previous_strings
= n
;
479 n_previous_strings
= 0;
482 free_menubar_widget_value_tree
(first_wv
);
487 t
+= 1000*tb.time
+tb.millitm
;
488 fprintf (stderr
, "
Menu update took
%ld msec.\n", t);
493 [NSApp setMainMenu
: menu];
501 /* Main emacs core entry point for menubar menus: called to indicate that the
502 frame's menus have changed, and the *step representation should be updated
505 set_frame_menubar
(struct frame
*f
, int first_time
, int deep_p
)
507 ns_update_menubar
(f
, deep_p
, nil
);
511 /* Utility (from macmenu.c): is this item a separator? */
513 name_is_separator
(name
)
516 const
char *start
= name
;
518 /* Check if name string consists of only dashes ('-'). */
519 while (*name
== '-') name
++;
520 /* Separators can also be of the form "--:TripleSuperMegaEtched"
521 or "--deep-shadow". We don't implement them yet, se we just treat
522 them like normal separators. */
523 return (*name
== '\0' || start
+ 2 == name
);
527 /* ==========================================================================
529 Menu: class implementation
531 ========================================================================== */
534 /* Menu that can define itself from Emacs "widget_value"s and will lazily
535 update itself when user clicked. Based on Carbon/AppKit implementation
536 by Yamamoto Mitsuharu. */
537 @implementation EmacsMenu
539 /* override designated initializer */
540 - initWithTitle
: (NSString
*)title
542 if (self
= [super initWithTitle
: title])
543 [self setAutoenablesItems
: NO
];
548 /* used for top-level */
549 - initWithTitle
: (NSString
*)title frame
: (struct frame
*)f
551 [self initWithTitle
: title];
554 [self setDelegate
: self
];
560 - (void
)setFrame
: (struct frame
*)f
566 /* delegate method called when a submenu is being opened: run a 'deep' call
567 to set_frame_menubar */
568 - (void
)menuNeedsUpdate
: (NSMenu
*)menu
570 NSEvent
*event
= [[FRAME_NS_VIEW
(frame
) window
] currentEvent
];
571 /* HACK: Cocoa/Carbon will request update on every keystroke
572 via IsMenuKeyEvent -> CheckMenusForKeyEvent. These are not needed
573 since key equivalents are handled through emacs.
574 On Leopard, even keystroke events generate SystemDefined events, but
575 their subtype is 8. */
576 if ([event
type] != NSSystemDefined ||
[event subtype
] == 8)
578 /*fprintf (stderr, "Updating menu '%s'\n", [[self title] UTF8String]); NSLog (@"%@\n", event); */
579 ns_update_menubar
(frame
, 1, self
);
583 - (BOOL
)performKeyEquivalent
: (NSEvent
*)theEvent
585 if (SELECTED_FRAME
() && FRAME_NS_P
(SELECTED_FRAME
())
586 && FRAME_NS_VIEW
(SELECTED_FRAME
()))
587 [FRAME_NS_VIEW
(SELECTED_FRAME
()) keyDown
: theEvent
];
592 /* Parse a widget_value's key rep (examples: 's-p', 's-S', '(C-x C-s)', '<f13>')
593 into an accelerator string. We are only able to display a single character
594 for an accelerator, together with an optional modifier combination. (Under
595 Carbon more control was possible, but in Cocoa multi-char strings passed to
596 NSMenuItem get ignored. For now we try to display a super-single letter
597 combo, and return the others as strings to be appended to the item title.
598 (This is signaled by setting keyEquivModMask to 0 for now.) */
599 -(NSString
*)parseKeyEquiv
: (char *)key
602 keyEquivModMask
= NSCommandKeyMask
;
604 if (!key ||
!strlen
(key
))
607 while (*tpos
== ' ' ||
*tpos
== '(')
610 keyEquivModMask
= 0; /* signal */
611 return [NSString stringWithUTF8String
: tpos
];
613 return [NSString stringWithFormat
: @"
%c", tpos[2]];
617 - (NSMenuItem
*)addItemWithWidgetValue
: (void
*)wvptr
620 widget_value
*wv
= (widget_value
*)wvptr
;
622 if (name_is_separator
(wv
->name
))
624 item
= [NSMenuItem separatorItem
];
625 [self addItem
: item
];
629 NSString
*title, *keyEq
;
630 title = [NSString stringWithUTF8String
: wv
->name
];
632 title = @"
< ?
>"
; /* (get out in the open so we know about it) */
634 keyEq
= [self parseKeyEquiv
: wv
->key
];
635 if (keyEquivModMask
== 0)
636 title = [title stringByAppendingFormat
: @"
(%@)", keyEq];
638 item
= [self addItemWithTitle
: (NSString
*)title
639 action
: @selector
(menuDown
:)
640 keyEquivalent
: keyEq
];
641 [item setKeyEquivalentModifierMask
: keyEquivModMask
];
643 [item setEnabled
: wv
->enabled
];
645 /* Draw radio buttons and tickboxes */
646 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE ||
647 wv
->button_type
== BUTTON_TYPE_RADIO
))
648 [item setState
: NSOnState
];
650 [item setState
: NSOffState
];
652 [item setTag
: (int
)wv
->call_data
];
664 for (n
= [self numberOfItems
]-1; n
>= 0; n
--)
666 NSMenuItem
*item
= [self itemAtIndex
: n
];
667 NSString
*title = [item
title];
668 if (([title length] == 0 ||
[@"Apple" isEqualToString
: title])
669 && ![item isSeparatorItem
])
671 [self removeItemAtIndex
: n
];
676 - (void
)fillWithWidgetValue
: (void
*)wvptr
678 widget_value
*wv
= (widget_value
*)wvptr
;
680 /* clear existing contents */
681 [self setMenuChangedMessagesEnabled
: NO
];
684 /* add new contents */
685 for (; wv
!= NULL; wv
= wv
->next
)
687 NSMenuItem
*item
= [self addItemWithWidgetValue
: wv
];
691 EmacsMenu
*submenu
= [[EmacsMenu alloc
] initWithTitle
: @"Submenu"
];
693 [self setSubmenu
: submenu forItem
: item
];
694 [submenu fillWithWidgetValue
: wv
->contents
];
696 [item setAction
: nil
];
700 [self setMenuChangedMessagesEnabled
: YES
];
701 #ifdef NS_IMPL_GNUSTEP
702 if ([[self window
] isVisible
])
705 if ([self supermenu
] == nil
)
711 /* adds an empty submenu and returns it */
712 - (EmacsMenu
*)addSubmenuWithTitle
: (char *)title forFrame
: (struct frame
*)f
714 NSString
*titleStr
= [NSString stringWithUTF8String
: title];
715 NSMenuItem
*item
= [self addItemWithTitle
: titleStr
716 action
: nil
/*@selector (menuDown:) */
718 EmacsMenu
*submenu
= [[EmacsMenu alloc
] initWithTitle
: titleStr frame
: f
];
719 [self setSubmenu
: submenu forItem
: item
];
724 /* run a menu in popup mode */
725 - (Lisp_Object
)runMenuAt
: (NSPoint
)p forFrame
: (struct frame
*)f
726 keymaps
: (int
)keymaps
728 EmacsView
*view = FRAME_NS_VIEW
(f
);
729 /* p = [view convertPoint:p fromView: nil]; */
730 p.y
= NSHeight
([view frame
]) - p.y
;
731 NSEvent
*e
= [[view window
] currentEvent
];
732 NSEvent
*event
= [NSEvent mouseEventWithType
: NSRightMouseDown
735 timestamp
: [e timestamp
]
736 windowNumber
: [[view window
] windowNumber
]
738 eventNumber
: 0/*[e eventNumber] */
743 context_menu_value
= -1;
744 [NSMenu popUpContextMenu
: self withEvent
: event forView
: view];
745 retVal
= context_menu_value
;
746 context_menu_value
= 0;
748 ? find_and_return_menu_selection
(f
, keymaps
, (void
*)retVal
)
756 /* ==========================================================================
758 Context Menu: implementing functions
760 ========================================================================== */
763 cleanup_popup_menu
(Lisp_Object arg
)
765 discard_menu_items
();
771 ns_popup_menu
(Lisp_Object position
, Lisp_Object
menu)
774 struct frame
*f
= NULL;
776 Lisp_Object window
, x
, y
, tem
, keymap
, title;
778 int specpdl_count
= SPECPDL_INDEX
(), specpdl_count2
;
779 char *error_name
= NULL;
781 widget_value
*wv
, *first_wv
= 0;
783 NSTRACE
(ns_popup_menu
);
785 if (!NILP
(position
))
789 if (EQ
(position
, Qt
)
790 ||
(CONSP
(position
) && (EQ
(XCAR
(position
), Qmenu_bar
)
791 || EQ
(XCAR
(position
), Qtool_bar
))))
793 /* Use the mouse's current position. */
794 struct frame
*new_f
= SELECTED_FRAME
();
796 if (FRAME_TERMINAL
(new_f
)->mouse_position_hook
)
797 (*FRAME_TERMINAL
(new_f
)->mouse_position_hook
)
798 (&new_f
, 0, 0, 0, &x
, &y
, 0);
800 XSETFRAME
(window
, new_f
);
803 window
= selected_window
;
810 CHECK_CONS
(position
);
811 tem
= Fcar
(position
);
812 if (XTYPE
(tem
) == Lisp_Cons
)
814 window
= Fcar
(Fcdr
(position
));
816 y
= Fcar
(Fcdr
(tem
));
820 tem
= Fcar
(Fcdr
(position
));
822 tem
= Fcar
(Fcdr
(Fcdr
(tem
)));
840 struct window
*win
= XWINDOW
(window
);
841 CHECK_LIVE_WINDOW
(window
);
842 f
= XFRAME
(WINDOW_FRAME
(win
));
843 p.x
= FRAME_COLUMN_WIDTH
(f
) * WINDOW_LEFT_EDGE_COL
(win
);
844 p.y
= FRAME_LINE_HEIGHT
(f
) * WINDOW_TOP_EDGE_LINE
(win
);
847 p.x
+= XINT
(x
); p.y
+= XINT
(y
);
849 XSETFRAME
(Vmenu_updating_frame
, f
);
852 { /* no position given */
853 /* FIXME: if called during dump, we need to stop precomputation of
854 key equivalents (see below) because the keydefs in ns-win.el have
855 not been loaded yet. */
858 Vmenu_updating_frame
= Qnil
;
861 /* now parse the lisp menus */
862 record_unwind_protect
(unuse_menu_items
, Qnil
);
866 /* Decode the menu items from what was specified. */
868 keymap
= get_keymap
(menu, 0, 0);
871 /* We were given a keymap. Extract menu info from the keymap. */
874 /* Extract the detailed info to make one pane. */
875 keymap_panes
(&menu, 1, NILP
(position
));
877 /* Search for a string appearing directly as an element of the keymap.
878 That string is the title of the menu. */
879 prompt
= Fkeymap_prompt
(keymap
);
880 title = NILP
(prompt
) ? build_string
("Select"
) : prompt
;
882 /* Make that be the pane title of the first pane. */
883 if (!NILP
(prompt
) && menu_items_n_panes
>= 0)
884 XVECTOR
(menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = prompt
;
888 else if (CONSP
(menu) && KEYMAPP
(XCAR
(menu)))
890 /* We were given a list of keymaps. */
891 int nmaps
= XFASTINT
(Flength
(menu));
893 = (Lisp_Object
*) alloca
(nmaps
* sizeof
(Lisp_Object
));
898 /* The first keymap that has a prompt string
899 supplies the menu title. */
900 for (tem
= menu, i
= 0; CONSP
(tem
); tem
= XCDR
(tem
))
904 maps
[i
++] = keymap
= get_keymap
(XCAR
(tem
), 1, 0);
906 prompt
= Fkeymap_prompt
(keymap
);
907 if (NILP
(title) && !NILP
(prompt
))
911 /* Extract the detailed info to make one pane. */
912 keymap_panes
(maps
, nmaps
, NILP
(position
));
914 /* Make the title be the pane title of the first pane. */
915 if (!NILP
(title) && menu_items_n_panes
>= 0)
916 XVECTOR
(menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = title;
922 /* We were given an old-fashioned menu. */
924 CHECK_STRING
(title);
926 list_of_panes
(Fcdr
(menu));
931 unbind_to
(specpdl_count
, Qnil
);
933 /* If no position given, that was a signal to just precompute and cache
934 key equivalents, which was a side-effect of what we just did. */
937 discard_menu_items
();
942 record_unwind_protect
(cleanup_popup_menu
, Qnil
);
945 /* now parse stage 2 as in ns_update_menubar */
946 wv
= xmalloc_widget_value
();
947 wv
->name
= "contextmenu"
;
950 wv
->button_type
= BUTTON_TYPE_NONE
;
954 specpdl_count2
= SPECPDL_INDEX
();
957 /* FIXME: a couple of one-line differences prevent reuse */
958 wv
= digest_single_submenu
(0, menu_items_used
, Qnil
);
961 widget_value
*save_wv
= 0, *prev_wv
= 0;
962 widget_value
**submenu_stack
963 = (widget_value
**) alloca
(menu_items_used
* sizeof
(widget_value
*));
964 /* Lisp_Object *subprefix_stack
965 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); */
966 int submenu_depth
= 0;
970 /* Loop over all panes and items, filling in the tree. */
972 while (i
< menu_items_used
)
974 if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qnil
))
976 submenu_stack
[submenu_depth
++] = save_wv
;
982 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qlambda
))
985 save_wv
= submenu_stack
[--submenu_depth
];
989 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qt
)
990 && submenu_depth
!= 0)
991 i
+= MENU_ITEMS_PANE_LENGTH
;
992 /* Ignore a nil in the item list.
993 It's meaningful only for dialog boxes. */
994 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qquote
))
996 else if (EQ
(XVECTOR
(menu_items
)->contents
[i
], Qt
))
998 /* Create a new pane. */
999 Lisp_Object pane_name
, prefix
;
1002 pane_name
= AREF
(menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1003 prefix
= AREF
(menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1005 #ifndef HAVE_MULTILINGUAL_MENU
1006 if (STRINGP
(pane_name
) && STRING_MULTIBYTE
(pane_name
))
1008 pane_name
= ENCODE_MENU_STRING
(pane_name
);
1009 ASET
(menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1012 pane_string
= (NILP
(pane_name
)
1013 ? ""
: (char *) SDATA
(pane_name
));
1014 /* If there is just one top-level pane, put all its items directly
1015 under the top-level menu. */
1016 if (menu_items_n_panes
== 1)
1019 /* If the pane has a meaningful name,
1020 make the pane a top-level menu item
1021 with its items as a submenu beneath it. */
1022 if (!keymaps
&& strcmp (pane_string
, ""
))
1024 wv
= xmalloc_widget_value
();
1028 first_wv
->contents
= wv
;
1029 wv
->name
= pane_string
;
1030 if (keymaps
&& !NILP
(prefix
))
1034 wv
->button_type
= BUTTON_TYPE_NONE
;
1039 else if (first_pane
)
1045 i
+= MENU_ITEMS_PANE_LENGTH
;
1049 /* Create a new item within current pane. */
1050 Lisp_Object item_name
, enable
, descrip
, def
, type, selected
, help;
1051 item_name
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1052 enable
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1053 descrip
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1054 def
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1055 type = AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1056 selected
= AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1057 help = AREF
(menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1059 #ifndef HAVE_MULTILINGUAL_MENU
1060 if (STRINGP
(item_name
) && STRING_MULTIBYTE
(item_name
))
1062 item_name
= ENCODE_MENU_STRING
(item_name
);
1063 ASET
(menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1066 if (STRINGP
(descrip
) && STRING_MULTIBYTE
(descrip
))
1068 descrip
= ENCODE_MENU_STRING
(descrip
);
1069 ASET
(menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1071 #endif
/* not HAVE_MULTILINGUAL_MENU */
1073 wv
= xmalloc_widget_value
();
1077 save_wv
->contents
= wv
;
1078 wv
->name
= (char *) SDATA
(item_name
);
1079 if (!NILP
(descrip
))
1080 wv
->key
= (char *) SDATA
(descrip
);
1082 /* If this item has a null value,
1083 make the call_data null so that it won't display a box
1084 when the mouse is on it. */
1086 = !NILP
(def
) ?
(void
*) &XVECTOR
(menu_items
)->contents
[i
] : 0;
1087 wv
->enabled
= !NILP
(enable
);
1090 wv
->button_type
= BUTTON_TYPE_NONE
;
1091 else if (EQ
(type, QCtoggle
))
1092 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1093 else if (EQ
(type, QCradio
))
1094 wv
->button_type
= BUTTON_TYPE_RADIO
;
1098 wv
->selected
= !NILP
(selected
);
1100 if (! STRINGP
(help))
1107 i
+= MENU_ITEMS_ITEM_LENGTH
;
1115 widget_value
*wv_title
= xmalloc_widget_value
();
1116 widget_value
*wv_sep
= xmalloc_widget_value
();
1118 /* Maybe replace this separator with a bitmap or owner-draw item
1119 so that it looks better. Having two separators looks odd. */
1120 wv_sep
->name
= "
--"
;
1121 wv_sep
->next
= first_wv
->contents
;
1122 wv_sep
->help = Qnil
;
1124 #ifndef HAVE_MULTILINGUAL_MENU
1125 if (STRING_MULTIBYTE
(title))
1126 title = ENCODE_MENU_STRING
(title);
1129 wv_title
->name
= (char *) SDATA
(title);
1130 wv_title
->enabled
= NO
;
1131 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1132 wv_title
->help = Qnil
;
1133 wv_title
->next
= wv_sep
;
1134 first_wv
->contents
= wv_title
;
1137 pmenu
= [[EmacsMenu alloc
] initWithTitle
:
1138 [NSString stringWithUTF8String
: SDATA
(title)]];
1139 [pmenu fillWithWidgetValue
: first_wv
->contents
];
1140 free_menubar_widget_value_tree
(first_wv
);
1141 unbind_to
(specpdl_count2
, Qnil
);
1143 popup_activated_flag
= 1;
1144 tem
= [pmenu runMenuAt
: p forFrame
: f keymaps
: keymaps
];
1145 popup_activated_flag
= 0;
1146 [[FRAME_NS_VIEW
(SELECTED_FRAME
()) window
] makeKeyWindow
];
1149 discard_menu_items
();
1150 unbind_to
(specpdl_count
, Qnil
);
1153 if (error_name
) error (error_name
);
1160 /* ==========================================================================
1162 Toolbar: externally-called functions
1164 ========================================================================== */
1167 free_frame_tool_bar
(FRAME_PTR f
)
1168 /* --------------------------------------------------------------------------
1169 Under NS we just hide the toolbar until it might be needed again.
1170 -------------------------------------------------------------------------- */
1172 [[FRAME_NS_VIEW
(f
) toolbar
] setVisible
: NO
];
1176 update_frame_tool_bar
(FRAME_PTR f
)
1177 /* --------------------------------------------------------------------------
1178 Update toolbar contents
1179 -------------------------------------------------------------------------- */
1182 EmacsToolbar
*toolbar
= [FRAME_NS_VIEW
(f
) toolbar
];
1184 [toolbar clearActive
];
1186 /* update EmacsToolbar as in GtkUtils, build items list */
1187 for (i
= 0; i
< f
->n_tool_bar_items
; ++i
)
1189 #define TOOLPROP
(IDX
) AREF
(f
->tool_bar_items
, \
1190 i
* TOOL_BAR_ITEM_NSLOTS
+ (IDX
))
1192 BOOL enabled_p
= !NILP
(TOOLPROP
(TOOL_BAR_ITEM_ENABLED_P
));
1193 BOOL selected_p
= !NILP
(TOOLPROP
(TOOL_BAR_ITEM_SELECTED_P
));
1198 Lisp_Object helpObj
;
1201 /* If image is a vector, choose the image according to the
1203 image = TOOLPROP
(TOOL_BAR_ITEM_IMAGES
);
1204 if (VECTORP
(image))
1206 /* NS toolbar auto-computes disabled and selected images */
1207 idx
= TOOL_BAR_IMAGE_ENABLED_SELECTED
;
1208 xassert
(ASIZE
(image) >= idx
);
1209 image = AREF
(image, idx
);
1215 /* Ignore invalid image specifications. */
1216 if (!valid_image_p
(image))
1218 NSLog
(@"Invalid
image for toolbar item"
);
1222 img_id
= lookup_image
(f
, image);
1223 img
= IMAGE_FROM_ID
(f
, img_id
);
1224 prepare_image_for_display
(f
, img
);
1226 if (img
->load_failed_p || img
->pixmap
== nil
)
1228 NSLog
(@"Could not prepare toolbar
image for display."
);
1232 helpObj
= TOOLPROP
(TOOL_BAR_ITEM_HELP
);
1234 helpObj
= TOOLPROP
(TOOL_BAR_ITEM_CAPTION
);
1235 helpText
= NILP
(helpObj
) ? ""
: (char *)SDATA
(helpObj
);
1237 [toolbar addDisplayItemWithImage
: img
->pixmap idx
: i helpText
: helpText
1238 enabled
: enabled_p
];
1242 if (![toolbar isVisible
])
1243 [toolbar setVisible
: YES
];
1245 if ([toolbar changed
])
1247 /* inform app that toolbar has changed */
1248 NSDictionary
*dict
= [toolbar configurationDictionary
];
1249 NSMutableDictionary
*newDict
= [dict mutableCopy
];
1250 NSEnumerator
*keys
= [[dict allKeys
] objectEnumerator
];
1252 while ((key
= [keys nextObject
]) != nil
)
1254 NSObject
*val
= [dict objectForKey
: key
];
1255 if ([val isKindOfClass
: [NSArray
class]])
1258 [toolbar toolbarDefaultItemIdentifiers
: toolbar
]
1263 [toolbar setConfigurationFromDictionary
: newDict
];
1270 /* ==========================================================================
1272 Toolbar: class implementation
1274 ========================================================================== */
1276 @implementation EmacsToolbar
1278 - initForView
: (EmacsView
*)view withIdentifier
: (NSString
*)identifier
1280 self
= [super initWithIdentifier
: identifier
];
1282 [self setDisplayMode
: NSToolbarDisplayModeIconOnly
];
1283 [self setSizeMode
: NSToolbarSizeModeSmall
];
1284 [self setDelegate
: self
];
1285 identifierToItem
= [[NSMutableDictionary alloc
] initWithCapacity
: 10];
1286 activeIdentifiers
= [[NSMutableArray alloc
] initWithCapacity
: 8];
1287 prevEnablement
= enablement
= 0L;
1293 [prevIdentifiers release
];
1294 [activeIdentifiers release
];
1295 [identifierToItem release
];
1299 - (void
) clearActive
1301 [prevIdentifiers release
];
1302 prevIdentifiers
= [activeIdentifiers copy
];
1303 [activeIdentifiers removeAllObjects
];
1304 prevEnablement
= enablement
;
1310 return [activeIdentifiers isEqualToArray
: prevIdentifiers
] &&
1311 enablement
== prevEnablement ? NO
: YES
;
1314 - (void
) addDisplayItemWithImage
: (EmacsImage
*)img idx
: (int
)idx
1315 helpText
: (char *)help enabled
: (BOOL
)enabled
1317 /* 1) come up w/identifier */
1318 NSString
*identifier
1319 = [NSString stringWithFormat
: @"
%u", [img hash]];
1321 /* 2) create / reuse item */
1322 NSToolbarItem
*item
= [identifierToItem objectForKey
: identifier
];
1325 item
= [[[NSToolbarItem alloc
] initWithItemIdentifier
: identifier
]
1327 [item setImage
: img
];
1328 [item setToolTip
: [NSString stringWithCString
: help]];
1329 [item setTarget
: emacsView
];
1330 [item setAction
: @selector
(toolbarClicked
:)];
1334 [item setEnabled
: enabled
];
1336 /* 3) update state */
1337 [identifierToItem setObject
: item forKey
: identifier
];
1338 [activeIdentifiers addObject
: identifier
];
1339 enablement
= (enablement
<< 1) |
(enabled
== YES
);
1342 /* This overrides super's implementation, which automatically sets
1343 all items to enabled state (for some reason). */
1344 - (void
)validateVisibleItems
{ }
1347 /* delegate methods */
1349 - (NSToolbarItem
*)toolbar
: (NSToolbar
*)toolbar
1350 itemForItemIdentifier
: (NSString
*)itemIdentifier
1351 willBeInsertedIntoToolbar
: (BOOL
)flag
1353 /* look up NSToolbarItem by identifier and return... */
1354 return [identifierToItem objectForKey
: itemIdentifier
];
1357 - (NSArray
*)toolbarDefaultItemIdentifiers
: (NSToolbar
*)toolbar
1359 /* return entire set.. */
1360 return activeIdentifiers
;
1363 /* for configuration palette (not yet supported) */
1364 - (NSArray
*)toolbarAllowedItemIdentifiers
: (NSToolbar
*)toolbar
1366 /* return entire set... */
1367 return [identifierToItem allKeys
];
1370 /* optional and unneeded */
1371 /* - toolbarWillAddItem: (NSNotification *)notification { } */
1372 /* - toolbarDidRemoveItem: (NSNotification *)notification { } */
1373 /* - (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar */
1375 @
end /* EmacsToolbar */
1379 /* ==========================================================================
1381 Tooltip: class implementation
1383 ========================================================================== */
1385 /* Needed because NeXTstep does not provide enough control over tooltip
1387 @implementation EmacsTooltip
1391 NSColor
*col
= [NSColor colorWithCalibratedRed
: 1.0 green
: 1.0
1392 blue
: 0.792 alpha
: 0.95];
1393 NSFont
*font
= [NSFont toolTipsFontOfSize
: 0];
1394 NSFont
*sfont
= [font screenFont
];
1395 int height
= [sfont ascender
] - [sfont descender
];
1396 /*[font boundingRectForFont].size.height; */
1397 NSRect r
= NSMakeRect
(0, 0, 100, height
+6);
1399 textField
= [[NSTextField alloc
] initWithFrame
: r
];
1400 [textField setFont
: font
];
1401 [textField setBackgroundColor
: col
];
1403 [textField setEditable
: NO
];
1404 [textField setSelectable
: NO
];
1405 [textField setBordered
: YES
];
1406 [textField setBezeled
: YES
];
1407 [textField setDrawsBackground
: YES
];
1409 win
= [[NSWindow alloc
]
1410 initWithContentRect
: [textField frame
]
1412 backing
: NSBackingStoreBuffered
1414 [win setReleasedWhenClosed
: NO
];
1415 [win setDelegate
: self
];
1416 [[win contentView
] addSubview
: textField
];
1417 /* [win setBackgroundColor: col]; */
1418 [win setOpaque
: NO
];
1427 [textField release
];
1431 - (void
) setText
: (char *)text
1433 NSString
*str
= [NSString stringWithUTF8String
: text];
1434 NSRect r
= [textField frame
];
1435 r.
size.width
= [[[textField font
] screenFont
] widthOfString
: str
] + 8;
1436 [textField setFrame
: r
];
1437 [textField setStringValue
: str
];
1440 - (void
) showAtX
: (int
)x Y
: (int
)y
for: (int
)seconds
1442 NSRect wr
= [win frame
];
1444 wr.origin
= NSMakePoint
(x
, y
);
1445 wr.
size = [textField frame
].
size;
1447 [win setFrame
: wr display
: YES
];
1448 [win orderFront
: self
];
1450 timer
= [NSTimer scheduledTimerWithTimeInterval
: (float
)seconds target
: self
1451 selector
: @selector
(hide
)
1452 userInfo
: nil repeats
: NO
];
1461 if ([timer isValid
])
1470 return timer
!= nil
;
1475 return [textField frame
];
1478 @
end /* EmacsTooltip */
1482 /* ==========================================================================
1484 Popup Dialog: implementing functions
1486 ========================================================================== */
1489 ns_popup_dialog
(Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
1492 Lisp_Object window
, tem
;
1497 NSTRACE
(x
-popup
-dialog);
1501 isQ
= NILP
(header
);
1503 if (EQ
(position
, Qt
))
1505 window
= selected_window
;
1507 else if (CONSP
(position
))
1510 tem
= Fcar
(position
);
1511 if (XTYPE
(tem
) == Lisp_Cons
)
1512 window
= Fcar
(Fcdr
(position
));
1515 tem
= Fcar
(Fcdr
(position
)); /* EVENT_START (position) */
1516 window
= Fcar
(tem
); /* POSN_WINDOW (tem) */
1519 else if (FRAMEP
(position
))
1525 CHECK_LIVE_WINDOW
(position
);
1529 if (FRAMEP
(window
))
1530 f
= XFRAME
(window
);
1533 CHECK_LIVE_WINDOW
(window
);
1534 f
= XFRAME
(WINDOW_FRAME
(XWINDOW
(window
)));
1536 p.x
= (int
)f
->left_pos
+ ((int
)FRAME_COLUMN_WIDTH
(f
) * f
->text_cols
)/2;
1537 p.y
= (int
)f
->top_pos
+ (FRAME_LINE_HEIGHT
(f
) * f
->text_lines
)/2;
1538 dialog = [[EmacsDialogPanel alloc
] initFromContents
: contents
1540 popup_activated_flag
= 1;
1541 tem
= [dialog runDialogAt
: p
];
1542 popup_activated_flag
= 0;
1546 [[FRAME_NS_VIEW
(SELECTED_FRAME
()) window
] makeKeyWindow
];
1551 /* ==========================================================================
1553 Popup Dialog: class implementation
1555 ========================================================================== */
1557 @interface FlippedView
: NSView
1562 @implementation FlippedView
1569 @implementation EmacsDialogPanel
1572 #define ICONSIZE
64.0
1573 #define TEXTHEIGHT
20.0
1574 #define MINCELLWIDTH
90.0
1576 - initWithContentRect
: (NSRect
)contentRect styleMask
: (unsigned int
)aStyle
1577 backing
: (NSBackingStoreType
)backingType defer
: (BOOL
)flag
1579 NSSize spacing
= {SPACER
, SPACER
};
1581 char this_cmd_name
[80];
1583 static NSImageView
*imgView
;
1584 static FlippedView
*contentView
;
1589 area.origin.x
= 3*SPACER
;
1590 area.origin.y
= 2*SPACER
;
1591 area.
size.width
= ICONSIZE
;
1592 area.
size.height
= ICONSIZE
;
1593 img
= [[NSImage imageNamed
: @"NSApplicationIcon"
] copy
];
1594 [img setScalesWhenResized
: YES
];
1595 [img setSize
: NSMakeSize
(ICONSIZE
, ICONSIZE
)];
1596 imgView
= [[NSImageView alloc
] initWithFrame
: area
];
1597 [imgView setImage
: img
];
1598 [imgView setEditable
: NO
];
1602 aStyle
= NSTitledWindowMask
;
1606 [super initWithContentRect
: contentRect styleMask
: aStyle
1607 backing
: backingType defer
: flag];
1608 contentView
= [[FlippedView alloc
] initWithFrame
: [[self contentView
] frame
]];
1609 [self setContentView
: contentView
];
1611 [[self contentView
] setAutoresizesSubviews
: YES
];
1613 [[self contentView
] addSubview
: imgView
];
1614 [self setTitle
: @""
];
1616 area.origin.x
+= ICONSIZE
+2*SPACER
;
1617 /* area.origin.y = TEXTHEIGHT; ICONSIZE/2-10+SPACER; */
1618 area.
size.width
= 400;
1619 area.
size.height
= TEXTHEIGHT
;
1620 command
= [[[NSTextField alloc
] initWithFrame
: area
] autorelease
];
1621 [[self contentView
] addSubview
: command
];
1622 [command setStringValue
: @"Emacs"
];
1623 [command setDrawsBackground
: NO
];
1624 [command setBezeled
: NO
];
1625 [command setSelectable
: NO
];
1626 [command setFont
: [NSFont boldSystemFontOfSize
: 13.0]];
1628 /* area.origin.x = ICONSIZE+2*SPACER;
1629 area.origin.y = TEXTHEIGHT + 2*SPACER;
1630 area.size.width = 400;
1631 area.size.height= 2;
1632 tem = [[[NSBox alloc] initWithFrame: area] autorelease];
1633 [[self contentView] addSubview: tem];
1634 [tem setTitlePosition: NSNoTitle];
1635 [tem setAutoresizingMask: NSViewWidthSizable];*/
1637 /* area.origin.x = ICONSIZE+2*SPACER; */
1638 area.origin.y
+= TEXTHEIGHT
+SPACER
;
1639 area.
size.width
= 400;
1640 area.
size.height
= TEXTHEIGHT
;
1641 title = [[[NSTextField alloc
] initWithFrame
: area
] autorelease
];
1642 [[self contentView
] addSubview
: title];
1643 [title setDrawsBackground
: NO
];
1644 [title setBezeled
: NO
];
1645 [title setSelectable
: NO
];
1646 [title setFont
: [NSFont systemFontOfSize
: 11.0]];
1648 cell = [[[NSButtonCell alloc
] initTextCell
: @""
] autorelease
];
1649 [cell setBordered
: NO
];
1650 [cell setEnabled
: NO
];
1651 [cell setCellAttribute
: NSCellIsInsetButton to
: 8];
1652 [cell setBezelStyle
: NSRoundedBezelStyle
];
1654 matrix
= [[NSMatrix alloc
] initWithFrame
: contentRect
1655 mode
: NSHighlightModeMatrix
1658 numberOfColumns
: 1];
1659 [[self contentView
] addSubview
: matrix
];
1661 [matrix setFrameOrigin
: NSMakePoint
(area.origin.x
,
1662 area.origin.y
+ (TEXTHEIGHT
+3*SPACER
))];
1663 [matrix setIntercellSpacing
: spacing
];
1665 [self setOneShot
: YES
];
1666 [self setReleasedWhenClosed
: YES
];
1667 [self setHidesOnDeactivate
: YES
];
1672 - (BOOL
)windowShouldClose
: (id
)sender
1674 [NSApp stopModalWithCode
: XHASH
(Qnil
)]; // FIXME
: BIG UGLY HACK
!!
1679 void process_dialog
(id window
, Lisp_Object list
)
1684 for (; XTYPE
(list
) == Lisp_Cons
; list
= XCDR
(list
))
1687 if (XTYPE
(item
) == Lisp_String
)
1689 [window addString
: XSTRING
(item
)->data row
: row
++];
1691 else if (XTYPE
(item
) == Lisp_Cons
)
1693 [window addButton
: XSTRING
(XCAR
(item
))->data
1694 value
: XCDR
(item
) row
: row
++];
1696 else if (NILP
(item
))
1705 - addButton
: (char *)str value
: (Lisp_Object
)val row
: (int
)row
1714 cell = [matrix cellAtRow
: row column
: cols
-1];
1715 [cell setTarget
: self
];
1716 [cell setAction
: @selector
(clicked
: )];
1717 [cell setTitle
: [NSString stringWithUTF8String
: str
]];
1718 [cell setTag
: XHASH
(val
)]; // FIXME
: BIG UGLY HACK
!!
1719 [cell setBordered
: YES
];
1720 [cell setEnabled
: YES
];
1726 - addString
: (char *)str row
: (int
)row
1735 cell = [matrix cellAtRow
: row column
: cols
-1];
1736 [cell setTitle
: [NSString stringWithUTF8String
: str
]];
1737 [cell setBordered
: YES
];
1738 [cell setEnabled
: NO
];
1754 NSArray
*sellist
= nil
;
1757 sellist
= [sender selectedCells
];
1758 if ([sellist count
]<1)
1761 seltag
= [[sellist objectAtIndex
: 0] tag
];
1762 if (seltag
!= XHASH
(Qundefined
)) // FIXME
: BIG UGLY HACK
!!
1763 [NSApp stopModalWithCode
: seltag
];
1768 - initFromContents
: (Lisp_Object
)contents isQuestion
: (BOOL
)isQ
1773 if (XTYPE
(contents
) == Lisp_Cons
)
1775 head
= Fcar
(contents
);
1776 process_dialog
(self
, Fcdr
(contents
));
1781 if (XTYPE
(head
) == Lisp_String
)
1782 [title setStringValue
:
1783 [NSString stringWithUTF8String
: XSTRING
(head
)->data
]];
1784 else if (isQ
== YES
)
1785 [title setStringValue
: @"Question"
];
1787 [title setStringValue
: @"Information"
];
1793 if (cols
== 1 && rows
> 1) /* Never told where to split */
1796 for (i
= 0; i
<rows
/2; i
++)
1798 [matrix putCell
: [matrix cellAtRow
: (rows
+1)/2 column
: 0]
1799 atRow
: i column
: 1];
1800 [matrix removeRow
: (rows
+1)/2];
1806 NSSize csize
= [matrix cellSize
];
1807 if (csize.width
< MINCELLWIDTH
)
1809 csize.width
= MINCELLWIDTH
;
1810 [matrix setCellSize
: csize
];
1811 [matrix sizeToCells
];
1816 [command sizeToFit
];
1820 if (r.
size.width
+r.origin.x
> t.
size.width
+t.origin.x
)
1822 t.origin.x
= r.origin.x
;
1823 t.
size.width
= r.
size.width
;
1825 r
= [command frame
];
1826 if (r.
size.width
+r.origin.x
> t.
size.width
+t.origin.x
)
1828 t.origin.x
= r.origin.x
;
1829 t.
size.width
= r.
size.width
;
1833 s
= [(NSView
*)[self contentView
] frame
];
1834 r.
size.width
+= t.origin.x
+t.
size.width
+2*SPACER
-s.
size.width
;
1835 r.
size.height
+= t.origin.y
+t.
size.height
+SPACER
-s.
size.height
;
1836 [self setFrame
: r display
: NO
];
1845 { [super dealloc
]; return; };
1849 - (Lisp_Object
)runDialogAt
: (NSPoint
)p
1852 NSModalSession session
;
1855 [self center
]; /*XXX p ignored? */
1856 [self orderFront
: NSApp
];
1858 session
= [NSApp beginModalSessionForWindow
: self
];
1859 while ((ret
= [NSApp runModalSession
: session
]) == NSRunContinuesResponse
)
1861 (e
= [NSApp nextEventMatchingMask
: NSAnyEventMask
1862 untilDate
: [NSDate distantFuture
]
1863 inMode
: NSEventTrackingRunLoopMode
1865 /*fprintf (stderr, "ret = %d\te = %p\n", ret, e); */
1867 [NSApp endModalSession
: session
];
1869 { // FIXME
: BIG UGLY HACK
!!!
1871 *(EMACS_INT
*)(&tmp
) = ret
;
1880 /* ==========================================================================
1884 ========================================================================== */
1886 DEFUN
("ns
-reset-menu"
, Fns_reset_menu
, Sns_reset_menu
, 0, 0, 0,
1887 doc: /* Cause the NS menu to be re-calculated. */)
1890 set_frame_menubar
(SELECTED_FRAME
(), 1, 0);
1895 DEFUN
("x
-popup
-menu"
, Fx_popup_menu
, Sx_popup_menu
, 2, 2, 0,
1896 doc: /* Pop up a deck-of-cards menu and return user's selection.
1897 POSITION is a position specification. This is either a mouse button event
1898 or a list ((XOFFSET YOFFSET) WINDOW)
1899 where XOFFSET and YOFFSET are positions in pixels from the top left
1900 corner of WINDOW. (WINDOW may be a window or a frame object.)
1901 This controls the position of the top left of the menu as a whole.
1902 If POSITION is t, it means to use the current mouse position.
1904 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
1905 The menu items come from key bindings that have a menu string as well as
1906 a definition; actually, the \"definition\" in such a key binding looks like
1907 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
1908 the keymap as a top-level element.
1910 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
1911 Otherwise, REAL-DEFINITION should be a valid key binding definition.
1913 You can also use a list of keymaps as MENU.
1914 Then each keymap makes a separate pane.
1916 When MENU is a keymap or a list of keymaps, the return value is the
1917 list of events corresponding to the user's choice. Note that
1918 `x-popup-menu' does not actually execute the command bound to that
1921 Alternatively, you can specify a menu of multiple panes
1922 with a list of the form (TITLE PANE1 PANE2...),
1923 where each pane is a list of form (TITLE ITEM1 ITEM2...).
1924 Each ITEM is normally a cons cell (STRING . VALUE);
1925 but a string can appear as an item--that makes a nonselectable line
1927 With this form of menu, the return value is VALUE from the chosen item. */)
1929 Lisp_Object position
, menu;
1931 return ns_popup_menu
(position
, menu);
1935 DEFUN
("x
-popup
-dialog"
, Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
1936 doc: /* Pop up a dialog box and return user's selection.
1937 POSITION specifies which frame to use.
1938 This is normally a mouse button event or a window or frame.
1939 If POSITION is t, it means to use the frame the mouse is on.
1940 The dialog box appears in the middle of the specified frame.
1942 CONTENTS specifies the alternatives to display in the dialog box.
1943 It is a list of the form (DIALOG ITEM1 ITEM2...).
1944 Each ITEM is a cons cell (STRING . VALUE).
1945 The return value is VALUE from the chosen item.
1947 An ITEM may also be just a string--that makes a nonselectable item.
1948 An ITEM may also be nil--that means to put all preceding items
1949 on the left of the dialog box and all following items on the right.
1950 \(By default, approximately half appear on each side.)
1952 If HEADER is non-nil, the frame title for the box is "Information",
1953 otherwise it is "Question".
1955 If the user gets rid of the dialog box without making a valid choice,
1956 for instance using the window manager, then this produces a quit and
1957 `x-popup-dialog' does not return. */)
1958 (position
, contents
, header
)
1959 Lisp_Object position
, contents
, header
;
1961 return ns_popup_dialog
(position
, contents
, header
);
1964 DEFUN
("
menu-or
-popup
-active
-p"
, Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
1965 doc: /* Return t if a menu or popup dialog is active. */)
1968 return popup_activated
() ? Qt
: Qnil
;
1971 /* ==========================================================================
1973 Lisp interface declaration
1975 ========================================================================== */
1980 defsubr
(&Sx_popup_menu
);
1981 defsubr
(&Sx_popup_dialog
);
1982 defsubr
(&Sns_reset_menu
);
1983 defsubr
(&Smenu_or_popup_active_p
);
1984 staticpro
(&menu_items
);
1987 Qdebug_on_next_call
= intern
("
debug-on
-next
-call"
);
1988 staticpro
(&Qdebug_on_next_call
);
1991 // arch
-tag
: 75773656-52e5
-4c44
-a398
-47bd87b32619