/* NeXT/Open/GNUstep and MacOSX Cocoa menu and toolbar module.
- Copyright (C) 2007-2011 Free Software Foundation, Inc.
+ Copyright (C) 2007-2012 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include "lisp.h"
#include "window.h"
+#include "character.h"
#include "buffer.h"
#include "keymap.h"
#include "coding.h"
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. */
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;
+ buffer = WVAR (XWINDOW (FRAME_SELECTED_WINDOW (f)), buffer);
specbind (Qinhibit_quit, Qt);
specbind (Qdebug_on_next_call, Qnil);
record_unwind_save_match_data ();
/* Save the frame's previous menu bar contents data */
if (previous_menu_items_used)
- memcpy (previous_items, &AREF (f->menu_bar_vector, 0),
+ memcpy (previous_items, aref_addr (FVAR (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 = FVAR (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;
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)
{
}
/* 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;
+ FVAR (f, menu_bar_vector) = 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 = SSDATA (string);
items = FRAME_MENU_BAR_ITEMS (f);
if (NILP (items))
{
+ free_menubar_widget_value_tree (first_wv);
[pool release];
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;
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 = SSDATA (string);
/* 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
+ 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
/* 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)
{
EmacsMenu *pmenu;
NSPoint p;
- Lisp_Object window, tem, keymap;
+ Lisp_Object tem;
ptrdiff_t specpdl_count = SPECPDL_INDEX ();
widget_value *wv, *first_wv = 0;
{
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;
/* 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))
}
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);
/* update EmacsToolbar as in GtkUtils, build items list */
for (i = 0; i < f->n_tool_bar_items; ++i)
{
-#define TOOLPROP(IDX) AREF (f->tool_bar_items, \
+#define TOOLPROP(IDX) AREF (FVAR (f, tool_bar_items), \
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;
ptrdiff_t img_id;
struct image *img;
{
/* 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
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];
========================================================================== */
+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;
}
struct frame *f;
NSPoint p;
BOOL isQ;
+ NSAutoreleasePool *pool;
NSTRACE (x-popup-dialog);
contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil));
BLOCK_INPUT;
+ pool = [[NSAutoreleasePool alloc] init];
dialog = [[EmacsDialogPanel alloc] initFromContents: contents
isQuestion: isQ];
+
{
ptrdiff_t specpdl_count = SPECPDL_INDEX ();
- record_unwind_protect (pop_down_menu, make_save_value (dialog, 0));
+ 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;
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;
+
+ 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];
item = XCAR (list);
if (XTYPE (item) == Lisp_String)
{
- [window addString: SDATA (item) row: row++];
+ [window addString: SSDATA (item) row: row++];
}
else if (XTYPE (item) == Lisp_Cons)
{
- [window addButton: SDATA (XCAR (item))
+ [window addButton: SSDATA (XCAR (item))
value: XCDR (item) row: row++];
}
else if (NILP (item))
if (XTYPE (head) == Lisp_String)
[title setStringValue:
- [NSString stringWithUTF8String: SDATA (head)]];
+ [NSString stringWithUTF8String: SSDATA (head)]];
else if (isQ == YES)
[title setStringValue: @"Question"];
else
}
-- (void)dealloc
-{
- { [super dealloc]; return; };
-}
-
-
- (Lisp_Object)runDialogAt: (NSPoint)p
{
NSInteger ret;
void
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);