X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/5df4f04cd32af723742c81095b38ae83b3c2b462..cb993c584c8ef91f5352ec9aa97d26fd76cfd643:/src/nsmenu.m diff --git a/src/nsmenu.m b/src/nsmenu.m index 5fd74333f2..951282910a 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -1,5 +1,5 @@ /* NeXT/Open/GNUstep and MacOSX Cocoa menu and toolbar module. - Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + Copyright (C) 2007-2011 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -23,7 +23,7 @@ Carbon version by Yamamoto Mitsuharu. */ /* This should be the first include, as it may set up #defines affecting interpretation of even the system includes. */ -#include "config.h" +#include #include #include "lisp.h" @@ -65,8 +65,7 @@ extern Lisp_Object Qundefined, Qmenu_enable, Qmenu_bar_update_hook; 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; @@ -105,7 +104,7 @@ free_frame_menubar (struct frame *f) int -popup_activated () +popup_activated (void) { return popup_activated_flag; } @@ -219,27 +218,27 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu) /* 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 (XVECTOR (items)->size * sizeof (int *)); - submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *)); - submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int)); + 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 (XVECTOR (items)->size * sizeof (int *)); + = (int *) alloca (ASIZE (items) * sizeof (int *)); init_menu_items (); - for (i = 0; i < XVECTOR (items)->size; i += 4) + for (i = 0; i < ASIZE (items); i += 4) { Lisp_Object key, string, maps; - key = XVECTOR (items)->contents[i]; - string = XVECTOR (items)->contents[i + 1]; - maps = XVECTOR (items)->contents[i + 2]; + key = AREF (items, i); + string = AREF (items, i + 1); + maps = AREF (items, i + 2); if (NILP (string)) break; @@ -312,11 +311,11 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu) /* FIXME: this ALWAYS fails on Buffers menu items.. something about their strings causes them to change every time, so we double-check failures */ - if (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])) + if (!EQ (previous_items[i], AREF (menu_items, i))) if (!(STRINGP (previous_items[i]) - && STRINGP (XVECTOR (menu_items)->contents[i]) + && STRINGP (AREF (menu_items, i)) && !strcmp (SDATA (previous_items[i]), - SDATA (XVECTOR (menu_items)->contents[i])))) + SDATA (AREF (menu_items, i))))) break; if (i == previous_menu_items_used) { @@ -347,16 +346,16 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu) /* Parse stage 2a: now GC cannot happen during the lifetime of the widget_value, so it's safe to store data from a Lisp_String */ wv = first_wv->contents; - for (i = 0; i < XVECTOR (items)->size; i += 4) + for (i = 0; i < ASIZE (items); i += 4) { Lisp_Object string; - string = XVECTOR (items)->contents[i + 1]; + string = AREF (items, i + 1); if (NILP (string)) break; /* if (submenu && strcmp (submenuTitle, SDATA (string))) continue; */ - wv->name = (char *) SDATA (string); + wv->name = SSDATA (string); update_submenu_strings (wv->contents); wv = wv->next; } @@ -408,7 +407,7 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu) /* check if no change.. this mechanism is a bit rough, but ready */ - n = XVECTOR (items)->size / 4; + n = ASIZE (items) / 4; if (f == last_f && n_previous_strings == n) { for (i = 0; isize; i += 4) + for (i = 0; i < ASIZE (items); i += 4) { - string = XVECTOR (items)->contents[i + 1]; + string = AREF (items, i + 1); if (NILP (string)) break; @@ -445,7 +444,7 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu) strncpy (previous_strings[i/4], SDATA (string), 10); 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; @@ -458,7 +457,6 @@ ns_update_menubar (struct frame *f, int deep_p, EmacsMenu *submenu) { /* but we need to make sure it will update on demand */ [svcsMenu setFrame: f]; - [svcsMenu setDelegate: svcsMenu]; } else #endif @@ -507,22 +505,6 @@ set_frame_menubar (struct frame *f, int first_time, int deep_p) } -/* 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 @@ -601,14 +583,14 @@ name_is_separator (name) 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)) return @""; - + while (*tpos == ' ' || *tpos == '(') tpos++; if ((*tpos == 's') && (*(tpos+1) == '-')) @@ -625,7 +607,7 @@ name_is_separator (name) 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]; @@ -669,7 +651,7 @@ name_is_separator (name) -(void)clear { int n; - + for (n = [self numberOfItems]-1; n >= 0; n--) { NSMenuItem *item = [self itemAtIndex: n]; @@ -713,14 +695,16 @@ name_is_separator (name) 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 @@ -737,19 +721,21 @@ name_is_separator (name) 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]; @@ -772,7 +758,7 @@ name_is_separator (name) 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; @@ -809,7 +795,7 @@ ns_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, i = 0; while (i < menu_items_used) { - if (EQ (XVECTOR (menu_items)->contents[i], Qnil)) + if (EQ (AREF (menu_items, i), Qnil)) { submenu_stack[submenu_depth++] = save_wv; save_wv = prev_wv; @@ -817,25 +803,25 @@ ns_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, first_pane = 1; i++; } - else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda)) + else if (EQ (AREF (menu_items, i), Qlambda)) { prev_wv = save_wv; save_wv = submenu_stack[--submenu_depth]; first_pane = 0; i++; } - else if (EQ (XVECTOR (menu_items)->contents[i], Qt) + else if (EQ (AREF (menu_items, i), Qt) && submenu_depth != 0) i += MENU_ITEMS_PANE_LENGTH; /* Ignore a nil in the item list. It's meaningful only for dialog boxes. */ - else if (EQ (XVECTOR (menu_items)->contents[i], Qquote)) + else if (EQ (AREF (menu_items, i), Qquote)) i += 1; - else if (EQ (XVECTOR (menu_items)->contents[i], Qt)) + else if (EQ (AREF (menu_items, i), Qt)) { /* 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); @@ -848,7 +834,7 @@ ns_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, } #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) @@ -913,15 +899,15 @@ ns_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, 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 *) &XVECTOR (menu_items)->contents[i] : 0; + = !NILP (def) ? (void *) &AREF (menu_items, i) : 0; wv->enabled = !NILP (enable); if (NILP (type)) @@ -964,7 +950,7 @@ ns_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, 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; @@ -999,7 +985,10 @@ free_frame_tool_bar (FRAME_PTR f) 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 @@ -1009,8 +998,11 @@ update_frame_tool_bar (FRAME_PTR f) -------------------------------------------------------------------------- */ { 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 */ @@ -1022,11 +1014,11 @@ update_frame_tool_bar (FRAME_PTR f) 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. */ @@ -1042,10 +1034,15 @@ update_frame_tool_bar (FRAME_PTR f) { 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; } @@ -1059,11 +1056,6 @@ update_frame_tool_bar (FRAME_PTR f) 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 @@ -1094,6 +1086,10 @@ update_frame_tool_bar (FRAME_PTR f) [newDict release]; } + FRAME_TOOLBAR_HEIGHT (f) = + NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)]) + - FRAME_NS_TITLEBAR_HEIGHT (f); + UNBLOCK_INPUT; } @@ -1142,7 +1138,7 @@ update_frame_tool_bar (FRAME_PTR f) } - (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 @@ -1232,8 +1228,8 @@ update_frame_tool_bar (FRAME_PTR f) [textField setEditable: NO]; [textField setSelectable: NO]; - [textField setBordered: YES]; - [textField setBezeled: YES]; + [textField setBordered: NO]; + [textField setBezeled: NO]; [textField setDrawsBackground: YES]; win = [[NSWindow alloc] @@ -1241,6 +1237,7 @@ update_frame_tool_bar (FRAME_PTR f) styleMask: 0 backing: NSBackingStoreBuffered defer: YES]; + [win setHasShadow: YES]; [win setReleasedWhenClosed: NO]; [win setDelegate: self]; [[win contentView] addSubview: textField]; @@ -1261,17 +1258,15 @@ update_frame_tool_bar (FRAME_PTR f) - (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 @@ -1344,13 +1339,13 @@ Lisp_Object 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; NSTRACE (x-popup-dialog); - + check_ns (); isQ = NILP (header); @@ -1393,6 +1388,14 @@ ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header) 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]; @@ -1512,10 +1515,10 @@ ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header) [cell setCellAttribute: NSCellIsInsetButton to: 8]; [cell setBezelStyle: NSRoundedBezelStyle]; - matrix = [[NSMatrix alloc] initWithFrame: contentRect - mode: NSHighlightModeMatrix - prototype: cell - numberOfRows: 0 + matrix = [[NSMatrix alloc] initWithFrame: contentRect + mode: NSHighlightModeMatrix + prototype: cell + numberOfRows: 0 numberOfColumns: 1]; [[self contentView] addSubview: matrix]; [matrix release]; @@ -1566,7 +1569,7 @@ void process_dialog (id window, Lisp_Object list) - addButton: (char *)str value: (Lisp_Object)val row: (int)row { id cell; - + if (row >= rows) { [matrix addRow]; @@ -1587,7 +1590,7 @@ void process_dialog (id window, Lisp_Object list) - addString: (char *)str row: (int)row { id cell; - + if (row >= rows) { [matrix addRow]; @@ -1616,7 +1619,7 @@ void process_dialog (id window, Lisp_Object list) EMACS_INT seltag; sellist = [sender selectedCells]; - if ([sellist count]<1) + if ([sellist count]<1) return self; seltag = [[sellist objectAtIndex: 0] tag]; @@ -1710,7 +1713,6 @@ void process_dialog (id window, Lisp_Object list) - (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]; @@ -1720,7 +1722,7 @@ void process_dialog (id window, Lisp_Object list) { /* 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]]; } @@ -1742,7 +1744,7 @@ void process_dialog (id window, Lisp_Object list) 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; @@ -1772,15 +1774,14 @@ otherwise it is "Question". 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; } @@ -1792,14 +1793,12 @@ DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_ ========================================================================== */ void -syms_of_nsmenu () +syms_of_nsmenu (void) { 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