/* 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 <config.h>
#include <setjmp.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;
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;
}
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;
/* 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 (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)
{
/* if (submenu && strcmp (submenuTitle, SDATA (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;
return;
break;
else
continue;
- if (strncmp (previous_strings[i], SDATA (string), 10))
+ 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], min (10, SBYTES (string) + 1),
+ SDATA (string));
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
}
-/* 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
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)
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 ();
+ 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
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;
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 */
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
[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
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;
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;
+ 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;
dialog = [[EmacsDialogPanel alloc] initFromContents: contents
isQuestion: isQ];
{
- int specpdl_count = SPECPDL_INDEX ();
+ ptrdiff_t specpdl_count = SPECPDL_INDEX ();
record_unwind_protect (pop_down_menu, make_save_value (dialog, 0));
popup_activated_flag = 1;
tem = [dialog runDialogAt: p];
- (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];
{
/* Run this for timers.el, indep of atimers; might not return.
TODO: use return value to avoid calling every iteration. */
- timer_check (1);
+ timer_check ();
[NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1]];
}
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