Merge with maintenance clone

This commit is contained in:
Airy ANDRE 2013-02-01 14:59:02 +01:00
commit b66abae4d0
7 changed files with 308 additions and 9 deletions

View File

@ -8,8 +8,18 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
#import <AppKit/NSMenuView.h>
#import <AppKit/NSMenuWindow.h>
#import <AppKit/NSMainMenuView.h>
#import <AppKit/NSRaise.h>
enum {
kNSMenuKeyboardNavigationNone,
kNSMenuKeyboardNavigationUp,
kNSMenuKeyboardNavigationDown,
kNSMenuKeyboardNavigationLeft,
kNSMenuKeyboardNavigationRight,
kNSMenuKeyboardNavigationLetter
};
@implementation NSMenuView
-(void)dealloc
@ -92,9 +102,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
}
#if 0
#define MENUDEBUG(x, ...) NSLog(x, __VA_ARGS__)
#define MENUDEBUG(...) NSLog(__VA_ARGS__)
#else
#define MENUDEBUG(x, ...)
#define MENUDEBUG(...)
#endif
const float kMenuInitialClickThreshold = 0.1f;
@ -132,6 +142,8 @@ const float kMouseMovementThreshold = .001f;
[event retain];
int keyboardNavigationAction = kNSMenuKeyboardNavigationNone;
BOOL cancelled = NO;
MENUDEBUG(@"entering outer loop");
@ -151,6 +163,8 @@ const float kMouseMovementThreshold = .001f;
screen=[self _screenForPoint:point];
}
if (keyboardNavigationAction == kNSMenuKeyboardNavigationNone) {
// We're not current dealing with a keyboard event
// Take a look at the visible menu stack (we're within a big loop so views can come and
// go and the mouse can wander all over) deepest first
while(--count>=0){
@ -171,7 +185,7 @@ const float kMouseMovementThreshold = .001f;
// Which item is the cursor on top of?
unsigned itemIndex=[checkView itemIndexAtPoint:checkPoint];
MENUDEBUG(@"index: %u", itemIndex);
MENUDEBUG(@"found an item index: %u", itemIndex);
// If it's not the currently selected item
if(itemIndex!=[checkView selectedItemIndex]){
@ -214,13 +228,230 @@ const float kMouseMovementThreshold = .001f;
MENUDEBUG(@"clearing all selection");
[[viewStack lastObject] setSelectedItemIndex:NSNotFound];
}
}
[event release];
// Let's take a look at what's come in on the event queue
event=[[self window] nextEventMatchingMask:NSLeftMouseUpMask|NSMouseMovedMask|NSLeftMouseDraggedMask|NSAppKitDefinedMask];
event=[[self window] nextEventMatchingMask:NSLeftMouseUpMask|NSMouseMovedMask|NSLeftMouseDraggedMask|NSKeyDownMask|NSAppKitDefinedMask];
[event retain];
if (keyboardNavigationAction != kNSMenuKeyboardNavigationNone) {
// We didn't enter the mouse handling loop that predecrements count - so do it here...
count--;
}
// Reset the keyboard navigation state
keyboardNavigationAction = kNSMenuKeyboardNavigationNone;
if ([event type] == NSKeyDown) {
NSString* chars = [event characters];
unichar ch = [chars characterAtIndex: 0];
switch (ch) {
case NSUpArrowFunctionKey:
keyboardNavigationAction = kNSMenuKeyboardNavigationUp;
break;
case NSDownArrowFunctionKey:
keyboardNavigationAction = kNSMenuKeyboardNavigationDown;
break;
case NSLeftArrowFunctionKey:
keyboardNavigationAction = kNSMenuKeyboardNavigationLeft;
break;
case NSRightArrowFunctionKey:
keyboardNavigationAction = kNSMenuKeyboardNavigationRight;
break;
case '\r': // Return = select the current item and exit the loop
MENUDEBUG(@"Selecting current item and exit");
state = STATE_EXIT;
break;
case 27: // Escape = pop unless we're done then it's cancel
{
if ([viewStack count] > 1) {
NSView* view = [viewStack lastObject];
MENUDEBUG(@"popping cascading view: %@", view);
[[view window] close];
[viewStack removeLastObject];
} else {
MENUDEBUG(@"Cancelling");
cancelled = YES;
}
}
break;
default:
keyboardNavigationAction = kNSMenuKeyboardNavigationLetter;
break;
}
NSMenuView* activeMenuView = [viewStack lastObject];
BOOL ignoreEnabledState = NO;
if ([viewStack count] == 1 && [activeMenuView isKindOfClass: [NSMainMenuView class]]) {
// For some reason main menu items are disabled - even though they work fine...
ignoreEnabledState = YES;
// we're navigating the top menu which has opposite semantics than a regular menu
switch (keyboardNavigationAction) {
case kNSMenuKeyboardNavigationDown:
keyboardNavigationAction = kNSMenuKeyboardNavigationRight;
break;
case kNSMenuKeyboardNavigationUp:
keyboardNavigationAction = kNSMenuKeyboardNavigationLeft;
break;
case kNSMenuKeyboardNavigationLeft:
keyboardNavigationAction = kNSMenuKeyboardNavigationUp;
break;
case kNSMenuKeyboardNavigationRight:
keyboardNavigationAction = kNSMenuKeyboardNavigationDown;
break;
}
}
switch (keyboardNavigationAction) {
case kNSMenuKeyboardNavigationUp:
{
MENUDEBUG(@"Up...");
unsigned oldIndex = [activeMenuView selectedItemIndex];
NSArray *items = [activeMenuView itemArray];
// Look for the next enabled item by search up and wrapping around the bottom
unsigned newIndex = 0;
if (oldIndex != NSNotFound) {
newIndex = oldIndex == 0 ? [items count] - 1 : oldIndex - 1;
}
MENUDEBUG(@"oldIndex = %u", oldIndex);
MENUDEBUG(@"newIndex = %u", newIndex);
BOOL found = NO;
while (!found && newIndex != oldIndex) {
// Make sure we stop eventually
if (oldIndex == NSNotFound) {
oldIndex = 0;
}
// Try and find a new item to select
NSMenuItem *item = [items objectAtIndex: newIndex];
if ([item isSeparatorItem] == NO &&
((ignoreEnabledState || [item isEnabled]) || [item hasSubmenu])) {
MENUDEBUG(@"selecting item = %@", item);
[activeMenuView setSelectedItemIndex: newIndex];
found = YES;
} else {
MENUDEBUG(@"skipping item: %@", item);
if (newIndex == 0) {
newIndex = [items count] - 1;
} else {
newIndex --;
}
}
}
}
break;
case kNSMenuKeyboardNavigationDown:
{
MENUDEBUG(@"Down...");
unsigned oldIndex = [activeMenuView selectedItemIndex];
NSArray *items = [activeMenuView itemArray];
// Look for the next enabled item by search down and wrapping around to the top
unsigned newIndex = 0;
if (oldIndex != NSNotFound) {
newIndex = oldIndex == [items count] -1 ? 0 : oldIndex + 1;
}
MENUDEBUG(@"oldIndex = %u", oldIndex);
MENUDEBUG(@"newIndex = %u", newIndex);
BOOL found = NO;
while (!found && newIndex != oldIndex) {
// Make sure we stop eventually
if (oldIndex == NSNotFound) {
oldIndex = 0;
}
// Try and find a new item to select
NSMenuItem *item = [items objectAtIndex: newIndex];
if ([item isSeparatorItem] == NO &&
((ignoreEnabledState || [item isEnabled]) || [item hasSubmenu])) {
MENUDEBUG(@"selecting item: %u", item);
[activeMenuView setSelectedItemIndex: newIndex];
found = YES;
} else {
MENUDEBUG(@"skipping item: %@", item);
if (newIndex == [items count] - 1) {
newIndex = 0;
} else {
newIndex++;
}
}
}
}
break;
case kNSMenuKeyboardNavigationLeft:
MENUDEBUG(@"Left...");
if ([viewStack count] > 1) {
NSView* view = [viewStack lastObject];
MENUDEBUG(@"popping cascading view: %@", view);
[[view window] close];
[viewStack removeLastObject];
}
break;
case kNSMenuKeyboardNavigationRight:
{
MENUDEBUG(@"Right...");
NSMenuView *branch = nil;
// If there's a submenu at the current selected index
if((branch=[activeMenuView viewAtSelectedIndexPositionOnScreen:screen])!=nil) {
MENUDEBUG(@"adding a new cascading view: %@", branch);
[viewStack addObject:branch];
} else {
// We'll pop it - they're trying to navigate to the next menu most likely
if ([viewStack count] > 1) {
NSView* view = [viewStack lastObject];
MENUDEBUG(@"popping cascading view: %@", view);
[[view window] close];
[viewStack removeLastObject];
}
}
}
break;
case kNSMenuKeyboardNavigationLetter:
{
MENUDEBUG(@"Letter...");
NSString *letterString = [[NSString stringWithCharacters: &ch length: 1] uppercaseString];
unsigned oldIndex = [activeMenuView selectedItemIndex];
NSArray *items = [activeMenuView itemArray];
// Look for the next enabled item by search down and wrapping around to the top
unsigned newIndex = 0;
if (oldIndex != NSNotFound) {
newIndex = oldIndex == [items count] -1 ? 0 : oldIndex + 1;
}
MENUDEBUG(@"oldIndex = %u", oldIndex);
MENUDEBUG(@"newIndex = %u", newIndex);
BOOL found = NO;
while (!found && newIndex != oldIndex) {
// Make sure we stop eventually
if (oldIndex == NSNotFound) {
oldIndex = 0;
}
// Try and find a new item to select
NSMenuItem *item = [items objectAtIndex: newIndex];
if ((ignoreEnabledState || [item isEnabled] == YES) || [item hasSubmenu] == YES) {
NSRange range = [[item title] rangeOfString: letterString];
if (range.location != NSNotFound) {
MENUDEBUG(@"selecting item: %u", item);
[activeMenuView setSelectedItemIndex: newIndex];
found = YES;
}
}
if (!found) {
MENUDEBUG(@"skipping item: %@", item);
if (newIndex == [items count] - 1) {
newIndex = 0;
} else {
newIndex++;
}
}
}
}
break;
}
}
// We use this special AppKitDefined event to let the menu respond to the app deactivation - it *has*
// to be passed through the event system, unfortunately
if ([event type] == NSAppKitDefined) {
@ -230,7 +461,7 @@ const float kMouseMovementThreshold = .001f;
}
}
if (cancelled == NO && [event type] != NSAppKitDefined) {
if (cancelled == NO && [event type] != NSAppKitDefined && [event type] != NSKeyDown) {
// looks like we can keep rolling

View File

@ -471,6 +471,8 @@ enum {
if (searchIndex >= [items count]) {
_selectedIndex = previous;
} else {
_selectedIndex = searchIndex;
}
[self setNeedsDisplay:YES];
@ -484,4 +486,51 @@ enum {
_keyboardUIState = KEYBOARD_OK;
}
- (void)insertText:(id)aString {
// We're intercepting insertText: so we can do menu navigation by letter
unichar ch = [aString characterAtIndex: 0];
NSString *letterString = [[NSString stringWithCharacters: &ch length: 1] uppercaseString];
NSInteger oldIndex = _selectedIndex;
NSArray *items = [_menu itemArray];
NSInteger newIndex = _selectedIndex;
// Set to the next item in the array or the start if we're at the end or there's no selection
if (oldIndex == NSNotFound || oldIndex == [items count] - 1) {
newIndex = 0;
} else {
newIndex = oldIndex + 1;
}
// Find the next visible item that has a title with an uppercase letter matching what the user
// entered (who knows what this means in Japan...)
BOOL found = NO;
while (!found && newIndex != oldIndex) {
// Make sure we stop eventually
if (oldIndex == NSNotFound) {
oldIndex = 0;
}
// Try and find a new item to select
NSMenuItem *item = [items objectAtIndex: newIndex];
if ([item isEnabled] == YES && [item isSeparatorItem] == NO) {
NSRange range = [[item title] rangeOfString: letterString];
if (range.location != NSNotFound) {
_selectedIndex = newIndex;
found = YES;
}
}
if (!found) {
if (newIndex == [items count] - 1) {
newIndex = 0;
} else {
newIndex++;
}
}
}
if (newIndex != oldIndex) {
[self setNeedsDisplay:YES];
}
}
@end

View File

@ -2571,7 +2571,11 @@ NSString * const NSOldSelectedCharacterRange=@"NSOldSelectedCharacterRange";
- (void)keyUp:(NSEvent*)event
{
<<<<<<< local
// Just to eat the event - else it is passed to the nextResponder, and we don't want that
=======
// Just to eat the event - else it is passed to the nextResponder, and we don't want that
>>>>>>> other
}
-(void)doCommandBySelector:(SEL)selector {

View File

@ -151,9 +151,11 @@ static BOOL openFileWithHelpViewer(const char *helpFilePath)
if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir])
{
NSString *win32Path = NSStringFromNullTerminatedUnicode([path fileSystemRepresentationW]);
NSMutableData *args=[NSMutableData data];
[args appendBytes:L"/select," length:16];
[args appendData:NSTaskArgumentDataFromStringW(path)];
[args appendData: NSTaskArgumentDataFromStringW(win32Path)];
[args appendBytes:L"\0" length:2];
return ((int)ShellExecuteW(GetDesktopWindow(),L"open",L"explorer",[args bytes],NULL,SW_SHOWNORMAL)<=32)?NO:YES;

View File

@ -147,14 +147,20 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
}
-(void)removeObject:object {
NSInteger count=[self count];
NSInteger count=[self count];
// Make sure it doesn't disappear on us during this operation
[object retain];
while(--count>=0){
id check=[self objectAtIndex:count];
if([check isEqual:object])
[self removeObjectAtIndex:count];
}
[object release];
}
-(void)removeObject:object inRange:(NSRange)range {
@ -164,12 +170,17 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
NSRaiseException(NSRangeException,self,_cmd,@"range %@ beyond count %d",
NSStringFromRange(range),[self count]);
// Make sure it doesn't disappear on us during this operation
[object retain];
while(--pos>=range.location){
id check=[self objectAtIndex:pos];
if([check isEqual:object])
[self removeObjectAtIndex:pos];
}
[object release];
}
-(void)removeObjectIdenticalTo:object {
@ -190,7 +201,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
NSRaiseException(NSRangeException,self,_cmd,@"range %@ beyond count %d",
NSStringFromRange(range),[self count]);
while(--pos>=range.location){
id check=[self objectAtIndex:pos];

View File

@ -88,6 +88,8 @@ void NSSetTableRemoveObject(NSSetTable *table,id object){
NSUInteger index=[object hash]%table->numBuckets;
NSSetBucket *current,*last,*bucket=table->buckets[index];
// Make sure the object lives through the operation
[object retain];
for(current=last=bucket;current!=NULL;last=current,current=current->next)
if([current->key isEqual:object]){
if(last==current)
@ -100,6 +102,7 @@ void NSSetTableRemoveObject(NSSetTable *table,id object){
NSZoneFree(NSZoneFromPointer(current),current);
break;
}
[object release];
}
NSUInteger NSSetTableObjectCount(NSSetTable *table,id object) {

View File

@ -391,7 +391,7 @@ void NSPlatformLogString(NSString *string) {
eventLog=RegisterEventSource(NULL,[processName() cString]);
}
ReportEvent(eventLog,EVENTLOG_ERROR_TYPE,1,1,NULL,1,0,&cString,NULL);
ReportEvent(eventLog,EVENTLOG_INFORMATION_TYPE,1,1,NULL,1,0,&cString,NULL);
// CloseEventLog(handle);
}