/* NeXT/Open/GNUstep and MacOSX Cocoa menu and toolbar module.
- Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+ Copyright (C) 2007-2012 Free Software Foundation, Inc.
This file is part of GNU Emacs.
/* This should be the first include, as it may set up #defines affecting
interpretation of even the system includes. */
-#include "config.h"
-#include <setjmp.h>
+#include <config.h>
#include "lisp.h"
#include "window.h"
+#include "character.h"
#include "buffer.h"
#include "keymap.h"
#include "coding.h"
extern Lisp_Object QCtoggle, QCradio;
Lisp_Object Qdebug_on_next_call;
-extern Lisp_Object Voverriding_local_map, Voverriding_local_map_menu_flag,
- Qoverriding_local_map, Qoverriding_terminal_local_map;
+extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
extern long context_menu_value;
EmacsMenu *mainMenu, *svcsMenu, *dockMenu;
/* Nonzero means a menu is currently active. */
static int popup_activated_flag;
-static NSModalSession popupSession;
+
+/* Nonzero means we are tracking and updating menus. */
+static int trackingMenu;
+
/* NOTE: toolbar implementation is at end,
following complete menu implementation. */
int
-popup_activated ()
+popup_activated (void)
{
return popup_activated_flag;
}
/* --------------------------------------------------------------------------
Update menubar. Three cases:
- 1) deep_p = 0, submenu = nil: Fresh switch onto a frame -- either set up
+ 1) ! deep_p, submenu = nil: Fresh switch onto a frame -- either set up
just top-level menu strings (OS X), or goto case (2) (GNUstep).
- 2) deep_p = 1, submenu = nil: Recompute all submenus.
- 3) deep_p = 1, submenu = non-nil: Update contents of a single submenu.
+ 2) deep_p, submenu = nil: Recompute all submenus.
+ 3) deep_p, submenu = non-nil: Update contents of a single submenu.
-------------------------------------------------------------------------- */
void
-ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu)
+ns_update_menubar (struct frame *f, bool deep_p, EmacsMenu *submenu)
{
NSAutoreleasePool *pool;
id menu = [NSApp mainMenu];
XSETFRAME (Vmenu_updating_frame, f);
/*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */
- BLOCK_INPUT;
+ block_input ();
pool = [[NSAutoreleasePool alloc] init];
/* Menu may have been created automatically; if so, discard it. */
int *submenu_top_level_items, *submenu_n_panes;
struct buffer *prev = current_buffer;
Lisp_Object buffer;
- int specpdl_count = SPECPDL_INDEX ();
+ ptrdiff_t specpdl_count = SPECPDL_INDEX ();
int previous_menu_items_used = f->menu_bar_items_used;
Lisp_Object *previous_items
- = (Lisp_Object *) alloca (previous_menu_items_used
- * sizeof (Lisp_Object));
+ = alloca (previous_menu_items_used * sizeof *previous_items);
/* lisp preliminaries */
buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
if (! NILP (Vlucid_menu_bar_dirty_flag))
call0 (Qrecompute_lucid_menubar);
safe_run_hooks (Qmenu_bar_update_hook);
- FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
+ fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
/* Now ready to go */
items = FRAME_MENU_BAR_ITEMS (f);
/* Save the frame's previous menu bar contents data */
if (previous_menu_items_used)
- bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
- previous_menu_items_used * sizeof (Lisp_Object));
+ memcpy (previous_items, aref_addr (f->menu_bar_vector, 0),
+ previous_menu_items_used * sizeof (Lisp_Object));
/* parse stage 1: extract from lisp */
save_menu_items ();
menu_items = f->menu_bar_vector;
menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
- submenu_start = (int *) alloca (ASIZE (items) * sizeof (int *));
- submenu_end = (int *) alloca (ASIZE (items) * sizeof (int *));
- submenu_n_panes = (int *) alloca (ASIZE (items) * sizeof (int));
- submenu_top_level_items
- = (int *) alloca (ASIZE (items) * sizeof (int *));
+ submenu_start = alloca (ASIZE (items) * sizeof *submenu_start);
+ submenu_end = alloca (ASIZE (items) * sizeof *submenu_end);
+ submenu_n_panes = alloca (ASIZE (items) * sizeof *submenu_n_panes);
+ submenu_top_level_items = alloca (ASIZE (items)
+ * sizeof *submenu_top_level_items);
init_menu_items ();
for (i = 0; i < ASIZE (items); i += 4)
{
/* FIXME: we'd like to only parse the needed submenu, but this
was causing crashes in the _common parsing code.. need to make
sure proper initialization done.. */
-/* if (submenu && strcmp (submenuTitle, SDATA (string)))
+/* if (submenu && strcmp (submenuTitle, SSDATA (string)))
continue; */
submenu_start[i] = menu_items_used;
discard_menu_items ();
unbind_to (specpdl_count, Qnil);
[pool release];
- UNBLOCK_INPUT;
+ unblock_input ();
return;
}
if (!EQ (previous_items[i], AREF (menu_items, i)))
if (!(STRINGP (previous_items[i])
&& STRINGP (AREF (menu_items, i))
- && !strcmp (SDATA (previous_items[i]),
- SDATA (AREF (menu_items, i)))))
+ && !strcmp (SSDATA (previous_items[i]),
+ SSDATA (AREF (menu_items, i)))))
break;
if (i == previous_menu_items_used)
{
discard_menu_items ();
unbind_to (specpdl_count, Qnil);
[pool release];
- UNBLOCK_INPUT;
+ unblock_input ();
return;
}
}
/* The menu items are different, so store them in the frame */
/* FIXME: this is not correct for single-submenu case */
- f->menu_bar_vector = menu_items;
+ fset_menu_bar_vector (f, menu_items);
f->menu_bar_items_used = menu_items_used;
/* Calls restore_menu_items, etc., as they were outside */
string = AREF (items, i + 1);
if (NILP (string))
break;
-/* if (submenu && strcmp (submenuTitle, SDATA (string)))
+/* if (submenu && strcmp (submenuTitle, SSDATA (string)))
continue; */
- wv->name = (char *) SDATA (string);
+ wv->name = SSDATA (string);
update_submenu_strings (wv->contents);
wv = wv->next;
}
items = FRAME_MENU_BAR_ITEMS (f);
if (NILP (items))
{
+ free_menubar_widget_value_tree (first_wv);
[pool release];
- UNBLOCK_INPUT;
+ unblock_input ();
return;
}
if (EQ (string, make_number (0))) // FIXME: Why??? --Stef
continue;
if (NILP (string))
- if (previous_strings[i][0])
- break;
- else
- continue;
- if (strncmp (previous_strings[i], SDATA (string), 10))
+ {
+ if (previous_strings[i][0])
+ break;
+ else
+ continue;
+ }
+ else if (memcmp (previous_strings[i], SDATA (string),
+ min (10, SBYTES (string) + 1)))
break;
}
if (i == n)
{
+ free_menubar_widget_value_tree (first_wv);
[pool release];
- UNBLOCK_INPUT;
+ unblock_input ();
return;
}
}
break;
if (n < 100)
- strncpy (previous_strings[i/4], SDATA (string), 10);
+ memcpy (previous_strings[i/4], SDATA (string),
+ min (10, SBYTES (string) + 1));
wv = xmalloc_widget_value ();
- wv->name = (char *) SDATA (string);
+ wv->name = SSDATA (string);
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
wv->help = Qnil;
- wv->call_data = (void *) (EMACS_INT) (-1);
+ wv->call_data = (void *) (intptr_t) (-1);
#ifdef NS_IMPL_COCOA
/* we'll update the real copy under app menu when time comes */
{
/* but we need to make sure it will update on demand */
[svcsMenu setFrame: f];
- [svcsMenu setDelegate: svcsMenu];
}
else
#endif
[NSApp setMainMenu: menu];
[pool release];
- UNBLOCK_INPUT;
+ unblock_input ();
}
frame's menus have changed, and the *step representation should be updated
from Lisp. */
void
-set_frame_menubar (struct frame *f, int first_time, int deep_p)
+set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
{
ns_update_menubar (f, deep_p, nil);
}
-/* Utility (from macmenu.c): is this item a separator? */
-static int
-name_is_separator (name)
- const char *name;
-{
- const char *start = name;
-
- /* Check if name string consists of only dashes ('-'). */
- while (*name == '-') name++;
- /* Separators can also be of the form "--:TripleSuperMegaEtched"
- or "--deep-shadow". We don't implement them yet, se we just treat
- them like normal separators. */
- return (*name == '\0' || start + 2 == name);
-}
-
-
/* ==========================================================================
Menu: class implementation
/* override designated initializer */
- initWithTitle: (NSString *)title
{
- if (self = [super initWithTitle: title])
+ if ((self = [super initWithTitle: title]))
[self setAutoenablesItems: NO];
return self;
}
frame = f;
}
+#ifdef NS_IMPL_COCOA
+#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
+extern NSString *NSMenuDidBeginTrackingNotification;
+#endif
+#endif
+
+#ifdef NS_IMPL_COCOA
+-(void)trackingNotification:(NSNotification *)notification
+{
+ /* Update menu in menuNeedsUpdate only while tracking menus. */
+ trackingMenu = ([notification name] == NSMenuDidBeginTrackingNotification
+ ? 1 : 0);
+}
+#endif
/* delegate method called when a submenu is being opened: run a 'deep' call
to set_frame_menubar */
- (void)menuNeedsUpdate: (NSMenu *)menu
{
- NSEvent *event;
if (!FRAME_LIVE_P (frame))
return;
- event = [[FRAME_NS_VIEW (frame) window] currentEvent];
- /* HACK: Cocoa/Carbon will request update on every keystroke
+
+ /* Cocoa/Carbon will request update on every keystroke
via IsMenuKeyEvent -> CheckMenusForKeyEvent. These are not needed
since key equivalents are handled through emacs.
- On Leopard, even keystroke events generate SystemDefined events, but
- their subtype is 8. */
- if ([event type] != NSSystemDefined || [event subtype] == 8
- /* Also, don't try this if from an event picked up asynchronously,
- as lots of lisp evaluation happens in ns_update_menubar. */
- || handling_signal != 0)
+ On Leopard, even keystroke events generate SystemDefined event.
+ Third-party applications that enhance mouse / trackpad
+ interaction, or also VNC/Remote Desktop will send events
+ of type AppDefined rather than SysDefined.
+ Menus will fail to show up if they haven't been initialized.
+ AppDefined events may lack timing data.
+
+ Thus, we rely on the didBeginTrackingNotification notification
+ as above to indicate the need for updates.
+ From 10.6 on, we could also use -[NSMenu propertiesToUpdate]: In the
+ key press case, NSMenuPropertyItemImage (e.g.) won't be set.
+ */
+ if (trackingMenu == 0)
return;
/*fprintf (stderr, "Updating menu '%s'\n", [[self title] UTF8String]); NSLog (@"%@\n", event); */
ns_update_menubar (frame, 1, self);
NSMenuItem get ignored. For now we try to display a super-single letter
combo, and return the others as strings to be appended to the item title.
(This is signaled by setting keyEquivModMask to 0 for now.) */
--(NSString *)parseKeyEquiv: (char *)key
+-(NSString *)parseKeyEquiv: (const char *)key
{
- char *tpos = key;
+ const char *tpos = key;
keyEquivModMask = NSCommandKeyMask;
if (!key || !strlen (key))
NSMenuItem *item;
widget_value *wv = (widget_value *)wvptr;
- if (name_is_separator (wv->name))
+ if (menu_separator_name_p (wv->name))
{
item = [NSMenuItem separatorItem];
[self addItem: item];
if ([[self window] isVisible])
[self sizeToFit];
#else
+#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_2
if ([self supermenu] == nil)
[self sizeToFit];
#endif
+#endif
}
/* adds an empty submenu and returns it */
-- (EmacsMenu *)addSubmenuWithTitle: (char *)title forFrame: (struct frame *)f
+- (EmacsMenu *)addSubmenuWithTitle: (const char *)title forFrame: (struct frame *)f
{
NSString *titleStr = [NSString stringWithUTF8String: title];
NSMenuItem *item = [self addItemWithTitle: titleStr
keymaps: (int)keymaps
{
EmacsView *view = FRAME_NS_VIEW (f);
+ NSEvent *e, *event;
+ long retVal;
+
/* p = [view convertPoint:p fromView: nil]; */
p.y = NSHeight ([view frame]) - p.y;
- NSEvent *e = [[view window] currentEvent];
- NSEvent *event = [NSEvent mouseEventWithType: NSRightMouseDown
- location: p
- modifierFlags: 0
- timestamp: [e timestamp]
- windowNumber: [[view window] windowNumber]
- context: [e context]
- eventNumber: 0/*[e eventNumber] */
- clickCount: 1
- pressure: 0];
- long retVal;
+ e = [[view window] currentEvent];
+ event = [NSEvent mouseEventWithType: NSRightMouseDown
+ location: p
+ modifierFlags: 0
+ timestamp: [e timestamp]
+ windowNumber: [[view window] windowNumber]
+ context: [e context]
+ eventNumber: 0/*[e eventNumber] */
+ clickCount: 1
+ pressure: 0];
context_menu_value = -1;
[NSMenu popUpContextMenu: self withEvent: event forView: view];
Lisp_Object
ns_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
- Lisp_Object title, char **error)
+ Lisp_Object title, const char **error)
{
EmacsMenu *pmenu;
NSPoint p;
- Lisp_Object window, tem, keymap;
- int specpdl_count = SPECPDL_INDEX ();
+ Lisp_Object tem;
+ ptrdiff_t specpdl_count = SPECPDL_INDEX ();
widget_value *wv, *first_wv = 0;
p.x = x; p.y = y;
{
widget_value *save_wv = 0, *prev_wv = 0;
widget_value **submenu_stack
- = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
+ = alloca (menu_items_used * sizeof *submenu_stack);
/* Lisp_Object *subprefix_stack
- = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); */
+ = alloca (menu_items_used * sizeof *subprefix_stack); */
int submenu_depth = 0;
int first_pane = 1;
int i;
{
/* Create a new pane. */
Lisp_Object pane_name, prefix;
- char *pane_string;
+ const char *pane_string;
pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
}
#endif
pane_string = (NILP (pane_name)
- ? "" : (char *) SDATA (pane_name));
+ ? "" : SSDATA (pane_name));
/* If there is just one top-level pane, put all its items directly
under the top-level menu. */
if (menu_items_n_panes == 1)
prev_wv->next = wv;
else
save_wv->contents = wv;
- wv->name = (char *) SDATA (item_name);
+ wv->name = SSDATA (item_name);
if (!NILP (descrip))
- wv->key = (char *) SDATA (descrip);
+ wv->key = SSDATA (descrip);
wv->value = 0;
/* If this item has a null value,
make the call_data null so that it won't display a box
when the mouse is on it. */
- wv->call_data
- = !NILP (def) ? (void *) &AREF (menu_items, i) : 0;
+ wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
wv->enabled = !NILP (enable);
if (NILP (type))
else if (EQ (type, QCradio))
wv->button_type = BUTTON_TYPE_RADIO;
else
- abort ();
+ emacs_abort ();
wv->selected = !NILP (selected);
title = ENCODE_MENU_STRING (title);
#endif
- wv_title->name = (char *) SDATA (title);
+ wv_title->name = SSDATA (title);
wv_title->enabled = NO;
wv_title->button_type = BUTTON_TYPE_NONE;
wv_title->help = Qnil;
}
pmenu = [[EmacsMenu alloc] initWithTitle:
- [NSString stringWithUTF8String: SDATA (title)]];
+ [NSString stringWithUTF8String: SSDATA (title)]];
[pmenu fillWithWidgetValue: first_wv->contents];
free_menubar_widget_value_tree (first_wv);
unbind_to (specpdl_count, Qnil);
Under NS we just hide the toolbar until it might be needed again.
-------------------------------------------------------------------------- */
{
+ block_input ();
[[FRAME_NS_VIEW (f) toolbar] setVisible: NO];
+ FRAME_TOOLBAR_HEIGHT (f) = 0;
+ unblock_input ();
}
void
-------------------------------------------------------------------------- */
{
int i;
- EmacsToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
+ EmacsView *view = FRAME_NS_VIEW (f);
+ NSWindow *window = [view window];
+ EmacsToolbar *toolbar = [view toolbar];
+ block_input ();
[toolbar clearActive];
/* update EmacsToolbar as in GtkUtils, build items list */
i * TOOL_BAR_ITEM_NSLOTS + (IDX))
BOOL enabled_p = !NILP (TOOLPROP (TOOL_BAR_ITEM_ENABLED_P));
- BOOL selected_p = !NILP (TOOLPROP (TOOL_BAR_ITEM_SELECTED_P));
int idx;
- int img_id;
+ ptrdiff_t img_id;
struct image *img;
Lisp_Object image;
Lisp_Object helpObj;
- char *helpText;
+ const char *helpText;
/* If image is a vector, choose the image according to the
button state. */
{
/* NS toolbar auto-computes disabled and selected images */
idx = TOOL_BAR_IMAGE_ENABLED_SELECTED;
- xassert (ASIZE (image) >= idx);
+ eassert (ASIZE (image) >= idx);
image = AREF (image, idx);
}
else
{
idx = -1;
}
+ helpObj = TOOLPROP (TOOL_BAR_ITEM_HELP);
+ if (NILP (helpObj))
+ helpObj = TOOLPROP (TOOL_BAR_ITEM_CAPTION);
+ helpText = NILP (helpObj) ? "" : SSDATA (helpObj);
+
/* Ignore invalid image specifications. */
if (!valid_image_p (image))
{
- NSLog (@"Invalid image for toolbar item");
+ /* Don't log anything, GNUS makes invalid images all the time. */
continue;
}
continue;
}
- helpObj = TOOLPROP (TOOL_BAR_ITEM_HELP);
- if (NILP (helpObj))
- helpObj = TOOLPROP (TOOL_BAR_ITEM_CAPTION);
- helpText = NILP (helpObj) ? "" : (char *)SDATA (helpObj);
-
[toolbar addDisplayItemWithImage: img->pixmap idx: i helpText: helpText
enabled: enabled_p];
#undef TOOLPROP
NSDictionary *dict = [toolbar configurationDictionary];
NSMutableDictionary *newDict = [dict mutableCopy];
NSEnumerator *keys = [[dict allKeys] objectEnumerator];
- NSObject *key;
+ id key;
while ((key = [keys nextObject]) != nil)
{
NSObject *val = [dict objectForKey: key];
[newDict release];
}
+ FRAME_TOOLBAR_HEIGHT (f) =
+ NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
+ - FRAME_NS_TITLEBAR_HEIGHT (f);
+ unblock_input ();
}
}
- (void) addDisplayItemWithImage: (EmacsImage *)img idx: (int)idx
- helpText: (char *)help enabled: (BOOL)enabled
+ helpText: (const char *)help enabled: (BOOL)enabled
{
/* 1) come up w/identifier */
NSString *identifier
[textField setEditable: NO];
[textField setSelectable: NO];
- [textField setBordered: YES];
- [textField setBezeled: YES];
+ [textField setBordered: NO];
+ [textField setBezeled: NO];
[textField setDrawsBackground: YES];
win = [[NSWindow alloc]
styleMask: 0
backing: NSBackingStoreBuffered
defer: YES];
+ [win setHasShadow: YES];
[win setReleasedWhenClosed: NO];
[win setDelegate: self];
[[win contentView] addSubview: textField];
- (void) setText: (char *)text
{
NSString *str = [NSString stringWithUTF8String: text];
- NSRect r = [textField frame];
- NSSize textSize = [str sizeWithAttributes:
- [NSDictionary dictionaryWithObject: [[textField font] screenFont]
- forKey: NSFontAttributeName]];
- NSSize padSize = [[[textField font] screenFont]
- boundingRectForFont].size;
-
- r.size.width = textSize.width + padSize.width/2;
- r.size.height = textSize.height + padSize.height/2;
- [textField setFrame: r];
+ NSRect r = [textField frame];
+ NSSize tooltipDims;
+
[textField setStringValue: str];
+ tooltipDims = [[textField cell] cellSize];
+
+ r.size.width = tooltipDims.width;
+ r.size.height = tooltipDims.height;
+ [textField setFrame: r];
}
- (void) showAtX: (int)x Y: (int)y for: (int)seconds
========================================================================== */
+struct Popdown_data
+{
+ NSAutoreleasePool *pool;
+ EmacsDialogPanel *dialog;
+};
static Lisp_Object
pop_down_menu (Lisp_Object arg)
{
struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
+ struct Popdown_data *unwind_data = (struct Popdown_data *) p->pointer;
+
+ block_input ();
if (popup_activated_flag)
{
+ EmacsDialogPanel *panel = unwind_data->dialog;
popup_activated_flag = 0;
- BLOCK_INPUT;
- [NSApp endModalSession: popupSession];
- [((EmacsDialogPanel *) (p->pointer)) close];
+ [panel close];
+ [unwind_data->pool release];
[[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
- UNBLOCK_INPUT;
}
+
+ xfree (unwind_data);
+ unblock_input ();
+
return Qnil;
}
ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
{
id dialog;
- Lisp_Object window, tem;
+ Lisp_Object window, tem, title;
struct frame *f;
NSPoint p;
BOOL isQ;
+ NSAutoreleasePool *pool;
NSTRACE (x-popup-dialog);
p.x = (int)f->left_pos + ((int)FRAME_COLUMN_WIDTH (f) * f->text_cols)/2;
p.y = (int)f->top_pos + (FRAME_LINE_HEIGHT (f) * f->text_lines)/2;
- BLOCK_INPUT;
+ title = Fcar (contents);
+ CHECK_STRING (title);
+
+ if (NILP (Fcar (Fcdr (contents))))
+ /* No buttons specified, add an "Ok" button so users can pop down
+ the dialog. */
+ contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil));
+
+ block_input ();
+ pool = [[NSAutoreleasePool alloc] init];
dialog = [[EmacsDialogPanel alloc] initFromContents: contents
isQuestion: isQ];
+
{
- int specpdl_count = SPECPDL_INDEX ();
- record_unwind_protect (pop_down_menu, make_save_value (dialog, 0));
+ ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+ struct Popdown_data *unwind_data = xmalloc (sizeof (*unwind_data));
+
+ unwind_data->pool = pool;
+ unwind_data->dialog = dialog;
+
+ record_unwind_protect (pop_down_menu, make_save_value (unwind_data, 0));
popup_activated_flag = 1;
tem = [dialog runDialogAt: p];
unbind_to (specpdl_count, Qnil); /* calls pop_down_menu */
}
- UNBLOCK_INPUT;
+
+ unblock_input ();
return tem;
}
{
NSSize spacing = {SPACER, SPACER};
NSRect area;
- char this_cmd_name[80];
id cell;
- static NSImageView *imgView;
- static FlippedView *contentView;
-
- if (imgView == nil)
- {
- NSImage *img;
- area.origin.x = 3*SPACER;
- area.origin.y = 2*SPACER;
- area.size.width = ICONSIZE;
- area.size.height= ICONSIZE;
- img = [[NSImage imageNamed: @"NSApplicationIcon"] copy];
- [img setScalesWhenResized: YES];
- [img setSize: NSMakeSize (ICONSIZE, ICONSIZE)];
- imgView = [[NSImageView alloc] initWithFrame: area];
- [imgView setImage: img];
- [imgView setEditable: NO];
- [img release];
- }
+ NSImageView *imgView;
+ FlippedView *contentView;
+ NSImage *img;
+
+ dialog_return = Qundefined;
+ button_values = NULL;
+ area.origin.x = 3*SPACER;
+ area.origin.y = 2*SPACER;
+ area.size.width = ICONSIZE;
+ area.size.height= ICONSIZE;
+ img = [[NSImage imageNamed: @"NSApplicationIcon"] copy];
+ [img setScalesWhenResized: YES];
+ [img setSize: NSMakeSize (ICONSIZE, ICONSIZE)];
+ imgView = [[NSImageView alloc] initWithFrame: area];
+ [imgView setImage: img];
+ [imgView setEditable: NO];
+ [img autorelease];
+ [imgView autorelease];
aStyle = NSTitledWindowMask;
flag = YES;
[super initWithContentRect: contentRect styleMask: aStyle
backing: backingType defer: flag];
contentView = [[FlippedView alloc] initWithFrame: [[self contentView] frame]];
+ [contentView autorelease];
+
[self setContentView: contentView];
[[self contentView] setAutoresizesSubviews: YES];
prototype: cell
numberOfRows: 0
numberOfColumns: 1];
- [[self contentView] addSubview: matrix];
- [matrix release];
[matrix setFrameOrigin: NSMakePoint (area.origin.x,
area.origin.y + (TEXTHEIGHT+3*SPACER))];
[matrix setIntercellSpacing: spacing];
+ [matrix autorelease];
+ [[self contentView] addSubview: matrix];
[self setOneShot: YES];
[self setReleasedWhenClosed: YES];
[self setHidesOnDeactivate: YES];
+ [self setStyleMask:
+ NSTitledWindowMask|NSClosableWindowMask|NSUtilityWindowMask];
+
return self;
}
- (BOOL)windowShouldClose: (id)sender
{
- [NSApp stopModalWithCode: XHASH (Qnil)]; // FIXME: BIG UGLY HACK!!
+ window_closed = YES;
+ [NSApp stop:self];
return NO;
}
+- (void)dealloc
+{
+ xfree (button_values);
+ [super dealloc];
+}
-void process_dialog (id window, Lisp_Object list)
+- (void)process_dialog: (Lisp_Object) list
{
- Lisp_Object item;
+ Lisp_Object item, lst = list;
int row = 0;
+ int buttons = 0, btnnr = 0;
+
+ for (; XTYPE (lst) == Lisp_Cons; lst = XCDR (lst))
+ {
+ item = XCAR (list);
+ if (XTYPE (item) == Lisp_Cons)
+ ++buttons;
+ }
+
+ if (buttons > 0)
+ button_values = (Lisp_Object *) xmalloc (buttons * sizeof (*button_values));
for (; XTYPE (list) == Lisp_Cons; list = XCDR (list))
{
item = XCAR (list);
if (XTYPE (item) == Lisp_String)
{
- [window addString: SDATA (item) row: row++];
+ [self addString: SSDATA (item) row: row++];
}
else if (XTYPE (item) == Lisp_Cons)
{
- [window addButton: SDATA (XCAR (item))
- value: XCDR (item) row: row++];
+ button_values[btnnr] = XCDR (item);
+ [self addButton: SSDATA (XCAR (item)) value: btnnr row: row++];
+ ++btnnr;
}
else if (NILP (item))
{
- [window addSplit];
+ [self addSplit];
row = 0;
}
}
}
-- addButton: (char *)str value: (Lisp_Object)val row: (int)row
+- (void)addButton: (char *)str value: (int)tag row: (int)row
{
id cell;
[cell setTarget: self];
[cell setAction: @selector (clicked: )];
[cell setTitle: [NSString stringWithUTF8String: str]];
- [cell setTag: XHASH (val)]; // FIXME: BIG UGLY HACK!!
+ [cell setTag: tag];
[cell setBordered: YES];
[cell setEnabled: YES];
-
- return self;
}
-- addString: (char *)str row: (int)row
+- (void)addString: (char *)str row: (int)row
{
id cell;
[cell setTitle: [NSString stringWithUTF8String: str]];
[cell setBordered: YES];
[cell setEnabled: NO];
-
- return self;
}
-- addSplit
+- (void)addSplit
{
[matrix addColumn];
cols++;
- return self;
}
-- clicked: sender
+- (void)clicked: sender
{
NSArray *sellist = nil;
EMACS_INT seltag;
sellist = [sender selectedCells];
- if ([sellist count]<1)
- return self;
+ if ([sellist count] < 1)
+ return;
seltag = [[sellist objectAtIndex: 0] tag];
- if (seltag != XHASH (Qundefined)) // FIXME: BIG UGLY HACK!!
- [NSApp stopModalWithCode: seltag];
- return self;
+ dialog_return = button_values[seltag];
+ [NSApp stop:self];
}
if (XTYPE (contents) == Lisp_Cons)
{
head = Fcar (contents);
- process_dialog (self, Fcdr (contents));
+ [self process_dialog: Fcdr (contents)];
}
else
head = contents;
if (XTYPE (head) == Lisp_String)
[title setStringValue:
- [NSString stringWithUTF8String: SDATA (head)]];
+ [NSString stringWithUTF8String: SSDATA (head)]];
else if (isQ == YES)
[title setStringValue: @"Question"];
else
if (cols == 1 && rows > 1) /* Never told where to split */
{
[matrix addColumn];
- for (i = 0; i<rows/2; i++)
+ for (i = 0; i < rows/2; i++)
{
[matrix putCell: [matrix cellAtRow: (rows+1)/2 column: 0]
atRow: i column: 1];
}
-- (void)dealloc
+
+- (void)timeout_handler: (NSTimer *)timedEntry
{
- { [super dealloc]; return; };
+ NSEvent *nxev = [NSEvent otherEventWithType: NSApplicationDefined
+ location: NSMakePoint (0, 0)
+ modifierFlags: 0
+ timestamp: 0
+ windowNumber: [[NSApp mainWindow] windowNumber]
+ context: [NSApp context]
+ subtype: 0
+ data1: 0
+ data2: 0];
+
+ timer_fired = YES;
+ /* We use sto because stopModal/abortModal out of the main loop does not
+ seem to work in 10.6. But as we use stop we must send a real event so
+ the stop is seen and acted upon. */
+ [NSApp stop:self];
+ [NSApp postEvent: nxev atStart: NO];
}
-
- (Lisp_Object)runDialogAt: (NSPoint)p
{
- NSInteger ret;
- extern EMACS_TIME timer_check (int do_it_now); /* TODO: add to a header */
-
- /* initiate a session that will be ended by pop_down_menu */
- popupSession = [NSApp beginModalSessionForWindow: self];
- while (popup_activated_flag
- && (ret = [NSApp runModalSession: popupSession])
- == NSRunContinuesResponse)
+ Lisp_Object ret = Qundefined;
+
+ while (popup_activated_flag)
{
- /* Run this for timers.el, indep of atimers; might not return.
- TODO: use return value to avoid calling every iteration. */
- timer_check (1);
- [NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1]];
+ NSTimer *tmo = nil;
+ EMACS_TIME next_time = timer_check ();
+
+ if (EMACS_TIME_VALID_P (next_time))
+ {
+ double time = EMACS_TIME_TO_DOUBLE (next_time);
+ tmo = [NSTimer timerWithTimeInterval: time
+ target: self
+ selector: @selector (timeout_handler:)
+ userInfo: 0
+ repeats: NO];
+ [[NSRunLoop currentRunLoop] addTimer: tmo
+ forMode: NSModalPanelRunLoopMode];
+ }
+ timer_fired = NO;
+ dialog_return = Qundefined;
+ [NSApp runModalForWindow: self];
+ ret = dialog_return;
+ if (! timer_fired)
+ {
+ if (tmo != nil) [tmo invalidate]; /* Cancels timer */
+ break;
+ }
}
- { /* FIXME: BIG UGLY HACK!!! */
- Lisp_Object tmp;
- *(EMACS_INT*)(&tmp) = ret;
- return tmp;
- }
+ if (EQ (ret, Qundefined) && window_closed)
+ /* Make close button pressed equivalent to C-g. */
+ Fsignal (Qquit, Qnil);
+
+ return ret;
}
@end
DEFUN ("ns-reset-menu", Fns_reset_menu, Sns_reset_menu, 0, 0, 0,
doc: /* Cause the NS menu to be re-calculated. */)
- ()
+ (void)
{
set_frame_menubar (SELECTED_FRAME (), 1, 0);
return Qnil;
If the user gets rid of the dialog box without making a valid choice,
for instance using the window manager, then this produces a quit and
`x-popup-dialog' does not return. */)
- (position, contents, header)
- Lisp_Object position, contents, header;
+ (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
{
return ns_popup_dialog (position, contents, header);
}
DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
doc: /* Return t if a menu or popup dialog is active. */)
- ()
+ (void)
{
return popup_activated () ? Qt : Qnil;
}
========================================================================== */
void
-syms_of_nsmenu ()
+syms_of_nsmenu (void)
{
+#ifndef NS_IMPL_COCOA
+ /* Don't know how to keep track of this in Next/Open/Gnustep. Always
+ update menus there. */
+ trackingMenu = 1;
+#endif
defsubr (&Sx_popup_dialog);
defsubr (&Sns_reset_menu);
defsubr (&Smenu_or_popup_active_p);
- Qdebug_on_next_call = intern ("debug-on-next-call");
+ Qdebug_on_next_call = intern_c_string ("debug-on-next-call");
staticpro (&Qdebug_on_next_call);
}
-
-// arch-tag: 75773656-52e5-4c44-a398-47bd87b32619