Author: mlytwyn Date: Fri May 8 00:40:12 2015 New Revision: 38481 URL: http://svn.gna.org/viewcvs/gnustep?rev=38481&view=rev Log: Fix recursion crash on method 'update'
Modified: libs/gui/branches/gnustep_testplant_branch/Headers/AppKit/NSMenu.h libs/gui/branches/gnustep_testplant_branch/Source/NSMenu.m Modified: libs/gui/branches/gnustep_testplant_branch/Headers/AppKit/NSMenu.h URL: http://svn.gna.org/viewcvs/gnustep/libs/gui/branches/gnustep_testplant_branch/Headers/AppKit/NSMenu.h?rev=38481&r1=38480&r2=38481&view=diff ============================================================================== --- libs/gui/branches/gnustep_testplant_branch/Headers/AppKit/NSMenu.h (original) +++ libs/gui/branches/gnustep_testplant_branch/Headers/AppKit/NSMenu.h Fri May 8 00:40:12 2015 @@ -348,7 +348,8 @@ unsigned int transient: 1; unsigned int horizontal: 1; unsigned int mainMenuChanged: 1; - unsigned int unused: 25; + unsigned int isUpdating: 1; + unsigned int unused: 24; } _menu; @private Modified: libs/gui/branches/gnustep_testplant_branch/Source/NSMenu.m URL: http://svn.gna.org/viewcvs/gnustep/libs/gui/branches/gnustep_testplant_branch/Source/NSMenu.m?rev=38481&r1=38480&r2=38481&view=diff ============================================================================== --- libs/gui/branches/gnustep_testplant_branch/Source/NSMenu.m (original) +++ libs/gui/branches/gnustep_testplant_branch/Source/NSMenu.m Fri May 8 00:40:12 2015 @@ -1091,150 +1091,157 @@ - (void) update { - if (_delegate) - { - if ([_delegate respondsToSelector:@selector(menuNeedsUpdate:)]) - { - [_delegate menuNeedsUpdate:self]; - } - else if ([_delegate respondsToSelector:@selector(numberOfItemsInMenu:)]) - { - NSInteger num; - - num = [_delegate numberOfItemsInMenu: self]; - if (num > 0) + if (_menu.isUpdating == NO) + { + _menu.isUpdating = YES; + + if (_delegate) + { + if ([_delegate respondsToSelector:@selector(menuNeedsUpdate:)]) { - BOOL cont = YES; - NSInteger i = 0; - NSInteger curr = [self numberOfItems]; - - while (num < curr) + [_delegate menuNeedsUpdate:self]; + } + else if ([_delegate respondsToSelector:@selector(numberOfItemsInMenu:)]) + { + NSInteger num; + + num = [_delegate numberOfItemsInMenu: self]; + if (num > 0) { - [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 - updateItem: (NSMenuItem*)[self itemAtIndex: i] - atIndex: i - shouldCancel: NO]; - i++; + BOOL cont = YES; + NSInteger i = 0; + NSInteger curr = [self numberOfItems]; + + 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 + updateItem: (NSMenuItem*)[self itemAtIndex: i] + atIndex: i + shouldCancel: NO]; + i++; + } } } } - } - - // We use this as a recursion check. - if (!_menu.changedMessagesEnabled) - return; - - if ([self autoenablesItems]) - { - unsigned i, count; - - count = [_items count]; - // Temporary disable automatic displaying of menu. - [self setMenuChangedMessagesEnabled: NO]; - - NS_DURING - { - for (i = 0; i < count; i++) - { - NSMenuItem *item = [_items objectAtIndex: i]; - SEL action = [item action]; - id validator = nil; - BOOL wasEnabled = [item isEnabled]; - BOOL shouldBeEnabled; - - // Update the submenu items if any. - if ([item hasSubmenu]) - [[item submenu] update]; - - // If there is no action - there can be no validator for the item. - if (action) - { - 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]; - } - else if ([item hasSubmenu] && [[item submenu] numberOfItems] == 0) + // We use this as a recursion check. + if (_menu.changedMessagesEnabled) + { + if ([self autoenablesItems]) + { + unsigned i, count; + + count = [_items count]; + + // Temporary disable automatic displaying of menu. + [self setMenuChangedMessagesEnabled: NO]; + + NS_DURING + { + for (i = 0; i < count; i++) + { + NSMenuItem *item = [_items objectAtIndex: i]; + SEL action = [item action]; + id validator = nil; + BOOL wasEnabled = [item isEnabled]; + BOOL shouldBeEnabled; + + // Update the submenu items if any. + if ([item hasSubmenu]) + [[item submenu] update]; + + // If there is no action - there can be no validator for the item. + if (action) + { + 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]; + } + else if ([item hasSubmenu] && [[item submenu] numberOfItems] == 0) + { + shouldBeEnabled = NO; + } + else + { + shouldBeEnabled = YES; + } + + if (shouldBeEnabled != wasEnabled) + { + [item setEnabled: shouldBeEnabled]; + } + } + } + NS_HANDLER { - shouldBeEnabled = NO; + NSLog(@"Error Occurred While Updating Menu %@: %@", [self title], localException); } - else - { - shouldBeEnabled = YES; - } - - if (shouldBeEnabled != wasEnabled) - { - [item setEnabled: shouldBeEnabled]; - } - } + NS_ENDHANDLER + // Reenable displaying of menus + [self setMenuChangedMessagesEnabled: YES]; // this will send pending _notifications } - NS_HANDLER - { - NSLog(@"Error Occurred While Updating Menu %@: %@", [self title], localException); - } - NS_ENDHANDLER - // Reenable displaying of menus - [self setMenuChangedMessagesEnabled: YES]; // this will send pending _notifications - } - - if (_menu.mainMenuChanged) - { - if (NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil) == NSWindows95InterfaceStyle) - { - [[GSTheme theme] updateAllWindowsWithMenu: self]; + + if (_menu.mainMenuChanged) + { + if (NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil) == NSWindows95InterfaceStyle) + { + [[GSTheme theme] updateAllWindowsWithMenu: self]; + } + _menu.mainMenuChanged = NO; } - _menu.mainMenuChanged = NO; - } - - if (_menu.needsSizing && ([_aWindow isVisible] || [_bWindow isVisible])) - { - NSDebugLLog (@"NSMenu", @" Calling Size To Fit (A)"); - [self sizeToFit]; + + if (_menu.needsSizing && ([_aWindow isVisible] || [_bWindow isVisible])) + { + NSDebugLLog (@"NSMenu", @" Calling Size To Fit (A)"); + [self sizeToFit]; + } + } + + _menu.isUpdating = NO; } return; _______________________________________________ Gnustep-cvs mailing list Gnustep-cvs@gna.org https://mail.gna.org/listinfo/gnustep-cvs