2001-12-17 16:51:51 +00:00
|
|
|
/** <title>NSMenu</title>
|
1999-07-06 15:50:03 +00:00
|
|
|
|
2016-12-31 16:03:01 +00:00
|
|
|
Copyright (C) 1999,2016 Free Software Foundation, Inc.
|
1999-07-06 15:50:03 +00:00
|
|
|
|
2001-08-21 23:24:35 +00:00
|
|
|
Author: Fred Kiefer <FredKiefer@gmx.de>
|
|
|
|
Date: Aug 2001
|
1999-11-16 22:25:07 +00:00
|
|
|
Author: David Lazaro Saz <khelekir@encomix.es>
|
|
|
|
Date: Oct 1999
|
2001-12-17 16:51:51 +00:00
|
|
|
Author: Michael Hanni <mhanni@sprintmail.com>
|
1999-07-18 03:53:42 +00:00
|
|
|
Date: 1999
|
2001-12-17 16:51:51 +00:00
|
|
|
Author: Felipe A. Rodriguez <far@ix.netcom.com>
|
1999-11-16 22:25:07 +00:00
|
|
|
Date: July 1998
|
1999-07-20 09:21:31 +00:00
|
|
|
and:
|
1999-07-18 03:53:42 +00:00
|
|
|
Author: Ovidiu Predescu <ovidiu@net-community.com>
|
|
|
|
Date: May 1997
|
1999-07-06 15:50:03 +00:00
|
|
|
|
|
|
|
This file is part of the GNUstep GUI Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-10-29 21:16:17 +00:00
|
|
|
modify it under the terms of the GNU Lesser General Public
|
1999-07-06 15:50:03 +00:00
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-10 04:01:49 +00:00
|
|
|
version 2 of the License, or (at your option) any later version.
|
2007-10-29 21:16:17 +00:00
|
|
|
|
1999-07-06 15:50:03 +00:00
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2007-10-29 21:16:17 +00:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
1999-07-06 15:50:03 +00:00
|
|
|
|
2007-10-29 21:16:17 +00:00
|
|
|
You should have received a copy of the GNU Lesser General Public
|
1999-07-06 15:50:03 +00:00
|
|
|
License along with this library; see the file COPYING.LIB.
|
2007-10-29 21:16:17 +00:00
|
|
|
If not, see <http://www.gnu.org/licenses/> or write to the
|
|
|
|
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
1999-07-06 15:50:03 +00:00
|
|
|
*/
|
|
|
|
|
2010-03-25 09:11:50 +00:00
|
|
|
#import "config.h"
|
|
|
|
#import <Foundation/NSCoder.h>
|
|
|
|
#import <Foundation/NSArray.h>
|
2010-08-02 14:00:24 +00:00
|
|
|
#import <Foundation/NSCharacterSet.h>
|
2010-03-25 09:11:50 +00:00
|
|
|
#import <Foundation/NSDebug.h>
|
|
|
|
#import <Foundation/NSException.h>
|
|
|
|
#import <Foundation/NSProcessInfo.h>
|
|
|
|
#import <Foundation/NSString.h>
|
|
|
|
#import <Foundation/NSNotification.h>
|
|
|
|
#import <Foundation/NSNotificationQueue.h>
|
|
|
|
#import <Foundation/NSRunLoop.h>
|
|
|
|
#import <Foundation/NSUserDefaults.h>
|
|
|
|
#import <Foundation/NSValue.h>
|
1997-07-07 16:56:52 +00:00
|
|
|
|
2010-03-25 09:11:50 +00:00
|
|
|
#import "AppKit/NSMatrix.h"
|
|
|
|
#import "AppKit/NSApplication.h"
|
2013-07-12 05:03:34 +00:00
|
|
|
#import "AppKit/NSCursor.h"
|
2010-03-25 09:11:50 +00:00
|
|
|
#import "AppKit/NSWindow.h"
|
|
|
|
#import "AppKit/NSEvent.h"
|
|
|
|
#import "AppKit/NSFont.h"
|
|
|
|
#import "AppKit/NSImage.h"
|
|
|
|
#import "AppKit/NSMenu.h"
|
|
|
|
#import "AppKit/NSMenuItem.h"
|
|
|
|
#import "AppKit/NSMenuView.h"
|
|
|
|
#import "AppKit/NSPanel.h"
|
|
|
|
#import "AppKit/NSPopUpButton.h"
|
|
|
|
#import "AppKit/NSPopUpButtonCell.h"
|
|
|
|
#import "AppKit/NSScreen.h"
|
|
|
|
#import "AppKit/NSAttributedString.h"
|
1997-07-07 16:56:52 +00:00
|
|
|
|
2010-03-25 09:11:50 +00:00
|
|
|
#import "GSGuiPrivate.h"
|
2010-05-12 09:02:25 +00:00
|
|
|
#import "NSDocumentFrameworkPrivate.h"
|
2010-03-25 09:11:50 +00:00
|
|
|
#import "GNUstepGUI/GSTheme.h"
|
2002-10-20 01:48:55 +00:00
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
/*
|
|
|
|
Drawing related:
|
|
|
|
|
2006-03-05 13:21:33 +00:00
|
|
|
NSMenu superMenu (if not root menu, the parent meu)
|
|
|
|
^
|
|
|
|
|
|
|
|
|
| +------------------> NSMenuView view (content, draws the menu items)
|
|
|
|
| |
|
|
|
|
NSMenu +----------+-------> NSMenuPanel A (regular window, torn off window)
|
|
|
|
| | `-------> NSMenuPanel B (transient window)
|
|
|
|
| |
|
|
|
|
| +------------------> NSString title (title)
|
|
|
|
|
|
|
|
|
v
|
|
|
|
NSMenu attachedMenu (the menu attached to this one, during navigation)
|
2003-03-07 05:33:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+--[NSMenuPanel]------+
|
|
|
|
| +-[NSMenuView]----+ |
|
|
|
|
| | title if applic | |
|
|
|
|
| | +-------------+ | |
|
|
|
|
| | | NSMenuItem- | | |
|
|
|
|
| | | Cell | | |
|
|
|
|
| | +-------------+ | |
|
|
|
|
| | . | |
|
|
|
|
| | . | |
|
|
|
|
| +-----------------+ |
|
|
|
|
+---------------------+
|
|
|
|
|
|
|
|
The two windows
|
|
|
|
---------------
|
|
|
|
|
|
|
|
Basically we have for a menu two windows, window A and window B.
|
|
|
|
Window A is the regular window and Window B is used for transient windows.
|
|
|
|
|
|
|
|
At any one time, the views, like title view, NSMenuView are put either in
|
|
|
|
window A or in window B. They are moved over from one window to the oter
|
|
|
|
when needed.
|
|
|
|
|
|
|
|
the code is supposed to know when it is using window A or B.
|
|
|
|
But it will probably only work correctly when
|
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
window A correspond to transient == NO
|
|
|
|
window B correspond to transient == YES
|
2003-03-07 05:33:17 +00:00
|
|
|
*/
|
2001-08-19 23:21:59 +00:00
|
|
|
|
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
/* Subclass of NSPanel since menus cannot become key */
|
|
|
|
@interface NSMenuPanel : NSPanel
|
2010-01-05 08:37:44 +00:00
|
|
|
{
|
|
|
|
NSMenu *_the_menu;
|
|
|
|
}
|
2010-05-24 10:48:14 +00:00
|
|
|
- (void) _setmenu: (NSMenu *)menu;
|
2001-08-19 23:21:59 +00:00
|
|
|
@end
|
|
|
|
|
2002-09-15 14:02:17 +00:00
|
|
|
@interface NSMenuView (GNUstepPrivate)
|
|
|
|
- (NSArray *)_itemCells;
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
static NSZone *menuZone = NULL;
|
2003-06-05 14:46:04 +00:00
|
|
|
static NSString *NSMenuLocationsKey = @"NSMenuLocations";
|
2003-03-07 05:33:17 +00:00
|
|
|
static NSString *NSEnqueuedMenuMoveName = @"EnqueuedMoveNotificationName";
|
2001-08-27 18:49:34 +00:00
|
|
|
static NSNotificationCenter *nc;
|
2007-12-25 14:53:45 +00:00
|
|
|
static BOOL menuBarVisible = YES;
|
1999-08-19 23:18:25 +00:00
|
|
|
|
2000-01-07 16:46:35 +00:00
|
|
|
@interface NSMenu (GNUstepPrivate)
|
2003-03-07 05:33:17 +00:00
|
|
|
|
2010-05-12 09:02:25 +00:00
|
|
|
- (NSString *) _name;
|
|
|
|
- (void) _setName: (NSString *)name;
|
2002-10-20 01:48:55 +00:00
|
|
|
- (NSMenuPanel *) _createWindow;
|
2006-10-02 05:09:48 +00:00
|
|
|
- (NSString *) _locationKey;
|
2003-03-19 16:15:21 +00:00
|
|
|
- (void) _rightMouseDisplay: (NSEvent*)theEvent;
|
2006-10-02 05:09:48 +00:00
|
|
|
- (void) _setGeometry;
|
|
|
|
- (void) _updateUserDefaults: (id) notification;
|
2010-05-24 10:48:14 +00:00
|
|
|
- (void) _organizeMenu;
|
2017-01-08 19:33:32 +00:00
|
|
|
- (BOOL) _isVisible;
|
|
|
|
- (BOOL) _isMain;
|
2003-03-07 05:33:17 +00:00
|
|
|
|
2002-10-20 01:48:55 +00:00
|
|
|
@end
|
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
|
2002-10-20 01:48:55 +00:00
|
|
|
@implementation NSMenuPanel
|
2010-01-05 08:37:44 +00:00
|
|
|
- (void) _setmenu: (NSMenu *)menu
|
|
|
|
{
|
|
|
|
_the_menu = menu;
|
|
|
|
}
|
|
|
|
|
2002-10-20 01:48:55 +00:00
|
|
|
- (BOOL) canBecomeKeyWindow
|
|
|
|
{
|
2002-11-08 16:39:41 +00:00
|
|
|
/* See [NSWindow-_lossOfKeyOrMainWindow] */
|
2017-01-08 19:33:32 +00:00
|
|
|
return [_the_menu _isMain];
|
2002-10-20 01:48:55 +00:00
|
|
|
}
|
2010-01-05 08:37:44 +00:00
|
|
|
|
|
|
|
- (void) orderFrontRegardless
|
|
|
|
{
|
|
|
|
NSInterfaceStyle style = NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil);
|
|
|
|
if (style == NSWindows95InterfaceStyle)
|
|
|
|
{
|
|
|
|
// if we're the top level menu in Windows mode, don't show it.
|
2010-01-19 18:48:00 +00:00
|
|
|
if([_the_menu supermenu] == nil && [_the_menu _ownedByPopUp] == NO)
|
2010-01-05 08:37:44 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[super orderFrontRegardless];
|
|
|
|
}
|
2000-01-07 16:46:35 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSMenu (GNUstepPrivate)
|
2001-08-21 23:24:35 +00:00
|
|
|
|
2010-05-12 09:02:25 +00:00
|
|
|
- (NSString *) _name;
|
|
|
|
{
|
|
|
|
return _name;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _setName: (NSString *)aName
|
|
|
|
{
|
|
|
|
ASSIGNCOPY(_name, aName);
|
|
|
|
}
|
|
|
|
|
2000-01-07 16:46:35 +00:00
|
|
|
- (NSString*) _locationKey
|
|
|
|
{
|
2008-07-08 20:17:44 +00:00
|
|
|
NSInterfaceStyle style = NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil);
|
2009-01-25 13:47:30 +00:00
|
|
|
if (style == NSMacintoshInterfaceStyle
|
|
|
|
|| style == NSWindows95InterfaceStyle)
|
2006-02-04 19:58:55 +00:00
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
2001-08-19 23:21:59 +00:00
|
|
|
if (_superMenu == nil)
|
2000-01-07 16:46:35 +00:00
|
|
|
{
|
2017-01-08 19:33:32 +00:00
|
|
|
if ([self _isMain])
|
2000-01-07 16:46:35 +00:00
|
|
|
{
|
|
|
|
return @"\033"; /* Root menu. */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return nil; /* Unused menu. */
|
|
|
|
}
|
|
|
|
}
|
2001-08-19 23:21:59 +00:00
|
|
|
else if (_superMenu->_superMenu == nil)
|
2000-01-07 16:46:35 +00:00
|
|
|
{
|
|
|
|
return [NSString stringWithFormat: @"\033%@", [self title]];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
return [[_superMenu _locationKey] stringByAppendingFormat: @"\033%@",
|
2000-01-07 16:46:35 +00:00
|
|
|
[self title]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-02-23 11:16:59 +00:00
|
|
|
/* Create a non autorelease window for this menu. */
|
2002-10-20 01:48:55 +00:00
|
|
|
- (NSMenuPanel*) _createWindow
|
2001-08-21 23:24:35 +00:00
|
|
|
{
|
2002-10-20 01:48:55 +00:00
|
|
|
NSMenuPanel *win = [[NSMenuPanel alloc]
|
2001-08-21 23:24:35 +00:00
|
|
|
initWithContentRect: NSZeroRect
|
|
|
|
styleMask: NSBorderlessWindowMask
|
|
|
|
backing: NSBackingStoreBuffered
|
|
|
|
defer: YES];
|
2010-02-13 03:24:19 +00:00
|
|
|
[win setBackgroundColor: [NSColor clearColor]];
|
2001-08-21 23:24:35 +00:00
|
|
|
[win setLevel: NSSubmenuWindowLevel];
|
2002-07-12 01:41:35 +00:00
|
|
|
[win setWorksWhenModal: NO];
|
2001-08-21 23:24:35 +00:00
|
|
|
[win setBecomesKeyOnlyIfNeeded: YES];
|
2010-01-05 08:37:44 +00:00
|
|
|
[win _setmenu: self];
|
2001-08-21 23:24:35 +00:00
|
|
|
|
|
|
|
return win;
|
|
|
|
}
|
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
/**
|
|
|
|
Will track the mouse movement. It will trigger the updating of the user
|
|
|
|
defaults in due time.
|
|
|
|
*/
|
|
|
|
- (void) _menuMoved: (id) notification
|
|
|
|
{
|
|
|
|
NSNotification *resend;
|
|
|
|
|
|
|
|
resend = [NSNotification notificationWithName: NSEnqueuedMenuMoveName
|
2003-03-07 05:50:53 +00:00
|
|
|
object: self];
|
2003-03-07 05:33:17 +00:00
|
|
|
|
|
|
|
[[NSNotificationQueue defaultQueue]
|
|
|
|
enqueueNotification: resend
|
|
|
|
postingStyle: NSPostASAP
|
|
|
|
coalesceMask: NSNotificationCoalescingOnSender
|
|
|
|
forModes: [NSArray arrayWithObject: NSDefaultRunLoopMode]];
|
|
|
|
}
|
|
|
|
|
2006-02-04 19:58:55 +00:00
|
|
|
- (void) _organizeMenu
|
|
|
|
{
|
2009-03-01 19:13:19 +00:00
|
|
|
NSString *infoString = _(@"Info");
|
|
|
|
NSString *servicesString = _(@"Services");
|
2009-02-17 18:24:44 +00:00
|
|
|
int i;
|
2006-10-02 05:09:48 +00:00
|
|
|
|
2017-01-08 19:33:32 +00:00
|
|
|
if ([self _isMain])
|
2006-02-04 19:58:55 +00:00
|
|
|
{
|
2009-02-17 18:24:44 +00:00
|
|
|
NSString *appTitle;
|
|
|
|
NSMenu *appMenu;
|
|
|
|
id <NSMenuItem> appItem;
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2013-02-05 12:14:20 +00:00
|
|
|
appTitle = [[[NSBundle mainBundle] localizedInfoDictionary]
|
|
|
|
objectForKey: @"ApplicationName"];
|
|
|
|
if (nil == appTitle)
|
|
|
|
{
|
|
|
|
appTitle = [[NSProcessInfo processInfo] processName];
|
|
|
|
}
|
2008-01-19 21:48:37 +00:00
|
|
|
appItem = [self itemWithTitle: appTitle];
|
2006-10-02 05:09:48 +00:00
|
|
|
appMenu = [appItem submenu];
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.horizontal == YES)
|
2009-02-17 18:24:44 +00:00
|
|
|
{
|
|
|
|
NSMutableArray *itemsToMove;
|
2011-04-10 20:14:53 +00:00
|
|
|
|
2009-02-17 18:24:44 +00:00
|
|
|
itemsToMove = [NSMutableArray new];
|
|
|
|
|
|
|
|
if (appMenu == nil)
|
|
|
|
{
|
|
|
|
[self insertItemWithTitle: appTitle
|
|
|
|
action: NULL
|
|
|
|
keyEquivalent: @""
|
|
|
|
atIndex: 0];
|
|
|
|
appItem = [self itemAtIndex: 0];
|
|
|
|
appMenu = [NSMenu new];
|
|
|
|
[self setSubmenu: appMenu forItem: appItem];
|
|
|
|
RELEASE(appMenu);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int index = [self indexOfItem: appItem];
|
|
|
|
|
|
|
|
if (index != 0)
|
|
|
|
{
|
|
|
|
RETAIN (appItem);
|
|
|
|
[self removeItemAtIndex: index];
|
|
|
|
[self insertItem: appItem atIndex: 0];
|
|
|
|
RELEASE (appItem);
|
|
|
|
}
|
|
|
|
}
|
2011-04-10 20:14:53 +00:00
|
|
|
|
2011-04-18 22:24:08 +00:00
|
|
|
if ([[GSTheme theme] menuShouldShowIcon])
|
2011-04-10 20:14:53 +00:00
|
|
|
{
|
2011-04-18 22:24:08 +00:00
|
|
|
NSImage *ti;
|
|
|
|
float bar;
|
|
|
|
ti = [[NSApp applicationIconImage] copy];
|
|
|
|
if (ti == nil)
|
|
|
|
{
|
|
|
|
ti = [[NSImage imageNamed: @"GNUstep"] copy];
|
|
|
|
}
|
|
|
|
[ti setScalesWhenResized: YES];
|
|
|
|
bar = [NSMenuView menuBarHeight] - 4;
|
|
|
|
[ti setSize: NSMakeSize(bar, bar)];
|
2011-04-10 20:14:53 +00:00
|
|
|
[appItem setImage: ti];
|
|
|
|
RELEASE(ti);
|
|
|
|
}
|
|
|
|
|
2009-02-17 18:24:44 +00:00
|
|
|
// Collect all simple items plus "Info" and "Services"
|
|
|
|
for (i = 1; i < [_items count]; i++)
|
|
|
|
{
|
|
|
|
NSMenuItem *anItem = [_items objectAtIndex: i];
|
|
|
|
NSString *title = [anItem title];
|
|
|
|
NSMenu *submenu = [anItem submenu];
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2009-02-17 18:24:44 +00:00
|
|
|
if (submenu == nil)
|
|
|
|
{
|
|
|
|
[itemsToMove addObject: anItem];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// The menu may not be localized, so we have to
|
|
|
|
// check both the English and the local version.
|
|
|
|
if ([title isEqual: @"Info"] ||
|
|
|
|
[title isEqual: @"Services"] ||
|
|
|
|
[title isEqual: infoString] ||
|
|
|
|
[title isEqual: servicesString])
|
|
|
|
{
|
|
|
|
[itemsToMove addObject: anItem];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < [itemsToMove count]; i++)
|
|
|
|
{
|
|
|
|
NSMenuItem *anItem = [itemsToMove objectAtIndex: i];
|
2006-10-02 05:09:48 +00:00
|
|
|
|
2009-02-17 18:24:44 +00:00
|
|
|
[self removeItem: anItem];
|
|
|
|
[appMenu addItem: anItem];
|
|
|
|
}
|
|
|
|
|
|
|
|
RELEASE(itemsToMove);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[appItem setImage: nil];
|
|
|
|
if (appMenu != nil)
|
|
|
|
{
|
|
|
|
NSArray *array = [NSArray arrayWithArray: [appMenu itemArray]];
|
|
|
|
/*
|
|
|
|
* Everything above the Serives menu goes into the info submenu,
|
|
|
|
* the rest into the main menu.
|
|
|
|
*/
|
|
|
|
int k = [appMenu indexOfItemWithTitle: servicesString];
|
|
|
|
|
|
|
|
// The menu may not be localized, so we have to
|
|
|
|
// check both the English and the local version.
|
|
|
|
if (k == -1)
|
|
|
|
k = [appMenu indexOfItemWithTitle: @"Services"];
|
|
|
|
|
|
|
|
if ((k > 0) && ([[array objectAtIndex: k - 1] isSeparatorItem]))
|
|
|
|
k--;
|
|
|
|
|
|
|
|
if (k == 1)
|
|
|
|
{
|
|
|
|
// Exactly one info item
|
|
|
|
NSMenuItem *anItem = [array objectAtIndex: 0];
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2009-02-17 18:24:44 +00:00
|
|
|
[appMenu removeItem: anItem];
|
|
|
|
[self insertItem: anItem atIndex: 0];
|
|
|
|
}
|
|
|
|
else if (k > 1)
|
|
|
|
{
|
|
|
|
id <NSMenuItem> infoItem;
|
|
|
|
NSMenu *infoMenu;
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2009-02-17 18:24:44 +00:00
|
|
|
// Multiple info items, add a submenu for them
|
|
|
|
[self insertItemWithTitle: infoString
|
|
|
|
action: NULL
|
|
|
|
keyEquivalent: @""
|
|
|
|
atIndex: 0];
|
|
|
|
infoItem = [self itemAtIndex: 0];
|
|
|
|
infoMenu = [NSMenu new];
|
|
|
|
[self setSubmenu: infoMenu forItem: infoItem];
|
|
|
|
RELEASE(infoMenu);
|
|
|
|
|
|
|
|
for (i = 0; i < k; i++)
|
|
|
|
{
|
|
|
|
NSMenuItem *anItem = [array objectAtIndex: i];
|
|
|
|
|
|
|
|
[appMenu removeItem: anItem];
|
|
|
|
[infoMenu addItem: anItem];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// No service menu, or it is the first item.
|
|
|
|
// We still look for an info item.
|
|
|
|
NSMenuItem *anItem = [array objectAtIndex: 0];
|
|
|
|
NSString *title = [anItem title];
|
|
|
|
|
|
|
|
// The menu may not be localized, so we have to
|
|
|
|
// check both the English and the local version.
|
|
|
|
if ([title isEqual: @"Info"] ||
|
|
|
|
[title isEqual: infoString])
|
|
|
|
{
|
|
|
|
[appMenu removeItem: anItem];
|
|
|
|
[self insertItem: anItem atIndex: 0];
|
|
|
|
k = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
k = 0;
|
|
|
|
}
|
|
|
|
}
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2009-02-17 18:24:44 +00:00
|
|
|
// Copy the remaining entries.
|
|
|
|
for (i = k; i < [array count]; i++)
|
|
|
|
{
|
|
|
|
NSMenuItem *anItem = [array objectAtIndex: i];
|
|
|
|
|
|
|
|
[appMenu removeItem: anItem];
|
|
|
|
[self addItem: anItem];
|
|
|
|
}
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2009-02-17 18:24:44 +00:00
|
|
|
[self removeItem: appItem];
|
|
|
|
}
|
|
|
|
}
|
2006-10-02 05:09:48 +00:00
|
|
|
}
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2009-02-17 18:24:44 +00:00
|
|
|
// recurse over all submenus
|
2006-10-02 05:09:48 +00:00
|
|
|
for (i = 0; i < [_items count]; i++)
|
|
|
|
{
|
2009-02-17 18:24:44 +00:00
|
|
|
NSMenuItem *anItem = [_items objectAtIndex: i];
|
|
|
|
NSMenu *submenu = [anItem submenu];
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
if (submenu != nil)
|
2009-02-17 18:24:44 +00:00
|
|
|
{
|
|
|
|
if ([submenu isTransient])
|
|
|
|
{
|
|
|
|
[submenu closeTransient];
|
|
|
|
}
|
|
|
|
[submenu close];
|
|
|
|
[submenu _organizeMenu];
|
|
|
|
}
|
2006-10-02 05:09:48 +00:00
|
|
|
}
|
2009-02-17 18:24:44 +00:00
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
[[self menuRepresentation] update];
|
|
|
|
[self sizeToFit];
|
|
|
|
}
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
- (void) _setGeometry
|
|
|
|
{
|
|
|
|
NSPoint origin;
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.horizontal == YES)
|
2006-10-02 05:09:48 +00:00
|
|
|
{
|
|
|
|
origin = NSMakePoint (0, [[NSScreen mainScreen] frame].size.height
|
|
|
|
- [_aWindow frame].size.height);
|
|
|
|
[_aWindow setFrameOrigin: origin];
|
|
|
|
[_bWindow setFrameOrigin: origin];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSString *key;
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
if (nil != (key = [self _locationKey]))
|
|
|
|
{
|
|
|
|
NSUserDefaults *defaults;
|
|
|
|
NSDictionary *menuLocations;
|
|
|
|
NSString *location;
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
defaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
menuLocations = [defaults objectForKey: NSMenuLocationsKey];
|
|
|
|
|
|
|
|
if ([menuLocations isKindOfClass: [NSDictionary class]])
|
|
|
|
location = [menuLocations objectForKey: key];
|
|
|
|
else
|
|
|
|
location = nil;
|
|
|
|
|
|
|
|
if (location && [location isKindOfClass: [NSString class]])
|
2006-02-04 19:58:55 +00:00
|
|
|
{
|
2006-10-02 05:09:48 +00:00
|
|
|
[_aWindow setFrameFromString: location];
|
|
|
|
[_bWindow setFrameFromString: location];
|
|
|
|
return;
|
2006-02-04 19:58:55 +00:00
|
|
|
}
|
|
|
|
}
|
2006-10-02 05:09:48 +00:00
|
|
|
|
2014-07-21 08:04:32 +00:00
|
|
|
if ((_aWindow != nil) && ([_aWindow screen] != nil))
|
|
|
|
{
|
|
|
|
origin = NSMakePoint(0, [[_aWindow screen] visibleFrame].size.height
|
|
|
|
- [_aWindow frame].size.height);
|
2006-10-02 05:09:48 +00:00
|
|
|
|
2014-07-21 08:04:32 +00:00
|
|
|
[_aWindow setFrameOrigin: origin];
|
|
|
|
[_bWindow setFrameOrigin: origin];
|
|
|
|
}
|
2006-02-04 19:58:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
/**
|
|
|
|
Save the current menu position in the standard user defaults
|
|
|
|
*/
|
|
|
|
- (void) _updateUserDefaults: (id) notification
|
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.horizontal == NO)
|
2003-03-07 05:33:17 +00:00
|
|
|
{
|
2006-02-04 19:58:55 +00:00
|
|
|
NSString *key;
|
2003-03-07 05:33:17 +00:00
|
|
|
|
2006-02-04 19:58:55 +00:00
|
|
|
NSDebugLLog (@"NSMenu", @"Synchronizing user defaults");
|
|
|
|
key = [self _locationKey];
|
|
|
|
if (key != nil)
|
2009-05-01 22:54:11 +00:00
|
|
|
{
|
|
|
|
NSUserDefaults *defaults;
|
|
|
|
NSMutableDictionary *menuLocations;
|
|
|
|
NSString *locString;
|
|
|
|
|
|
|
|
defaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
menuLocations = [defaults objectForKey: NSMenuLocationsKey];
|
|
|
|
if ([menuLocations isKindOfClass: [NSDictionary class]])
|
|
|
|
menuLocations = AUTORELEASE([menuLocations mutableCopy]);
|
|
|
|
else
|
|
|
|
menuLocations = nil;
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2009-05-01 22:54:11 +00:00
|
|
|
if ([_aWindow isVisible]
|
2017-01-08 19:33:32 +00:00
|
|
|
&& ([self isTornOff] || ([self _isMain])))
|
2009-05-01 22:54:11 +00:00
|
|
|
{
|
|
|
|
if (menuLocations == nil)
|
|
|
|
{
|
|
|
|
menuLocations = AUTORELEASE([[NSMutableDictionary alloc]
|
|
|
|
initWithCapacity: 2]);
|
|
|
|
}
|
|
|
|
locString = [[self window] stringWithSavedFrame];
|
|
|
|
[menuLocations setObject: locString forKey: key];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[menuLocations removeObjectForKey: key];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([menuLocations count] > 0)
|
|
|
|
{
|
|
|
|
[defaults setObject: menuLocations
|
|
|
|
forKey: NSMenuLocationsKey];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[defaults removeObjectForKey: NSMenuLocationsKey];
|
|
|
|
}
|
|
|
|
[defaults synchronize];
|
|
|
|
}
|
2003-03-07 05:33:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-03-19 16:15:21 +00:00
|
|
|
- (void) _rightMouseDisplay: (NSEvent*)theEvent
|
|
|
|
{
|
2010-05-12 22:47:10 +00:00
|
|
|
[[GSTheme theme] rightMouseDisplay: self
|
|
|
|
forEvent: theEvent];
|
2003-03-19 16:15:21 +00:00
|
|
|
}
|
|
|
|
|
2017-01-08 19:33:32 +00:00
|
|
|
- (BOOL) _isVisible
|
|
|
|
{
|
|
|
|
return [_aWindow isVisible] || [_bWindow isVisible];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) _isMain
|
|
|
|
{
|
|
|
|
return [NSApp mainMenu] == self;
|
|
|
|
}
|
|
|
|
|
2000-01-07 16:46:35 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
@implementation NSMenu
|
1997-07-07 16:56:52 +00:00
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
/*
|
|
|
|
* Class Methods
|
|
|
|
*/
|
1999-06-30 03:10:38 +00:00
|
|
|
+ (void) initialize
|
1999-03-24 11:31:06 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
if (self == [NSMenu class])
|
|
|
|
{
|
|
|
|
[self setVersion: 1];
|
2001-08-27 18:49:34 +00:00
|
|
|
nc = [NSNotificationCenter defaultCenter];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
1999-03-24 11:31:06 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
+ (void) setMenuZone: (NSZone*)zone
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
menuZone = zone;
|
|
|
|
}
|
1997-07-07 16:56:52 +00:00
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
+ (NSZone*) menuZone
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
|
|
|
return menuZone;
|
|
|
|
}
|
1997-07-07 16:56:52 +00:00
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
+ (BOOL) menuBarVisible
|
|
|
|
{
|
|
|
|
return menuBarVisible;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (void) setMenuBarVisible: (BOOL)flag
|
|
|
|
{
|
|
|
|
menuBarVisible = flag;
|
|
|
|
}
|
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
/*
|
2003-03-07 05:33:17 +00:00
|
|
|
*
|
2000-01-05 20:16:59 +00:00
|
|
|
*/
|
1999-07-20 09:21:31 +00:00
|
|
|
- (id) init
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
2003-02-21 23:50:21 +00:00
|
|
|
return [self initWithTitle: [[NSProcessInfo processInfo] processName]];
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-11-25 11:54:08 +00:00
|
|
|
- (void) dealloc
|
|
|
|
{
|
2001-08-27 18:49:34 +00:00
|
|
|
[nc removeObserver: self];
|
1999-11-25 11:54:08 +00:00
|
|
|
|
2004-02-06 00:16:54 +00:00
|
|
|
// Now clean the pointer to us stored each _items element
|
|
|
|
[_items makeObjectsPerformSelector: @selector(setMenu:) withObject: nil];
|
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
RELEASE(_notifications);
|
|
|
|
RELEASE(_title);
|
|
|
|
RELEASE(_items);
|
2004-09-24 10:54:18 +00:00
|
|
|
[_view setMenu: nil];
|
2001-08-19 23:21:59 +00:00
|
|
|
RELEASE(_view);
|
|
|
|
RELEASE(_aWindow);
|
|
|
|
RELEASE(_bWindow);
|
2010-05-12 09:02:25 +00:00
|
|
|
RELEASE(_name);
|
1999-11-25 11:54:08 +00:00
|
|
|
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
/*
|
|
|
|
|
|
|
|
*/
|
2000-01-05 20:16:59 +00:00
|
|
|
- (id) initWithTitle: (NSString*)aTitle
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2004-09-24 10:54:18 +00:00
|
|
|
NSMenuView *menuRep;
|
1999-07-28 10:31:56 +00:00
|
|
|
|
2010-01-19 08:34:24 +00:00
|
|
|
self = [super init];
|
|
|
|
if (!self)
|
|
|
|
return nil;
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
// Keep the title.
|
2001-08-19 23:21:59 +00:00
|
|
|
ASSIGN(_title, aTitle);
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2004-09-24 10:54:18 +00:00
|
|
|
// Create an array to store our menu items.
|
2001-08-19 23:21:59 +00:00
|
|
|
_items = [[NSMutableArray alloc] init];
|
1997-07-07 16:56:52 +00:00
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.changedMessagesEnabled = YES;
|
2001-08-19 23:21:59 +00:00
|
|
|
_notifications = [[NSMutableArray alloc] init];
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.needsSizing = YES;
|
1999-11-16 22:25:07 +00:00
|
|
|
// According to the spec, menus do autoenable by default.
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.autoenable = YES;
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2002-02-23 11:16:59 +00:00
|
|
|
/* Please note that we own all this menu network of objects. So,
|
|
|
|
none of these objects should be retaining us. When we are deallocated,
|
|
|
|
we release all the objects we own, and that should cause deallocation
|
|
|
|
of the whole menu network. */
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
// Create the windows that will display the menu.
|
2001-08-21 23:24:35 +00:00
|
|
|
_aWindow = [self _createWindow];
|
|
|
|
_bWindow = [self _createWindow];
|
2003-02-16 06:04:03 +00:00
|
|
|
[_bWindow setLevel: NSPopUpMenuWindowLevel];
|
1999-11-17 02:23:47 +00:00
|
|
|
|
2001-08-27 18:49:34 +00:00
|
|
|
// Create a NSMenuView to draw our menu items.
|
2004-09-24 10:54:18 +00:00
|
|
|
menuRep = [[NSMenuView alloc] initWithFrame: NSZeroRect];
|
|
|
|
[self setMenuRepresentation: menuRep];
|
|
|
|
RELEASE(menuRep);
|
2001-07-03 18:16:03 +00:00
|
|
|
|
2002-02-23 12:18:26 +00:00
|
|
|
/* Set up the notification to start the process of redisplaying
|
|
|
|
the menus where the user left them the last time.
|
|
|
|
|
|
|
|
Use NSApplicationDidFinishLaunching, and not
|
|
|
|
NSApplicationWillFinishLaunching, so that the programmer can set
|
|
|
|
up menus in NSApplicationWillFinishLaunching.
|
|
|
|
*/
|
2001-08-27 18:49:34 +00:00
|
|
|
[nc addObserver: self
|
2010-04-24 17:12:35 +00:00
|
|
|
selector: @selector(applicationDidFinishLaunching:)
|
2002-02-23 12:18:26 +00:00
|
|
|
name: NSApplicationDidFinishLaunchingNotification
|
2001-08-27 18:49:34 +00:00
|
|
|
object: NSApp];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2003-02-21 23:50:21 +00:00
|
|
|
[nc addObserver: self
|
|
|
|
selector: @selector(_showOnActivateApp:)
|
|
|
|
name: NSApplicationWillBecomeActiveNotification
|
|
|
|
object: NSApp];
|
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
[nc addObserver: self
|
|
|
|
selector: @selector (_menuMoved:)
|
|
|
|
name: NSWindowDidMoveNotification
|
|
|
|
object: _aWindow];
|
|
|
|
|
|
|
|
[nc addObserver: self
|
|
|
|
selector: @selector (_updateUserDefaults:)
|
|
|
|
name: NSEnqueuedMenuMoveName
|
|
|
|
object: self];
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
return self;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
/*
|
|
|
|
* Setting Up the Menu Commands
|
|
|
|
*/
|
2010-04-24 17:12:35 +00:00
|
|
|
|
|
|
|
- (void) menuChanged
|
|
|
|
{
|
|
|
|
// propagate notification up to the main menu
|
2017-01-08 19:33:32 +00:00
|
|
|
if ([self _isMain])
|
2010-04-24 17:12:35 +00:00
|
|
|
_menu.mainMenuChanged = YES;
|
|
|
|
else
|
|
|
|
[[self supermenu] menuChanged];
|
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) insertItem: (id <NSMenuItem>)newItem
|
2013-01-30 12:43:27 +00:00
|
|
|
atIndex: (NSInteger)index
|
1996-09-12 19:24:32 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
NSNotification *inserted;
|
|
|
|
NSDictionary *d;
|
1999-07-26 06:44:26 +00:00
|
|
|
|
2001-08-27 18:49:34 +00:00
|
|
|
if (![(id)newItem conformsToProtocol: @protocol(NSMenuItem)])
|
1999-07-13 01:39:46 +00:00
|
|
|
{
|
2001-08-27 18:49:34 +00:00
|
|
|
NSLog(@"You must use an object that conforms to NSMenuItem.\n");
|
|
|
|
return;
|
1999-07-13 01:39:46 +00:00
|
|
|
}
|
|
|
|
|
2001-08-27 18:49:34 +00:00
|
|
|
/*
|
|
|
|
* If the item is already attached to another menu it
|
|
|
|
* isn't added.
|
|
|
|
*/
|
|
|
|
if ([newItem menu] != nil)
|
2004-02-06 00:16:54 +00:00
|
|
|
{
|
|
|
|
NSLog(@"The object %@ is already attached to a menu, then it isn't possible to add it.\n", newItem);
|
|
|
|
return;
|
|
|
|
}
|
2001-08-27 18:49:34 +00:00
|
|
|
|
|
|
|
[_items insertObject: newItem atIndex: index];
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.needsSizing = YES;
|
2009-09-01 05:58:48 +00:00
|
|
|
[(NSMenuView*)_view setNeedsSizing: YES];
|
2001-08-27 18:49:34 +00:00
|
|
|
|
|
|
|
// Create the notification for the menu representation.
|
|
|
|
d = [NSDictionary
|
2016-12-31 16:03:01 +00:00
|
|
|
dictionaryWithObject: [NSNumber numberWithInteger: index]
|
2001-08-27 18:49:34 +00:00
|
|
|
forKey: @"NSMenuItemIndex"];
|
|
|
|
inserted = [NSNotification
|
|
|
|
notificationWithName: NSMenuDidAddItemNotification
|
|
|
|
object: self
|
|
|
|
userInfo: d];
|
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.changedMessagesEnabled)
|
2001-08-27 18:49:34 +00:00
|
|
|
[nc postNotification: inserted];
|
|
|
|
else
|
|
|
|
[_notifications addObject: inserted];
|
2010-04-24 17:12:35 +00:00
|
|
|
[self menuChanged];
|
2001-08-27 18:49:34 +00:00
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
// Set this after the insert notification has been sent.
|
2001-09-23 22:38:48 +00:00
|
|
|
[newItem setMenu: self];
|
1996-09-12 19:24:32 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
- (id <NSMenuItem>) insertItemWithTitle: (NSString*)aString
|
1999-07-26 06:44:26 +00:00
|
|
|
action: (SEL)aSelector
|
2000-01-05 20:16:59 +00:00
|
|
|
keyEquivalent: (NSString*)charCode
|
2013-01-30 12:43:27 +00:00
|
|
|
atIndex: (NSInteger)index
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2001-08-27 18:49:34 +00:00
|
|
|
NSMenuItem *anItem = [[NSMenuItem alloc] initWithTitle: aString
|
|
|
|
action: aSelector
|
|
|
|
keyEquivalent: charCode];
|
1997-07-07 16:56:52 +00:00
|
|
|
|
2001-08-27 18:49:34 +00:00
|
|
|
// Insert the new item into the menu.
|
1999-11-25 11:54:08 +00:00
|
|
|
[self insertItem: anItem atIndex: index];
|
1999-07-26 06:44:26 +00:00
|
|
|
|
|
|
|
// For returns sake.
|
2001-08-30 06:50:04 +00:00
|
|
|
return AUTORELEASE(anItem);
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) addItem: (id <NSMenuItem>)newItem
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
[self insertItem: newItem atIndex: [_items count]];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
- (id <NSMenuItem>) addItemWithTitle: (NSString*)aString
|
1999-07-20 09:21:31 +00:00
|
|
|
action: (SEL)aSelector
|
2000-01-05 20:16:59 +00:00
|
|
|
keyEquivalent: (NSString*)keyEquiv
|
1999-06-02 19:55:23 +00:00
|
|
|
{
|
1999-07-20 09:21:31 +00:00
|
|
|
return [self insertItemWithTitle: aString
|
|
|
|
action: aSelector
|
|
|
|
keyEquivalent: keyEquiv
|
2001-08-19 23:21:59 +00:00
|
|
|
atIndex: [_items count]];
|
1999-06-02 19:55:23 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) removeItem: (id <NSMenuItem>)anItem
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
NSInteger index = [self indexOfItem: anItem];
|
2001-08-27 18:49:34 +00:00
|
|
|
|
|
|
|
if (-1 == index)
|
|
|
|
return;
|
|
|
|
|
|
|
|
[self removeItemAtIndex: index];
|
1999-07-26 06:44:26 +00:00
|
|
|
}
|
|
|
|
|
2013-01-30 12:43:27 +00:00
|
|
|
- (void) removeItemAtIndex: (NSInteger)index
|
1999-07-26 06:44:26 +00:00
|
|
|
{
|
2001-08-27 18:49:34 +00:00
|
|
|
NSNotification *removed;
|
|
|
|
NSDictionary *d;
|
|
|
|
id anItem = [_items objectAtIndex: index];
|
1996-10-03 18:45:41 +00:00
|
|
|
|
1999-07-26 06:44:26 +00:00
|
|
|
if (!anItem)
|
|
|
|
return;
|
1996-09-12 19:24:32 +00:00
|
|
|
|
2001-08-27 18:49:34 +00:00
|
|
|
[anItem setMenu: nil];
|
|
|
|
[_items removeObjectAtIndex: index];
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.needsSizing = YES;
|
2009-09-01 05:58:48 +00:00
|
|
|
[(NSMenuView*)_view setNeedsSizing: YES];
|
2001-08-27 18:49:34 +00:00
|
|
|
|
2016-12-31 16:03:01 +00:00
|
|
|
d = [NSDictionary dictionaryWithObject: [NSNumber numberWithInteger: index]
|
2001-08-27 18:49:34 +00:00
|
|
|
forKey: @"NSMenuItemIndex"];
|
|
|
|
removed = [NSNotification
|
|
|
|
notificationWithName: NSMenuDidRemoveItemNotification
|
|
|
|
object: self
|
|
|
|
userInfo: d];
|
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.changedMessagesEnabled)
|
2001-08-27 18:49:34 +00:00
|
|
|
[nc postNotification: removed];
|
1999-07-20 09:21:31 +00:00
|
|
|
else
|
2001-08-27 18:49:34 +00:00
|
|
|
[_notifications addObject: removed];
|
2010-04-24 17:12:35 +00:00
|
|
|
[self menuChanged];
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-09-12 19:24:32 +00:00
|
|
|
|
1999-07-26 06:44:26 +00:00
|
|
|
- (void) itemChanged: (id <NSMenuItem>)anObject
|
1999-03-11 12:34:04 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
NSNotification *changed;
|
|
|
|
NSDictionary *d;
|
2013-01-30 12:43:27 +00:00
|
|
|
NSInteger index = [self indexOfItem: anObject];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
2001-08-27 18:49:34 +00:00
|
|
|
if (-1 == index)
|
|
|
|
return;
|
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.needsSizing = YES;
|
2009-09-01 05:58:48 +00:00
|
|
|
[(NSMenuView*)_view setNeedsSizing: YES];
|
1996-10-03 18:45:41 +00:00
|
|
|
|
2016-12-31 16:03:01 +00:00
|
|
|
d = [NSDictionary dictionaryWithObject: [NSNumber numberWithInteger: index]
|
2001-08-27 18:49:34 +00:00
|
|
|
forKey: @"NSMenuItemIndex"];
|
1999-11-16 22:25:07 +00:00
|
|
|
changed = [NSNotification
|
|
|
|
notificationWithName: NSMenuDidChangeItemNotification
|
|
|
|
object: self
|
|
|
|
userInfo: d];
|
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.changedMessagesEnabled)
|
2001-08-27 18:49:34 +00:00
|
|
|
[nc postNotification: changed];
|
1999-11-16 22:25:07 +00:00
|
|
|
else
|
2001-08-19 23:21:59 +00:00
|
|
|
[_notifications addObject: changed];
|
2010-04-24 17:12:35 +00:00
|
|
|
[self menuChanged];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
|
|
|
// Update the menu.
|
|
|
|
[self update];
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
/*
|
|
|
|
* Finding Menu Items
|
|
|
|
*/
|
2013-01-30 12:43:27 +00:00
|
|
|
- (id <NSMenuItem>) itemWithTag: (NSInteger)aTag
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
NSUInteger i;
|
|
|
|
NSUInteger count = [_items count];
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-03-11 12:34:04 +00:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
id menuItem = [_items objectAtIndex: i];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
|
|
|
if ([menuItem tag] == aTag)
|
|
|
|
return menuItem;
|
1999-03-11 12:34:04 +00:00
|
|
|
}
|
1997-07-07 16:56:52 +00:00
|
|
|
return nil;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
- (id <NSMenuItem>) itemWithTitle: (NSString*)aString
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
NSUInteger i;
|
|
|
|
NSUInteger count = [_items count];
|
1997-10-09 22:55:31 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
for (i = 0; i < count; i++)
|
1999-03-11 12:34:04 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
id menuItem = [_items objectAtIndex: i];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2000-09-26 11:45:32 +00:00
|
|
|
if ([[menuItem title] isEqualToString: aString])
|
1999-11-16 22:25:07 +00:00
|
|
|
return menuItem;
|
1999-03-11 12:34:04 +00:00
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
return nil;
|
1999-03-11 12:34:04 +00:00
|
|
|
}
|
|
|
|
|
2015-05-26 17:11:17 +00:00
|
|
|
- (NSMenuItem *) itemAtIndex: (NSInteger)index
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2013-01-30 12:43:27 +00:00
|
|
|
if (index >= [_items count] || index < 0)
|
1999-11-16 22:25:07 +00:00
|
|
|
[NSException raise: NSRangeException
|
1999-11-25 11:54:08 +00:00
|
|
|
format: @"Range error in method -itemAtIndex: "];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
return [_items objectAtIndex: index];
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
2013-01-30 12:43:27 +00:00
|
|
|
- (NSInteger) numberOfItems
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
return [_items count];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
- (NSArray*) itemArray
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
return (NSArray*)_items;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
/*
|
|
|
|
* Finding Indices of Menu Items
|
|
|
|
*/
|
2013-01-30 12:43:27 +00:00
|
|
|
- (NSInteger) indexOfItem: (id <NSMenuItem>)anObject
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2011-12-17 17:16:09 +00:00
|
|
|
NSUInteger index;
|
2000-03-05 01:23:01 +00:00
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
index = [_items indexOfObjectIdenticalTo: anObject];
|
2000-03-05 01:23:01 +00:00
|
|
|
|
|
|
|
if (index == NSNotFound)
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return index;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
2013-01-30 12:43:27 +00:00
|
|
|
- (NSInteger) indexOfItemWithTitle: (NSString*)aTitle
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
id anItem;
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
if ((anItem = [self itemWithTitle: aTitle]))
|
2001-08-19 23:21:59 +00:00
|
|
|
return [_items indexOfObjectIdenticalTo: anItem];
|
1999-06-30 03:10:38 +00:00
|
|
|
else
|
|
|
|
return -1;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
2013-01-30 12:43:27 +00:00
|
|
|
- (NSInteger) indexOfItemWithTag: (NSInteger)aTag
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
id anItem;
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
if ((anItem = [self itemWithTag: aTag]))
|
2001-08-19 23:21:59 +00:00
|
|
|
return [_items indexOfObjectIdenticalTo: anItem];
|
1999-06-30 03:10:38 +00:00
|
|
|
else
|
|
|
|
return -1;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
2013-01-30 12:43:27 +00:00
|
|
|
- (NSInteger) indexOfItemWithTarget: (id)anObject
|
1999-11-25 11:54:08 +00:00
|
|
|
andAction: (SEL)actionSelector
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
NSUInteger i;
|
|
|
|
NSUInteger count = [_items count];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
NSMenuItem *menuItem = [_items objectAtIndex: i];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2010-09-09 23:50:38 +00:00
|
|
|
if (actionSelector == 0 || sel_isEqual([menuItem action], actionSelector))
|
2008-10-24 07:59:42 +00:00
|
|
|
{
|
|
|
|
// There are different possibilities to implement the check here
|
2009-11-28 15:48:59 +00:00
|
|
|
if ([menuItem target] == anObject)
|
2008-10-24 07:59:42 +00:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
return -1;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
2013-01-30 12:43:27 +00:00
|
|
|
- (NSInteger) indexOfItemWithRepresentedObject: (id)anObject
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
NSUInteger i;
|
|
|
|
NSUInteger count = [_items count];
|
1999-07-30 22:10:02 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
for (i = 0; i < count; i++)
|
1999-07-30 22:10:02 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
if ([[[_items objectAtIndex: i] representedObject]
|
2008-10-24 07:59:42 +00:00
|
|
|
isEqual: anObject])
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
1999-07-30 22:10:02 +00:00
|
|
|
}
|
1999-08-19 23:18:25 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
return -1;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
2013-01-30 12:43:27 +00:00
|
|
|
- (NSInteger) indexOfItemWithSubmenu: (NSMenu *)anObject
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
NSUInteger i;
|
|
|
|
NSUInteger count = [_items count];
|
1999-08-19 23:18:25 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
for (i = 0; i < count; i++)
|
1999-08-19 23:18:25 +00:00
|
|
|
{
|
2001-08-27 18:49:34 +00:00
|
|
|
id item = [_items objectAtIndex: i];
|
|
|
|
|
|
|
|
if ([item hasSubmenu] &&
|
2008-10-24 07:59:42 +00:00
|
|
|
[[item submenu] isEqual: anObject])
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
1999-08-19 23:18:25 +00:00
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
return -1;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
//
|
|
|
|
// Managing Submenus.
|
|
|
|
//
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) setSubmenu: (NSMenu *)aMenu
|
2000-02-19 00:40:47 +00:00
|
|
|
forItem: (id <NSMenuItem>)anItem
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2001-08-27 18:49:34 +00:00
|
|
|
[anItem setSubmenu: aMenu];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) submenuAction: (id)sender
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (NSMenu *) attachedMenu
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_attachedMenu && _menu.transient
|
|
|
|
&& !_attachedMenu->_menu.transient)
|
1999-11-16 22:25:07 +00:00
|
|
|
return nil;
|
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
return _attachedMenu;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
Look for the semantics in the header. Note that
|
|
|
|
this implementation works because there are ... cases:
|
|
|
|
<enum>
|
|
|
|
<item>
|
|
|
|
This menu is transient, its supermenu is also transient.
|
|
|
|
In this case we just do the check between the transient windows
|
|
|
|
and everything is fine
|
|
|
|
</item>
|
|
|
|
<item>
|
|
|
|
The menu is transient, its supermenu is not transient.
|
|
|
|
This can go WRONG
|
|
|
|
</item>
|
|
|
|
</enum>
|
|
|
|
*/
|
1999-03-11 12:34:04 +00:00
|
|
|
- (BOOL) isAttached
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
return _superMenu && [_superMenu attachedMenu] == self;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (BOOL) isTornOff
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
return _menu.is_tornoff;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
- (NSPoint) locationForSubmenu: (NSMenu*)aSubmenu
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2001-09-11 17:29:51 +00:00
|
|
|
return [_view locationForSubmenu: aSubmenu];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (NSMenu *) supermenu
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
return _superMenu;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) setSupermenu: (NSMenu *)supermenu
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2002-02-23 11:16:59 +00:00
|
|
|
/* The supermenu retains us (indirectly). Do not retain it. */
|
2001-08-19 23:21:59 +00:00
|
|
|
_superMenu = supermenu;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
//
|
|
|
|
// Enabling and Disabling Menu Items
|
|
|
|
//
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) setAutoenablesItems: (BOOL)flag
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.autoenable = flag;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (BOOL) autoenablesItems
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
return _menu.autoenable;
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
1997-07-07 16:56:52 +00:00
|
|
|
|
2016-12-31 16:03:01 +00:00
|
|
|
- (void) _updateSubmenu
|
|
|
|
{
|
2017-01-08 19:33:32 +00:00
|
|
|
if ([self _isVisible])
|
2016-12-31 16:03:01 +00:00
|
|
|
{
|
|
|
|
// Update the menu items when the menu is visible...
|
|
|
|
[self update];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// ...else only progress to submenus
|
|
|
|
NSUInteger i;
|
|
|
|
NSUInteger count = [_items count];
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
NSMenuItem *item = [_items objectAtIndex: i];
|
|
|
|
|
|
|
|
if ([item hasSubmenu])
|
|
|
|
{
|
|
|
|
[[item submenu] _updateSubmenu];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) update
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_delegate)
|
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
if ([_delegate respondsToSelector: @selector(menuNeedsUpdate:)])
|
2007-12-25 14:53:45 +00:00
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
[_delegate menuNeedsUpdate: self];
|
2007-12-25 14:53:45 +00:00
|
|
|
}
|
2016-12-31 16:03:01 +00:00
|
|
|
else if ([_delegate respondsToSelector: @selector(numberOfItemsInMenu:)])
|
2007-12-25 14:53:45 +00:00
|
|
|
{
|
2013-01-30 12:43:27 +00:00
|
|
|
NSInteger num;
|
2007-12-25 14:53:45 +00:00
|
|
|
|
|
|
|
num = [_delegate numberOfItemsInMenu: self];
|
|
|
|
if (num > 0)
|
|
|
|
{
|
|
|
|
BOOL cont = YES;
|
2013-01-30 12:43:27 +00:00
|
|
|
NSInteger i = 0;
|
|
|
|
NSInteger curr = [self numberOfItems];
|
2007-12-25 14:53:45 +00:00
|
|
|
|
|
|
|
while (num < curr)
|
|
|
|
{
|
|
|
|
[self removeItemAtIndex: --curr];
|
|
|
|
}
|
|
|
|
while (num > curr)
|
|
|
|
{
|
|
|
|
[self insertItemWithTitle: @""
|
|
|
|
action: NULL
|
|
|
|
keyEquivalent: @""
|
|
|
|
atIndex: curr++];
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Should only process the items we display
|
|
|
|
while (cont && i < num)
|
|
|
|
{
|
|
|
|
cont = [_delegate menu: self
|
2008-12-31 16:49:46 +00:00
|
|
|
updateItem: (NSMenuItem*)[self itemAtIndex: i]
|
2007-12-25 14:53:45 +00:00
|
|
|
atIndex: i
|
|
|
|
shouldCancel: NO];
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-09-11 17:29:51 +00:00
|
|
|
// We use this as a recursion check.
|
2007-12-25 14:53:45 +00:00
|
|
|
if (!_menu.changedMessagesEnabled)
|
2001-09-11 17:29:51 +00:00
|
|
|
return;
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
if ([self autoenablesItems])
|
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
NSUInteger i;
|
|
|
|
NSUInteger count = [_items count];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
// Temporary disable automatic displaying of menu.
|
|
|
|
[self setMenuChangedMessagesEnabled: NO];
|
2010-03-09 23:11:40 +00:00
|
|
|
|
|
|
|
NS_DURING
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2010-03-09 23:11:40 +00:00
|
|
|
for (i = 0; i < count; i++)
|
2001-10-07 23:43:43 +00:00
|
|
|
{
|
2010-03-09 23:11:40 +00:00
|
|
|
NSMenuItem *item = [_items objectAtIndex: i];
|
|
|
|
SEL action = [item action];
|
|
|
|
id validator = nil;
|
|
|
|
BOOL wasEnabled = [item isEnabled];
|
|
|
|
BOOL shouldBeEnabled;
|
|
|
|
|
|
|
|
if ([item hasSubmenu])
|
2016-12-31 16:03:01 +00:00
|
|
|
{
|
|
|
|
[[item submenu] _updateSubmenu];
|
|
|
|
}
|
2010-03-09 23:11:40 +00:00
|
|
|
|
|
|
|
// If there is no action - there can be no validator for the item.
|
|
|
|
if (action)
|
2001-10-07 23:43:43 +00:00
|
|
|
{
|
2010-03-09 23:11:40 +00:00
|
|
|
validator = [NSApp targetForAction: action
|
|
|
|
to: [item target]
|
|
|
|
from: item];
|
|
|
|
}
|
|
|
|
else if (_popUpButtonCell != nil)
|
|
|
|
{
|
|
|
|
if (NULL != (action = [_popUpButtonCell action]))
|
|
|
|
{
|
|
|
|
validator = [NSApp targetForAction: action
|
|
|
|
to: [_popUpButtonCell target]
|
|
|
|
from: [_popUpButtonCell controlView]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (validator == nil)
|
|
|
|
{
|
|
|
|
if ((action == NULL) && (_popUpButtonCell != nil))
|
|
|
|
{
|
|
|
|
shouldBeEnabled = YES;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
shouldBeEnabled = NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ([validator
|
|
|
|
respondsToSelector: @selector(validateMenuItem:)])
|
|
|
|
{
|
|
|
|
shouldBeEnabled = [validator validateMenuItem: item];
|
|
|
|
}
|
|
|
|
else if ([validator
|
|
|
|
respondsToSelector: @selector(validateUserInterfaceItem:)])
|
|
|
|
{
|
|
|
|
shouldBeEnabled = [validator validateUserInterfaceItem: item];
|
|
|
|
}
|
2015-01-11 21:56:27 +00:00
|
|
|
else if ([item hasSubmenu] && [[item submenu] numberOfItems] == 0)
|
|
|
|
{
|
|
|
|
shouldBeEnabled = NO;
|
|
|
|
}
|
|
|
|
else
|
2010-03-09 23:11:40 +00:00
|
|
|
{
|
|
|
|
shouldBeEnabled = YES;
|
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2010-03-09 23:11:40 +00:00
|
|
|
if (shouldBeEnabled != wasEnabled)
|
|
|
|
{
|
|
|
|
[item setEnabled: shouldBeEnabled];
|
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
2010-03-09 23:11:40 +00:00
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
NSLog(@"Error Occurred While Updating Menu %@: %@", [self title], localException);
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
1999-11-16 22:25:07 +00:00
|
|
|
// Reenable displaying of menus
|
2010-04-24 17:12:35 +00:00
|
|
|
[self setMenuChangedMessagesEnabled: YES]; // this will send pending _notifications
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_menu.mainMenuChanged)
|
|
|
|
{
|
|
|
|
if (NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil) == NSWindows95InterfaceStyle)
|
|
|
|
{
|
|
|
|
[[GSTheme theme] updateAllWindowsWithMenu: self];
|
|
|
|
}
|
|
|
|
_menu.mainMenuChanged = NO;
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
|
|
|
|
2017-01-08 19:33:32 +00:00
|
|
|
if (_menu.needsSizing && [self _isVisible])
|
2003-03-22 16:29:40 +00:00
|
|
|
{
|
|
|
|
NSDebugLLog (@"NSMenu", @" Calling Size To Fit (A)");
|
|
|
|
[self sizeToFit];
|
|
|
|
}
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
return;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
//
|
|
|
|
// Handling Keyboard Equivalents
|
|
|
|
//
|
1999-06-30 03:10:38 +00:00
|
|
|
- (BOOL) performKeyEquivalent: (NSEvent*)theEvent
|
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
NSUInteger i;
|
|
|
|
NSUInteger count = [_items count];
|
|
|
|
NSEventType type = [theEvent type];
|
|
|
|
NSUInteger modifiers = [theEvent modifierFlags];
|
|
|
|
NSString *keyEquivalent = [theEvent charactersIgnoringModifiers];
|
|
|
|
NSUInteger relevantModifiersMask = NSCommandKeyMask | NSAlternateKeyMask | NSControlKeyMask;
|
2017-01-08 19:33:32 +00:00
|
|
|
|
|
|
|
if ((type != NSKeyDown && type != NSKeyUp) || [keyEquivalent length] == 0)
|
|
|
|
return NO;
|
|
|
|
|
2010-06-22 22:00:47 +00:00
|
|
|
/* Take shift key into account only for control keys and arrow and function keys */
|
|
|
|
if ((modifiers & NSFunctionKeyMask)
|
|
|
|
|| ([keyEquivalent length] > 0 && [[NSCharacterSet controlCharacterSet] characterIsMember:[keyEquivalent characterAtIndex:0]]))
|
|
|
|
relevantModifiersMask |= NSShiftKeyMask;
|
2010-03-09 23:11:40 +00:00
|
|
|
|
2017-01-08 19:33:32 +00:00
|
|
|
if (![self _isVisible])
|
|
|
|
{
|
|
|
|
// Need to enable items as the automatic mechanism is switched off for invisible menus
|
|
|
|
[self update];
|
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
NSMenuItem *item = [_items objectAtIndex: i];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
if ([item hasSubmenu])
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
2011-01-17 09:02:30 +00:00
|
|
|
/* Ignore the Services submenu during menu traversal so that its key
|
|
|
|
equivalents do not accidentally shadow standard key equivalents
|
|
|
|
in the application's own menus. NSApp calls -performKeyEquivalent:
|
|
|
|
explicitly for the Services menu when no matching key equivalent
|
|
|
|
was found here (see NSApplication -sendEvent:).
|
|
|
|
Note: Shadowing is no problem for a standard OpenStep menu, where
|
|
|
|
the Services menu appears close to the end of the main menu, but
|
|
|
|
is very likely for Macintosh or Windows 95 interface styles, where
|
|
|
|
the Services menu appears in the first submenu of the main menu. */
|
|
|
|
// FIXME Should really remove conflicting key equivalents from the
|
|
|
|
// menus so that users don't get confused.
|
|
|
|
if ([item submenu] == [NSApp servicesMenu])
|
|
|
|
continue;
|
2010-06-22 22:00:47 +00:00
|
|
|
// Recurse through submenus whether active or not.
|
1999-11-16 22:25:07 +00:00
|
|
|
if ([[item submenu] performKeyEquivalent: theEvent])
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
// The event has been handled by an item in the submenu.
|
1999-06-30 03:10:38 +00:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
NSUInteger mask = [item keyEquivalentModifierMask];
|
2006-05-01 18:39:03 +00:00
|
|
|
|
|
|
|
if ([[item keyEquivalent] isEqualToString: keyEquivalent]
|
2010-06-22 22:00:47 +00:00
|
|
|
&& (modifiers & relevantModifiersMask) == (mask & relevantModifiersMask))
|
2010-06-08 21:56:15 +00:00
|
|
|
{
|
|
|
|
if ([item isEnabled])
|
|
|
|
{
|
|
|
|
[_view performActionWithHighlightingForItemAtIndex: i];
|
|
|
|
}
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
//
|
|
|
|
// Simulating Mouse Clicks
|
|
|
|
//
|
2013-01-30 12:43:27 +00:00
|
|
|
- (void) performActionForItemAtIndex: (NSInteger)index
|
1996-09-12 19:24:32 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
id<NSMenuItem> item = [_items objectAtIndex: index];
|
1998-12-16 15:21:55 +00:00
|
|
|
NSDictionary *d;
|
2001-10-07 23:43:43 +00:00
|
|
|
SEL action;
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
if (![item isEnabled])
|
1997-07-07 16:56:52 +00:00
|
|
|
return;
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2006-02-04 19:58:55 +00:00
|
|
|
// Send the actual action and the stipulated notifications.
|
1999-11-16 22:25:07 +00:00
|
|
|
d = [NSDictionary dictionaryWithObject: item forKey: @"MenuItem"];
|
1998-12-16 15:21:55 +00:00
|
|
|
[nc postNotificationName: NSMenuWillSendActionNotification
|
1998-12-22 12:34:03 +00:00
|
|
|
object: self
|
|
|
|
userInfo: d];
|
2002-06-19 15:00:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
if (_popUpButtonCell != nil)
|
|
|
|
{
|
|
|
|
// Tell the popup button, which item was selected
|
|
|
|
[_popUpButtonCell selectItemAtIndex: index];
|
|
|
|
}
|
|
|
|
|
2012-02-19 16:22:49 +00:00
|
|
|
if ((action = [item action]) != NULL)
|
1999-12-11 03:02:53 +00:00
|
|
|
{
|
2001-10-07 23:43:43 +00:00
|
|
|
[NSApp sendAction: action
|
2012-02-19 16:22:49 +00:00
|
|
|
to: [item target]
|
|
|
|
from: item];
|
1999-12-11 03:02:53 +00:00
|
|
|
}
|
2012-02-19 16:22:49 +00:00
|
|
|
else if (_popUpButtonCell != nil)
|
2001-10-07 23:43:43 +00:00
|
|
|
{
|
2012-02-19 16:22:49 +00:00
|
|
|
if ((action = [_popUpButtonCell action]) != NULL)
|
|
|
|
[NSApp sendAction: action
|
|
|
|
to: [_popUpButtonCell target]
|
|
|
|
from: [_popUpButtonCell controlView]];
|
2001-10-07 23:43:43 +00:00
|
|
|
}
|
|
|
|
|
1998-12-16 15:21:55 +00:00
|
|
|
[nc postNotificationName: NSMenuDidSendActionNotification
|
1999-11-16 22:25:07 +00:00
|
|
|
object: self
|
|
|
|
userInfo: d];
|
1996-09-12 19:24:32 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
//
|
|
|
|
// Setting the Title
|
|
|
|
//
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) setTitle: (NSString*)aTitle
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
ASSIGN(_title, aTitle);
|
2003-03-22 16:29:40 +00:00
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.needsSizing = YES;
|
2009-09-01 05:58:48 +00:00
|
|
|
[(NSMenuView*)_view setNeedsSizing: YES];
|
2017-01-08 19:33:32 +00:00
|
|
|
if ([self _isVisible])
|
2003-03-22 16:29:40 +00:00
|
|
|
{
|
|
|
|
[self sizeToFit];
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (NSString*) title
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
return _title;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
- (id) delegate
|
|
|
|
{
|
|
|
|
return _delegate;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setDelegate: (id)delegate
|
|
|
|
{
|
2009-01-25 18:28:20 +00:00
|
|
|
_delegate = delegate;
|
2007-12-25 14:53:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 18:28:20 +00:00
|
|
|
- (float) menuBarHeight
|
2007-12-25 14:53:45 +00:00
|
|
|
{
|
|
|
|
// FIXME
|
|
|
|
return [NSMenuView menuBarHeight];
|
|
|
|
}
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
//
|
|
|
|
// Setting the Representing Object
|
|
|
|
//
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) setMenuRepresentation: (id)menuRep
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2001-08-27 18:49:34 +00:00
|
|
|
NSView *contentView;
|
|
|
|
|
|
|
|
if (![menuRep isKindOfClass: [NSMenuView class]])
|
|
|
|
{
|
|
|
|
NSLog(@"You must use an NSMenuView, or a derivative thereof.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-01-25 13:47:30 +00:00
|
|
|
/* If we are replacing a menu representation with a new version,
|
|
|
|
* we should display it in the same view as the old representation.
|
|
|
|
* If we can't find a view for that, we display in the content view
|
|
|
|
* of our default window.
|
|
|
|
*/
|
|
|
|
if ([_view superview] == nil)
|
|
|
|
{
|
|
|
|
contentView = [_aWindow contentView];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
contentView = [_view superview];
|
|
|
|
}
|
2006-02-04 19:58:55 +00:00
|
|
|
|
2004-09-24 10:54:18 +00:00
|
|
|
if (_view == menuRep)
|
|
|
|
{
|
2009-01-25 13:47:30 +00:00
|
|
|
/* Hack ... if the representation was 'borrowed' for an in-window
|
|
|
|
* menu, we will still have it recorded as ours, but it won't be
|
|
|
|
* in our view hierarchy, so we have to re-add it.
|
|
|
|
*/
|
2010-01-05 08:37:44 +00:00
|
|
|
/*
|
2009-01-25 13:47:30 +00:00
|
|
|
if (contentView != [menuRep superview])
|
|
|
|
{
|
|
|
|
[contentView addSubview: menuRep];
|
|
|
|
}
|
2010-01-05 08:37:44 +00:00
|
|
|
*/
|
2004-09-24 10:54:18 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-01-25 13:47:30 +00:00
|
|
|
_menu.horizontal = [menuRep isHorizontal];
|
|
|
|
|
2004-09-24 10:54:18 +00:00
|
|
|
if (_view != nil)
|
|
|
|
{
|
|
|
|
// remove the old representation
|
2011-05-15 14:42:08 +00:00
|
|
|
[_view removeFromSuperview];
|
2004-09-24 10:54:18 +00:00
|
|
|
[_view setMenu: nil];
|
|
|
|
}
|
2001-08-27 18:49:34 +00:00
|
|
|
|
|
|
|
ASSIGN(_view, menuRep);
|
|
|
|
[_view setMenu: self];
|
|
|
|
|
|
|
|
// add the new representation
|
|
|
|
[contentView addSubview: _view];
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-12-05 13:07:59 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (id) menuRepresentation
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
return _view;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
- (id) contextMenuRepresentation
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setContextMenuRepresentation: (id)representation
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) tearOffMenuRepresentation
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setTearOffMenuRepresentation: (id)representation
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
//
|
|
|
|
// Updating the Menu Layout
|
|
|
|
//
|
2003-03-07 05:33:17 +00:00
|
|
|
// Wim 20030301: Question, what happens when the notification trigger
|
|
|
|
// new notifications? I think it is not allowed to add items
|
|
|
|
// to the _notifications array while enumerating it.
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) setMenuChangedMessagesEnabled: (BOOL)flag
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.changedMessagesEnabled != flag)
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
|
|
|
if (flag)
|
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
if ([_notifications count])
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
NSEnumerator *enumerator = [_notifications objectEnumerator];
|
1999-11-16 22:25:07 +00:00
|
|
|
id aNotification;
|
|
|
|
|
|
|
|
while ((aNotification = [enumerator nextObject]))
|
|
|
|
[nc postNotification: aNotification];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clean the notification array.
|
2001-08-19 23:21:59 +00:00
|
|
|
[_notifications removeAllObjects];
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.changedMessagesEnabled = flag;
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (BOOL) menuChangedMessagesEnabled
|
1997-12-04 01:58:57 +00:00
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
return _menu.changedMessagesEnabled;
|
1997-12-04 01:58:57 +00:00
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
- (void) sizeToFit
|
1999-07-28 10:31:56 +00:00
|
|
|
{
|
2003-03-22 16:29:40 +00:00
|
|
|
NSRect oldWindowFrame;
|
|
|
|
NSRect newWindowFrame;
|
1999-11-16 22:25:07 +00:00
|
|
|
NSRect menuFrame;
|
1999-07-28 10:31:56 +00:00
|
|
|
|
2003-04-01 19:51:41 +00:00
|
|
|
[_view sizeToFit];
|
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
menuFrame = [_view frame];
|
2017-10-05 21:05:28 +00:00
|
|
|
|
2011-03-13 15:26:20 +00:00
|
|
|
// Main
|
2003-03-22 16:29:40 +00:00
|
|
|
oldWindowFrame = [_aWindow frame];
|
2003-03-30 12:48:06 +00:00
|
|
|
newWindowFrame = [NSWindow frameRectForContentRect: menuFrame
|
2003-03-27 16:16:47 +00:00
|
|
|
styleMask: [_aWindow styleMask]];
|
2003-03-30 12:48:06 +00:00
|
|
|
|
|
|
|
if (oldWindowFrame.size.height > 1)
|
|
|
|
{
|
|
|
|
newWindowFrame.origin = NSMakePoint (oldWindowFrame.origin.x,
|
|
|
|
oldWindowFrame.origin.y
|
|
|
|
+ oldWindowFrame.size.height
|
|
|
|
- newWindowFrame.size.height);
|
|
|
|
}
|
|
|
|
[_aWindow setFrame: newWindowFrame display: NO];
|
|
|
|
|
|
|
|
// Transient
|
2003-03-27 16:16:47 +00:00
|
|
|
oldWindowFrame = [_bWindow frame];
|
2003-03-22 16:29:40 +00:00
|
|
|
newWindowFrame = [NSWindow frameRectForContentRect: menuFrame
|
|
|
|
styleMask: [_bWindow styleMask]];
|
2003-03-30 12:48:06 +00:00
|
|
|
if (oldWindowFrame.size.height > 1)
|
|
|
|
{
|
|
|
|
newWindowFrame.origin = NSMakePoint (oldWindowFrame.origin.x,
|
|
|
|
oldWindowFrame.origin.y
|
|
|
|
+ oldWindowFrame.size.height
|
|
|
|
- newWindowFrame.size.height);
|
|
|
|
}
|
|
|
|
[_bWindow setFrame: newWindowFrame display: NO];
|
2003-03-07 05:33:17 +00:00
|
|
|
|
2001-10-07 23:43:43 +00:00
|
|
|
if (_popUpButtonCell == nil)
|
1999-07-30 22:10:02 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
[_view setFrameOrigin: NSMakePoint (0, 0)];
|
2003-03-27 16:16:47 +00:00
|
|
|
}
|
2003-03-30 12:48:06 +00:00
|
|
|
|
2001-09-11 17:29:51 +00:00
|
|
|
[_view setNeedsDisplay: YES];
|
2003-03-30 12:48:06 +00:00
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.needsSizing = NO;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-09-12 19:24:32 +00:00
|
|
|
|
2000-01-07 16:46:35 +00:00
|
|
|
/*
|
|
|
|
* Displaying Context Sensitive Help
|
|
|
|
*/
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) helpRequested: (NSEvent *)event
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
// TODO: Won't be implemented until we have NSHelp*
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
+ (void) popUpContextMenu: (NSMenu*)menu
|
|
|
|
withEvent: (NSEvent*)event
|
|
|
|
forView: (NSView*)view
|
2007-12-25 14:53:45 +00:00
|
|
|
{
|
|
|
|
[self popUpContextMenu: menu
|
|
|
|
withEvent: event
|
|
|
|
forView: view
|
|
|
|
withFont: nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (void) popUpContextMenu: (NSMenu *)menu
|
|
|
|
withEvent: (NSEvent *)event
|
|
|
|
forView: (NSView *)view
|
|
|
|
withFont: (NSFont *)font
|
2001-08-19 23:21:59 +00:00
|
|
|
{
|
2003-03-19 16:15:21 +00:00
|
|
|
[menu _rightMouseDisplay: event];
|
2001-08-19 23:21:59 +00:00
|
|
|
}
|
|
|
|
|
2001-08-27 18:49:34 +00:00
|
|
|
/*
|
|
|
|
* NSObject Protocol
|
|
|
|
*/
|
|
|
|
- (BOOL) isEqual: (id)anObject
|
|
|
|
{
|
|
|
|
if (self == anObject)
|
|
|
|
return YES;
|
|
|
|
if ([anObject isKindOfClass: [NSMenu class]])
|
|
|
|
{
|
|
|
|
if (![_title isEqualToString: [anObject title]])
|
|
|
|
return NO;
|
|
|
|
return [[self itemArray] isEqual: [anObject itemArray]];
|
|
|
|
}
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2000-01-07 16:46:35 +00:00
|
|
|
/*
|
|
|
|
* NSCoding Protocol
|
|
|
|
*/
|
1999-11-16 22:25:07 +00:00
|
|
|
- (void) encodeWithCoder: (NSCoder*)encoder
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2006-10-15 08:34:47 +00:00
|
|
|
if ([encoder allowsKeyedCoding])
|
2006-08-05 13:08:53 +00:00
|
|
|
{
|
|
|
|
[encoder encodeObject: _title forKey: @"NSTitle"];
|
|
|
|
[encoder encodeObject: _items forKey: @"NSMenuItems"];
|
2006-08-13 20:21:46 +00:00
|
|
|
|
2017-01-08 19:33:32 +00:00
|
|
|
if ([self _isMain])
|
2006-08-13 20:21:46 +00:00
|
|
|
{
|
|
|
|
[encoder encodeObject: @"_NSMainMenu" forKey: @"NSName"];
|
|
|
|
}
|
2006-08-05 13:08:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
BOOL autoenable = _menu.autoenable;
|
|
|
|
|
2006-08-05 13:08:53 +00:00
|
|
|
[encoder encodeObject: _title];
|
|
|
|
[encoder encodeObject: _items];
|
2007-12-25 14:53:45 +00:00
|
|
|
[encoder encodeValueOfObjCType: @encode(BOOL) at: &autoenable];
|
2006-08-05 13:08:53 +00:00
|
|
|
}
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-09-12 19:24:32 +00:00
|
|
|
|
2004-02-05 00:36:04 +00:00
|
|
|
- (id) initWithCoder: (NSCoder*)aDecoder
|
1996-09-12 19:24:32 +00:00
|
|
|
{
|
2000-02-19 00:40:47 +00:00
|
|
|
NSString *dTitle;
|
2010-05-12 09:02:25 +00:00
|
|
|
NSString *dName;
|
2000-02-19 00:40:47 +00:00
|
|
|
NSArray *dItems;
|
|
|
|
BOOL dAuto;
|
2016-12-31 16:03:01 +00:00
|
|
|
NSUInteger i;
|
|
|
|
NSUInteger count;
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2004-02-05 00:36:04 +00:00
|
|
|
if ([aDecoder allowsKeyedCoding])
|
|
|
|
{
|
2009-01-10 03:49:43 +00:00
|
|
|
//
|
|
|
|
// NSNoAutoenable is present when the "Autoenable" option is NOT checked.
|
|
|
|
// NO = Autoenable menus, YES = Don't auto enable menus. We, therefore,
|
|
|
|
// have to invert the values of this flag in order to get the value of
|
|
|
|
// dAuto.
|
|
|
|
//
|
|
|
|
if ([aDecoder containsValueForKey: @"NSNoAutoenable"])
|
|
|
|
{
|
2010-01-19 08:34:24 +00:00
|
|
|
dAuto = ![aDecoder decodeBoolForKey: @"NSNoAutoenable"];
|
2009-01-10 03:49:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-01-19 08:34:24 +00:00
|
|
|
dAuto = YES;
|
2009-01-10 03:49:43 +00:00
|
|
|
}
|
2004-02-05 00:36:04 +00:00
|
|
|
dTitle = [aDecoder decodeObjectForKey: @"NSTitle"];
|
|
|
|
dItems = [aDecoder decodeObjectForKey: @"NSMenuItems"];
|
2010-05-12 09:02:25 +00:00
|
|
|
if ([aDecoder containsValueForKey: @"NSName"])
|
|
|
|
{
|
|
|
|
dName = [aDecoder decodeObjectForKey: @"NSName"];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dName = nil;
|
|
|
|
}
|
2004-02-05 00:36:04 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dTitle = [aDecoder decodeObject];
|
|
|
|
dItems = [aDecoder decodeObject];
|
2010-05-12 09:02:25 +00:00
|
|
|
dName = nil;
|
2004-02-05 00:36:04 +00:00
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &dAuto];
|
|
|
|
}
|
2000-02-19 00:40:47 +00:00
|
|
|
self = [self initWithTitle: dTitle];
|
|
|
|
[self setAutoenablesItems: dAuto];
|
2010-05-12 09:15:25 +00:00
|
|
|
[self _setName: dName];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2001-09-23 22:38:48 +00:00
|
|
|
[self setMenuChangedMessagesEnabled: NO];
|
2000-02-19 00:40:47 +00:00
|
|
|
/*
|
|
|
|
* Make sure that items and submenus are set correctly.
|
|
|
|
*/
|
2016-12-31 16:03:01 +00:00
|
|
|
count = [dItems count];
|
|
|
|
for (i = 0; i < count; i++)
|
2000-02-19 00:40:47 +00:00
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
NSMenuItem *item = [dItems objectAtIndex: i];
|
2000-02-19 00:40:47 +00:00
|
|
|
[self addItem: item];
|
|
|
|
}
|
2001-09-23 22:38:48 +00:00
|
|
|
[self setMenuChangedMessagesEnabled: YES];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
|
|
|
return self;
|
1996-09-12 19:24:32 +00:00
|
|
|
}
|
|
|
|
|
2010-05-12 09:02:25 +00:00
|
|
|
- (void) awakeFromNib
|
|
|
|
{
|
|
|
|
NSString *name = [self _name];
|
|
|
|
|
|
|
|
if (name)
|
|
|
|
{
|
|
|
|
if ([name isEqualToString: @"_NSMainMenu"])
|
|
|
|
{
|
|
|
|
// NB This is already handled by the nib loading code
|
|
|
|
//[NSApp setMainMenu: self];
|
|
|
|
}
|
|
|
|
else if ([name isEqualToString: @"_NSAppleMenu"])
|
|
|
|
{
|
|
|
|
// GNUstep does not handle Apple's application menu specially
|
|
|
|
}
|
|
|
|
else if ([name isEqualToString: @"_NSWindowsMenu"])
|
|
|
|
{
|
|
|
|
[NSApp setWindowsMenu: self];
|
|
|
|
}
|
|
|
|
else if ([name isEqualToString: @"_NSServicesMenu"])
|
|
|
|
{
|
|
|
|
[NSApp setServicesMenu: self];
|
|
|
|
}
|
|
|
|
else if ([name isEqualToString: @"_NSRecentDocumentsMenu"])
|
|
|
|
{
|
|
|
|
[[NSDocumentController sharedDocumentController]
|
|
|
|
_setRecentDocumentsMenu: self];
|
|
|
|
}
|
|
|
|
else if ([name isEqualToString: @"_NSFontMenu"])
|
|
|
|
{
|
|
|
|
[[NSFontManager sharedFontManager] setFontMenu: self];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-01-07 16:46:35 +00:00
|
|
|
/*
|
|
|
|
* NSCopying Protocol
|
|
|
|
*/
|
1999-06-30 03:10:38 +00:00
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
2001-08-27 18:49:34 +00:00
|
|
|
NSMenu *new = [[NSMenu allocWithZone: zone] initWithTitle: _title];
|
2016-12-31 16:03:01 +00:00
|
|
|
NSUInteger i;
|
|
|
|
NSUInteger count = [_items count];
|
2001-08-27 18:49:34 +00:00
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
[new setAutoenablesItems: _menu.autoenable];
|
2001-08-27 18:49:34 +00:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
// This works because the copy on NSMenuItem sets the menu to nil!!!
|
2010-09-12 16:34:22 +00:00
|
|
|
NSMenuItem *item = [[_items objectAtIndex: i] copyWithZone: zone];
|
|
|
|
[new insertItem: item atIndex: i];
|
|
|
|
RELEASE(item);
|
2001-08-27 18:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return new;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
2001-08-27 18:49:34 +00:00
|
|
|
|
1996-09-12 19:24:32 +00:00
|
|
|
@end
|
1999-07-28 10:31:56 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
@implementation NSMenu (GNUstepExtra)
|
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
- (void) setTornOff: (BOOL)flag
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2016-12-31 16:03:01 +00:00
|
|
|
NSMenu *supermenu;
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.is_tornoff = flag;
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2001-08-21 23:24:35 +00:00
|
|
|
if (flag)
|
2000-01-07 16:46:35 +00:00
|
|
|
{
|
2003-03-07 05:33:17 +00:00
|
|
|
supermenu = [self supermenu];
|
|
|
|
if (supermenu != nil)
|
|
|
|
{
|
|
|
|
[[supermenu menuRepresentation] setHighlightedItemIndex: -1];
|
|
|
|
supermenu->_attachedMenu = nil;
|
|
|
|
}
|
2000-01-07 16:46:35 +00:00
|
|
|
}
|
2003-03-07 05:33:17 +00:00
|
|
|
[_view update];
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
1999-07-28 10:31:56 +00:00
|
|
|
|
2000-01-07 16:46:35 +00:00
|
|
|
- (void) _showTornOffMenuIfAny: (NSNotification*)notification
|
1999-08-19 23:18:25 +00:00
|
|
|
{
|
2008-07-08 20:17:44 +00:00
|
|
|
NSInterfaceStyle style = NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil);
|
2009-01-25 13:47:30 +00:00
|
|
|
if (style == NSMacintoshInterfaceStyle
|
|
|
|
|| style == NSWindows95InterfaceStyle)
|
2006-02-04 19:58:55 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2017-01-08 19:33:32 +00:00
|
|
|
if (![self _isMain])
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2000-01-07 16:46:35 +00:00
|
|
|
NSString *key;
|
|
|
|
|
|
|
|
key = [self _locationKey];
|
2000-01-08 08:09:19 +00:00
|
|
|
if (key != nil)
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2000-01-08 08:09:19 +00:00
|
|
|
NSString *location;
|
|
|
|
NSUserDefaults *defaults;
|
|
|
|
NSDictionary *menuLocations;
|
|
|
|
|
|
|
|
defaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
menuLocations = [defaults objectForKey: NSMenuLocationsKey];
|
2003-06-05 14:46:04 +00:00
|
|
|
|
|
|
|
if ([menuLocations isKindOfClass: [NSDictionary class]])
|
|
|
|
location = [menuLocations objectForKey: key];
|
|
|
|
else
|
|
|
|
location = nil;
|
2000-01-08 08:09:19 +00:00
|
|
|
if (location && [location isKindOfClass: [NSString class]])
|
|
|
|
{
|
2003-03-07 05:33:17 +00:00
|
|
|
[self setTornOff: YES];
|
2000-01-08 08:09:19 +00:00
|
|
|
[self display];
|
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
|
|
|
}
|
1999-08-19 23:18:25 +00:00
|
|
|
}
|
|
|
|
|
2010-04-24 17:12:35 +00:00
|
|
|
- (void) applicationDidFinishLaunching:(NSNotification *)notification
|
|
|
|
{
|
2010-12-27 07:05:38 +00:00
|
|
|
if (NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil) ==
|
|
|
|
NSWindows95InterfaceStyle)
|
|
|
|
{
|
|
|
|
[[GSTheme theme] updateAllWindowsWithMenu: [NSApp mainMenu]];
|
|
|
|
}
|
2016-12-31 16:03:01 +00:00
|
|
|
[self _showTornOffMenuIfAny: notification];
|
2010-04-24 17:12:35 +00:00
|
|
|
}
|
|
|
|
|
2003-02-21 23:50:21 +00:00
|
|
|
- (void) _showOnActivateApp: (NSNotification*)notification
|
|
|
|
{
|
2017-01-08 19:33:32 +00:00
|
|
|
if ([self _isMain])
|
2003-02-21 23:50:21 +00:00
|
|
|
{
|
|
|
|
[self display];
|
|
|
|
// we must make sure that any attached submenu is visible too.
|
|
|
|
[[self attachedMenu] display];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
- (BOOL) isTransient
|
1999-07-28 10:31:56 +00:00
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
return _menu.transient;
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
- (BOOL) isPartlyOffScreen
|
|
|
|
{
|
2005-06-21 22:48:21 +00:00
|
|
|
NSWindow *window;
|
|
|
|
|
|
|
|
window = [self window];
|
2017-10-05 21:05:28 +00:00
|
|
|
if ((nil != window) && (nil != [window screen]))
|
|
|
|
{
|
|
|
|
return !NSContainsRect([[window screen] visibleFrame], [window frame]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"Menu has no window %@ or screen %@", window, [window screen]);
|
|
|
|
return YES;
|
|
|
|
}
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
1999-11-25 11:54:08 +00:00
|
|
|
- (void) _performMenuClose: (id)sender
|
1999-07-28 10:31:56 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
if (_attachedMenu)
|
|
|
|
[_view detachSubmenu];
|
2003-03-07 05:33:17 +00:00
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
[_view setHighlightedItemIndex: -1];
|
2000-01-07 16:46:35 +00:00
|
|
|
[self close];
|
2003-03-07 05:33:17 +00:00
|
|
|
[self setTornOff: NO];
|
|
|
|
[self _updateUserDefaults: nil];
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) display
|
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.transient)
|
2003-03-07 05:33:17 +00:00
|
|
|
{
|
2003-03-27 16:16:47 +00:00
|
|
|
NSDebugLLog (@"NSMenu",
|
2009-09-01 05:58:48 +00:00
|
|
|
@"trying to display while already displayed transient");
|
2003-03-07 05:33:17 +00:00
|
|
|
}
|
2003-04-01 19:51:41 +00:00
|
|
|
|
2017-01-08 19:33:32 +00:00
|
|
|
[self update];
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.needsSizing)
|
2003-03-30 12:48:06 +00:00
|
|
|
{
|
|
|
|
[self sizeToFit];
|
|
|
|
}
|
|
|
|
|
2003-03-22 16:29:40 +00:00
|
|
|
if (_superMenu && ![self isTornOff])
|
|
|
|
{
|
|
|
|
// query super menu for position
|
|
|
|
[_aWindow setFrameOrigin: [_superMenu locationForSubmenu: self]];
|
|
|
|
_superMenu->_attachedMenu = self;
|
|
|
|
}
|
2003-03-27 16:16:47 +00:00
|
|
|
else if ([_aWindow frame].origin.y <= 0
|
2006-10-02 05:09:48 +00:00
|
|
|
&& _popUpButtonCell == nil) // get geometry only if not set
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2006-10-02 05:09:48 +00:00
|
|
|
[self _setGeometry];
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
2003-03-30 12:48:06 +00:00
|
|
|
|
2003-03-27 16:16:47 +00:00
|
|
|
NSDebugLLog (@"NSMenu",
|
2003-03-30 12:48:06 +00:00
|
|
|
@"Display, origin: %@",
|
|
|
|
NSStringFromPoint ([_aWindow frame].origin));
|
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
[_aWindow orderFrontRegardless];
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) displayTransient
|
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
NSPoint location;
|
2000-09-26 11:45:32 +00:00
|
|
|
NSView *contentView;
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.transient)
|
2003-03-07 05:33:17 +00:00
|
|
|
{
|
|
|
|
NSDebugLLog (@"NSMenu", @"displaying transient while it is transient");
|
|
|
|
return;
|
|
|
|
}
|
2003-04-04 12:11:25 +00:00
|
|
|
|
2017-03-31 22:14:50 +00:00
|
|
|
[self update];
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.needsSizing)
|
2003-04-04 12:11:25 +00:00
|
|
|
{
|
|
|
|
[self sizeToFit];
|
|
|
|
}
|
2003-03-07 05:33:17 +00:00
|
|
|
|
|
|
|
_oldHiglightedIndex = [[self menuRepresentation] highlightedItemIndex];
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.transient = YES;
|
2003-03-07 05:33:17 +00:00
|
|
|
|
2000-01-07 20:46:45 +00:00
|
|
|
/*
|
|
|
|
* Cache the old submenu if any and query the supermenu our position.
|
|
|
|
* Otherwise, raise menu under the mouse.
|
|
|
|
*/
|
2001-08-19 23:21:59 +00:00
|
|
|
if (_superMenu != nil)
|
2000-01-07 20:46:45 +00:00
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
_oldAttachedMenu = _superMenu->_attachedMenu;
|
|
|
|
_superMenu->_attachedMenu = self;
|
|
|
|
location = [_superMenu locationForSubmenu: self];
|
2000-01-07 20:46:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-08-19 23:21:59 +00:00
|
|
|
NSRect frame = [_aWindow frame];
|
2010-12-30 19:56:03 +00:00
|
|
|
NSInterfaceStyle style;
|
2000-01-07 20:46:45 +00:00
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
location = [_aWindow mouseLocationOutsideOfEventStream];
|
|
|
|
location = [_aWindow convertBaseToScreen: location];
|
2010-12-30 19:56:03 +00:00
|
|
|
location.y -= frame.size.height;
|
|
|
|
|
|
|
|
/* When using the standard NextStep/OpenStep interface style, the
|
|
|
|
center of the menu's title view is placed below the mouse cursor.
|
|
|
|
However, in Macintosh and Windows95 styles, menus have no visible
|
|
|
|
title. To prevent the user from accidentally selecting the first
|
|
|
|
item, the top left edge is placed below the mouse cursor for them. */
|
|
|
|
style = NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil);
|
|
|
|
if (style != NSWindows95InterfaceStyle &&
|
|
|
|
style != NSMacintoshInterfaceStyle)
|
|
|
|
{
|
|
|
|
location.x -= frame.size.width/2;
|
|
|
|
if (location.x < 0)
|
|
|
|
location.x = 0;
|
|
|
|
location.y += 10;
|
|
|
|
}
|
2000-01-07 20:46:45 +00:00
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
[_bWindow setFrameOrigin: location];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
[_view removeFromSuperviewWithoutNeedingDisplay];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
contentView = [_bWindow contentView];
|
|
|
|
[contentView addSubview: _view];
|
2003-03-27 16:16:47 +00:00
|
|
|
|
2003-04-01 19:51:41 +00:00
|
|
|
[_view update];
|
2013-07-12 05:03:34 +00:00
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
[_bWindow orderFront: self];
|
2013-07-12 05:03:34 +00:00
|
|
|
|
|
|
|
/* Right mouse buttons which display transient menus don't update
|
|
|
|
* the cursor. So, the current cursor is displayed over the
|
|
|
|
* contextual menu (for example an I beam). However, when menu is
|
|
|
|
* closed the cursor pop, this can set a wrong cursor. We push here
|
|
|
|
* an arrow cursor, the cursor we want at menus. Being sure that
|
|
|
|
* this will pop when menu closes.
|
|
|
|
*/
|
|
|
|
[[NSCursor arrowCursor] push];
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) close
|
|
|
|
{
|
2001-08-27 18:49:34 +00:00
|
|
|
NSMenu *sub = [self attachedMenu];
|
1999-12-15 15:28:18 +00:00
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.transient)
|
2003-03-07 05:33:17 +00:00
|
|
|
{
|
|
|
|
NSDebugLLog (@"NSMenu", @"We should not close ordinary menu while transient version is still open");
|
|
|
|
}
|
|
|
|
|
1999-12-15 15:28:18 +00:00
|
|
|
/*
|
|
|
|
* If we have an attached submenu, we must close that too - but then make
|
|
|
|
* sure we still have a record of it so that it can be re-displayed if we
|
|
|
|
* are redisplayed.
|
|
|
|
*/
|
|
|
|
if (sub != nil)
|
|
|
|
{
|
|
|
|
[sub close];
|
2001-08-19 23:21:59 +00:00
|
|
|
_attachedMenu = sub;
|
1999-12-15 15:28:18 +00:00
|
|
|
}
|
2001-08-19 23:21:59 +00:00
|
|
|
[_aWindow orderOut: self];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
if (_superMenu && ![self isTornOff])
|
|
|
|
{
|
|
|
|
_superMenu->_attachedMenu = nil;
|
|
|
|
[[_superMenu menuRepresentation] setHighlightedItemIndex: -1];
|
|
|
|
}
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) closeTransient
|
|
|
|
{
|
2000-09-26 11:45:32 +00:00
|
|
|
NSView *contentView;
|
2003-03-07 05:33:17 +00:00
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.transient == NO)
|
2003-03-07 05:33:17 +00:00
|
|
|
{
|
2003-03-07 06:03:15 +00:00
|
|
|
NSDebugLLog (@"NSMenu",
|
|
|
|
@"Closing transient: %@ while it is NOT transient now", _title);
|
2003-03-07 05:33:17 +00:00
|
|
|
return;
|
|
|
|
}
|
2000-09-26 11:45:32 +00:00
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
[_bWindow orderOut: self];
|
|
|
|
[_view removeFromSuperviewWithoutNeedingDisplay];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2001-08-19 23:21:59 +00:00
|
|
|
contentView = [_aWindow contentView];
|
|
|
|
[contentView addSubview: _view];
|
1999-07-28 10:31:56 +00:00
|
|
|
|
2003-04-01 19:51:41 +00:00
|
|
|
[contentView setNeedsDisplay: YES];
|
|
|
|
|
2000-01-07 20:46:45 +00:00
|
|
|
// Restore the old submenu (if any).
|
2001-08-19 23:21:59 +00:00
|
|
|
if (_superMenu != nil)
|
2003-03-07 05:33:17 +00:00
|
|
|
{
|
|
|
|
_superMenu->_attachedMenu = _oldAttachedMenu;
|
|
|
|
[[_superMenu menuRepresentation] setHighlightedItemIndex:
|
2003-03-07 06:03:15 +00:00
|
|
|
[_superMenu indexOfItemWithSubmenu: _superMenu->_attachedMenu]];
|
2003-03-07 05:33:17 +00:00
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
[[self menuRepresentation] setHighlightedItemIndex: _oldHiglightedIndex];
|
|
|
|
|
2007-12-25 14:53:45 +00:00
|
|
|
_menu.transient = NO;
|
2003-04-01 19:51:41 +00:00
|
|
|
[_view update];
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
2000-01-07 20:46:45 +00:00
|
|
|
- (NSWindow*) window
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
if (_menu.transient)
|
2001-08-19 23:21:59 +00:00
|
|
|
return (NSWindow *)_bWindow;
|
1999-11-16 22:25:07 +00:00
|
|
|
else
|
2001-08-19 23:21:59 +00:00
|
|
|
return (NSWindow *)_aWindow;
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2004-11-11 19:52:24 +00:00
|
|
|
- (void) setMain: (BOOL)isMain
|
|
|
|
{
|
|
|
|
if (isMain)
|
|
|
|
{
|
2006-10-02 05:09:48 +00:00
|
|
|
NSMenuView *oldRep;
|
|
|
|
NSInterfaceStyle oldStyle;
|
|
|
|
NSInterfaceStyle newStyle;
|
|
|
|
|
|
|
|
oldRep = [self menuRepresentation];
|
|
|
|
oldStyle = [oldRep interfaceStyle];
|
|
|
|
newStyle = NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil);
|
2010-04-24 17:12:35 +00:00
|
|
|
|
2006-02-05 07:43:04 +00:00
|
|
|
/*
|
2006-10-02 05:09:48 +00:00
|
|
|
* If necessary, rebuild menu for (different) style
|
2006-02-05 07:43:04 +00:00
|
|
|
*/
|
2006-10-02 05:09:48 +00:00
|
|
|
if (oldStyle != newStyle)
|
|
|
|
{
|
2009-02-17 18:24:44 +00:00
|
|
|
NSMenuView *newRep;
|
2006-10-02 05:09:48 +00:00
|
|
|
|
2012-02-01 09:12:34 +00:00
|
|
|
if (oldStyle == NSWindows95InterfaceStyle)
|
|
|
|
{
|
|
|
|
/* Remove the menu from all main windows.
|
|
|
|
*/
|
|
|
|
[[GSTheme theme] updateAllWindowsWithMenu: nil];
|
|
|
|
}
|
|
|
|
if (newStyle == NSWindows95InterfaceStyle)
|
|
|
|
{
|
|
|
|
[self close];
|
|
|
|
}
|
2009-02-17 18:24:44 +00:00
|
|
|
newRep = [[NSMenuView alloc] initWithFrame: NSZeroRect];
|
|
|
|
if (newStyle == NSMacintoshInterfaceStyle
|
|
|
|
|| newStyle == NSWindows95InterfaceStyle)
|
|
|
|
{
|
|
|
|
[newRep setHorizontal: YES];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[newRep setHorizontal: NO];
|
|
|
|
}
|
|
|
|
[newRep setInterfaceStyle: newStyle];
|
|
|
|
[self setMenuRepresentation: newRep];
|
|
|
|
[self _organizeMenu];
|
|
|
|
RELEASE(newRep);
|
2012-02-01 09:12:34 +00:00
|
|
|
if (newStyle == NSWindows95InterfaceStyle)
|
2009-02-17 18:24:44 +00:00
|
|
|
{
|
2012-02-01 09:12:34 +00:00
|
|
|
/* Put menu in all main windows for microsoft style.
|
2009-02-17 18:24:44 +00:00
|
|
|
*/
|
2012-02-01 09:12:34 +00:00
|
|
|
[[GSTheme theme] updateAllWindowsWithMenu: self];
|
2009-02-17 18:24:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-25 18:28:20 +00:00
|
|
|
/* Adjust the menu window to suit the menu view unless the menu
|
|
|
|
* is being displayed in the application main window.
|
|
|
|
*/
|
2012-01-29 00:43:50 +00:00
|
|
|
if (newStyle != NSWindows95InterfaceStyle)
|
2009-02-17 18:24:44 +00:00
|
|
|
{
|
2009-01-25 13:47:30 +00:00
|
|
|
[[self window] setTitle: [[NSProcessInfo processInfo] processName]];
|
|
|
|
[[self window] setLevel: NSMainMenuWindowLevel];
|
|
|
|
[self _setGeometry];
|
|
|
|
[self sizeToFit];
|
2012-02-01 09:12:34 +00:00
|
|
|
|
|
|
|
if ([NSApp isActive])
|
|
|
|
{
|
|
|
|
[self display];
|
|
|
|
}
|
2009-02-17 18:24:44 +00:00
|
|
|
}
|
2004-11-11 19:52:24 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[[self window] setLevel: NSSubmenuWindowLevel];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-01-23 16:32:20 +00:00
|
|
|
/**
|
|
|
|
Set the frame origin of the receiver to aPoint. If a submenu of
|
|
|
|
the receiver is attached. The frame origin of the submenu is set
|
|
|
|
appropriately.
|
|
|
|
*/
|
1999-11-16 22:25:07 +00:00
|
|
|
- (void) nestedSetFrameOrigin: (NSPoint) aPoint
|
1999-07-28 10:31:56 +00:00
|
|
|
{
|
2003-03-07 05:33:17 +00:00
|
|
|
NSWindow *theWindow = [self window];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
|
|
|
// Move ourself and get our width.
|
2001-08-21 23:24:35 +00:00
|
|
|
[theWindow setFrameOrigin: aPoint];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
|
|
|
// Do the same for attached menus.
|
2001-08-19 23:21:59 +00:00
|
|
|
if (_attachedMenu)
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2002-01-23 16:32:20 +00:00
|
|
|
aPoint = [self locationForSubmenu: _attachedMenu];
|
2001-08-19 23:21:59 +00:00
|
|
|
[_attachedMenu nestedSetFrameOrigin: aPoint];
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-11-17 23:01:54 +00:00
|
|
|
#define SHIFT_DELTA 18.0
|
1999-11-16 22:25:07 +00:00
|
|
|
|
|
|
|
- (void) shiftOnScreen
|
|
|
|
{
|
2007-12-25 14:53:45 +00:00
|
|
|
NSWindow *theWindow = [self window];
|
1999-11-16 22:25:07 +00:00
|
|
|
NSRect frameRect = [theWindow frame];
|
2005-06-21 22:48:21 +00:00
|
|
|
NSRect screenRect = [[theWindow screen] visibleFrame];
|
1999-11-16 22:25:07 +00:00
|
|
|
NSPoint vector = {0.0, 0.0};
|
2003-03-07 05:33:17 +00:00
|
|
|
BOOL moveIt = NO;
|
2010-07-26 19:16:18 +00:00
|
|
|
NSPoint location = [theWindow mouseLocationOutsideOfEventStream];
|
|
|
|
NSPoint pointerLoc = [theWindow convertBaseToScreen: location];
|
2010-12-30 19:56:03 +00:00
|
|
|
NSInterfaceStyle style = NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil);
|
2003-03-07 05:33:17 +00:00
|
|
|
|
2010-12-30 19:56:03 +00:00
|
|
|
// Don't move the main menu bar in Macintosh interface style, this is
|
|
|
|
// annoying (in particular, since the effective screen range is reduced
|
|
|
|
// by the height of the menu bar!)
|
2017-01-08 19:33:32 +00:00
|
|
|
if (style == NSMacintoshInterfaceStyle && [self _isMain])
|
2006-02-04 19:58:55 +00:00
|
|
|
return;
|
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
// 1 - determine the amount we need to shift in the y direction.
|
2010-07-26 19:16:18 +00:00
|
|
|
if (pointerLoc.y <= 1 && NSMinY (frameRect) < 0)
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2003-03-07 05:33:17 +00:00
|
|
|
vector.y = MIN (SHIFT_DELTA, -NSMinY (frameRect));
|
|
|
|
moveIt = YES;
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
2010-07-26 19:16:18 +00:00
|
|
|
/* Note: pointerLoc.y may be greater than NSMaxY(screenRect) if we have a
|
|
|
|
horizontal menu bar at the top of the screen (Macintosh interface style) */
|
|
|
|
// FIXME Don't move the horizontal menu bar downward in this case!
|
|
|
|
else if (pointerLoc.y >= NSMaxY(screenRect) &&
|
|
|
|
NSMaxY (frameRect) > NSMaxY (screenRect))
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2003-03-07 05:33:17 +00:00
|
|
|
vector.y = -MIN (SHIFT_DELTA, NSMaxY (frameRect) - NSMaxY (screenRect));
|
|
|
|
moveIt = YES;
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
// 2 - determine the amount we need to shift in the x direction.
|
2010-07-26 19:16:18 +00:00
|
|
|
if (pointerLoc.x == 0 && NSMinX (frameRect) < 0)
|
2003-03-07 05:33:17 +00:00
|
|
|
{
|
|
|
|
vector.x = MIN (SHIFT_DELTA, -NSMinX (frameRect));
|
|
|
|
moveIt = YES;
|
|
|
|
}
|
|
|
|
// Note the -3. This is done so the menu, after shifting completely
|
|
|
|
// has some spare room on the right hand side. This is needed otherwise
|
|
|
|
// the user can never access submenus of this menu.
|
2010-07-26 19:16:18 +00:00
|
|
|
else if (pointerLoc.x == NSMaxX(screenRect) - 1 &&
|
|
|
|
NSMaxX (frameRect) > NSMaxX (screenRect) - 3)
|
2003-03-07 05:33:17 +00:00
|
|
|
{
|
2003-03-07 06:03:15 +00:00
|
|
|
vector.x
|
|
|
|
= -MIN (SHIFT_DELTA, NSMaxX (frameRect) - NSMaxX (screenRect) + 3);
|
2003-03-07 05:33:17 +00:00
|
|
|
moveIt = YES;
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
2003-03-30 12:48:06 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
if (moveIt)
|
|
|
|
{
|
2003-03-30 12:48:06 +00:00
|
|
|
NSPoint masterLocation;
|
|
|
|
NSPoint destinationPoint;
|
|
|
|
|
2010-12-30 19:56:03 +00:00
|
|
|
if (style == NSMacintoshInterfaceStyle || _menu.horizontal)
|
2006-02-04 19:58:55 +00:00
|
|
|
{
|
2010-07-26 19:16:18 +00:00
|
|
|
masterLocation = frameRect.origin;
|
2007-12-25 14:53:45 +00:00
|
|
|
destinationPoint.x = masterLocation.x + vector.x;
|
|
|
|
destinationPoint.y = masterLocation.y + vector.y;
|
2006-02-04 19:58:55 +00:00
|
|
|
[self nestedSetFrameOrigin: destinationPoint];
|
2007-12-25 14:53:45 +00:00
|
|
|
}
|
2006-02-04 19:58:55 +00:00
|
|
|
else
|
2007-12-25 14:53:45 +00:00
|
|
|
{
|
|
|
|
NSMenu *candidateMenu;
|
|
|
|
NSMenu *masterMenu;
|
|
|
|
|
|
|
|
// Look for the "master" menu, i.e. the one to move from.
|
|
|
|
for (candidateMenu = masterMenu = self;
|
|
|
|
(candidateMenu = masterMenu->_superMenu)
|
2010-12-30 19:56:03 +00:00
|
|
|
&& !candidateMenu->_menu.horizontal
|
2007-12-25 14:53:45 +00:00
|
|
|
&& (!masterMenu->_menu.is_tornoff
|
|
|
|
|| masterMenu->_menu.transient);
|
|
|
|
masterMenu = candidateMenu);
|
|
|
|
|
|
|
|
masterLocation = [[masterMenu window] frame].origin;
|
|
|
|
destinationPoint.x = masterLocation.x + vector.x;
|
|
|
|
destinationPoint.y = masterLocation.y + vector.y;
|
2006-02-04 19:58:55 +00:00
|
|
|
[masterMenu nestedSetFrameOrigin: destinationPoint];
|
2007-12-25 14:53:45 +00:00
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
2001-08-19 23:21:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)_ownedByPopUp
|
|
|
|
{
|
2001-10-07 23:43:43 +00:00
|
|
|
return _popUpButtonCell != nil;
|
2001-08-19 23:21:59 +00:00
|
|
|
}
|
|
|
|
|
2008-02-07 19:12:59 +00:00
|
|
|
- (NSPopUpButtonCell *)_owningPopUp
|
|
|
|
{
|
|
|
|
return _popUpButtonCell;
|
|
|
|
}
|
|
|
|
|
2001-10-07 23:43:43 +00:00
|
|
|
- (void)_setOwnedByPopUp: (NSPopUpButtonCell*)popUp
|
2001-08-19 23:21:59 +00:00
|
|
|
{
|
2001-10-07 23:43:43 +00:00
|
|
|
if (_popUpButtonCell != popUp)
|
2001-08-19 23:21:59 +00:00
|
|
|
{
|
2001-10-07 23:43:43 +00:00
|
|
|
_popUpButtonCell = popUp;
|
|
|
|
if (popUp != nil)
|
2001-08-19 23:21:59 +00:00
|
|
|
{
|
|
|
|
[_aWindow setLevel: NSPopUpMenuWindowLevel];
|
|
|
|
[_bWindow setLevel: NSPopUpMenuWindowLevel];
|
|
|
|
}
|
2000-01-08 08:09:19 +00:00
|
|
|
}
|
2003-03-07 05:33:17 +00:00
|
|
|
[self update];
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
- (NSString*) description
|
1999-07-28 10:31:56 +00:00
|
|
|
{
|
2003-03-07 05:33:17 +00:00
|
|
|
return [NSString stringWithFormat: @"NSMenu: %@ (%@)",
|
2007-12-25 14:53:45 +00:00
|
|
|
_title, _menu.transient ? @"Transient": @"Normal"];
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
2001-08-21 23:24:35 +00:00
|
|
|
|
2003-03-07 05:33:17 +00:00
|
|
|
@end
|
2001-09-11 17:29:51 +00:00
|
|
|
|