diff --git a/src/MacVim/MMBackend.h b/src/MacVim/MMBackend.h index df754a66b1..a49cb24054 100644 --- a/src/MacVim/MMBackend.h +++ b/src/MacVim/MMBackend.h @@ -57,6 +57,7 @@ - (NSConnection *)connection; - (NSDictionary *)actionDict; +- (void)queueMessage:(int)msgid properties:(NSDictionary *)props; - (BOOL)checkin; - (BOOL)openVimWindow; - (void)clearAll; @@ -84,15 +85,6 @@ saving:(int)saving; - (int)presentDialogWithType:(int)type title:(char *)title message:(char *)msg buttons:(char *)btns textField:(char *)txtfield; -- (void)addMenuWithTag:(int)tag parent:(int)parentTag name:(char *)name - atIndex:(int)index; -- (void)addMenuItemWithTag:(int)tag parent:(int)parentTag name:(char *)name - tip:(char *)tip icon:(char *)icon - keyEquivalent:(int)key modifiers:(int)mods - action:(char *)action isAlternate:(int)isAlt - atIndex:(int)index; -- (void)removeMenuItemWithTag:(int)tag; -- (void)enableMenuItemWithTag:(int)tag state:(int)enabled; - (void)showPopupMenuWithName:(char *)name atMouseLocation:(BOOL)mouse; - (void)showToolbar:(int)enable flags:(int)flags; - (void)createScrollbarWithIdentifier:(long)ident type:(int)type; diff --git a/src/MacVim/MMBackend.m b/src/MacVim/MMBackend.m index 0afd312264..6df13500e2 100644 --- a/src/MacVim/MMBackend.m +++ b/src/MacVim/MMBackend.m @@ -51,10 +51,12 @@ static unsigned MMServerMax = 1000; // TODO: Move to separate file. static int eventModifierFlagsToVimModMask(int modifierFlags); -static int vimModMaskToEventModifierFlags(int mods); static int eventModifierFlagsToVimMouseModMask(int modifierFlags); static int eventButtonNumberToVimMouseButton(int buttonNumber); -static int specialKeyToNSKey(int key); + +// In gui_macvim.m +vimmenu_T *menu_for_descriptor(NSArray *desc); + enum { MMBlinkStateNone = 0, @@ -76,6 +78,7 @@ static NSString *MMSymlinkWarningString = + @interface MMBackend (Private) - (void)queueVimStateMessage; - (void)processInputQueue; @@ -226,6 +229,11 @@ static NSString *MMSymlinkWarningString = return actionDict; } +- (void)queueMessage:(int)msgid properties:(NSDictionary *)props +{ + [self queueMessage:msgid data:[props dictionaryAsData]]; +} + - (BOOL)checkin { if (![self connection]) { @@ -740,78 +748,6 @@ static NSString *MMSymlinkWarningString = return retval; } -- (void)addMenuWithTag:(int)tag parent:(int)parentTag name:(char *)name - atIndex:(int)index -{ - //NSLog(@"addMenuWithTag:%d parent:%d name:%s atIndex:%d", tag, parentTag, - // name, index); - - int namelen = name ? strlen(name) : 0; - NSMutableData *data = [NSMutableData data]; - - [data appendBytes:&tag length:sizeof(int)]; - [data appendBytes:&parentTag length:sizeof(int)]; - [data appendBytes:&namelen length:sizeof(int)]; - if (namelen > 0) [data appendBytes:name length:namelen]; - [data appendBytes:&index length:sizeof(int)]; - - [self queueMessage:AddMenuMsgID data:data]; -} - -- (void)addMenuItemWithTag:(int)tag parent:(int)parentTag name:(char *)name - tip:(char *)tip icon:(char *)icon - keyEquivalent:(int)key modifiers:(int)mods - action:(char *)action isAlternate:(int)isAlt - atIndex:(int)index -{ - //NSLog(@"addMenuItemWithTag:%d parent:%d name:%s tip:%s atIndex:%d", tag, - // parentTag, name, tip, index); - - int namelen = name ? strlen(name) : 0; - int tiplen = tip ? strlen(tip) : 0; - int iconlen = icon ? strlen(icon) : 0; - int eventFlags = vimModMaskToEventModifierFlags(mods); - int actionlen = action ? strlen(action) : 0; - NSMutableData *data = [NSMutableData data]; - - key = specialKeyToNSKey(key); - - [data appendBytes:&tag length:sizeof(int)]; - [data appendBytes:&parentTag length:sizeof(int)]; - [data appendBytes:&namelen length:sizeof(int)]; - if (namelen > 0) [data appendBytes:name length:namelen]; - [data appendBytes:&tiplen length:sizeof(int)]; - if (tiplen > 0) [data appendBytes:tip length:tiplen]; - [data appendBytes:&iconlen length:sizeof(int)]; - if (iconlen > 0) [data appendBytes:icon length:iconlen]; - [data appendBytes:&actionlen length:sizeof(int)]; - if (actionlen > 0) [data appendBytes:action length:actionlen]; - [data appendBytes:&index length:sizeof(int)]; - [data appendBytes:&key length:sizeof(int)]; - [data appendBytes:&eventFlags length:sizeof(int)]; - [data appendBytes:&isAlt length:sizeof(int)]; - - [self queueMessage:AddMenuItemMsgID data:data]; -} - -- (void)removeMenuItemWithTag:(int)tag -{ - NSMutableData *data = [NSMutableData data]; - [data appendBytes:&tag length:sizeof(int)]; - - [self queueMessage:RemoveMenuItemMsgID data:data]; -} - -- (void)enableMenuItemWithTag:(int)tag state:(int)enabled -{ - NSMutableData *data = [NSMutableData data]; - - [data appendBytes:&tag length:sizeof(int)]; - [data appendBytes:&enabled length:sizeof(int)]; - - [self queueMessage:EnableMenuItemMsgID data:data]; -} - - (void)showPopupMenuWithName:(char *)name atMouseLocation:(BOOL)mouse { int len = strlen(name); @@ -1659,14 +1595,12 @@ static NSString *MMSymlinkWarningString = //NSLog(@"[VimTask] Resizing shell to %dx%d.", cols, rows); gui_resize_shell(cols, rows); } else if (ExecuteMenuMsgID == msgid) { - if (!data) return; - const void *bytes = [data bytes]; - int tag = *((int*)bytes); bytes += sizeof(int); - - vimmenu_T *menu = (vimmenu_T*)tag; - // TODO! Make sure 'menu' is a valid menu pointer! - if (menu) { - gui_menu_cb(menu); + NSDictionary *attrs = [NSDictionary dictionaryWithData:data]; + if (attrs) { + NSArray *desc = [attrs objectForKey:@"descriptor"]; + vimmenu_T *menu = menu_for_descriptor(desc); + if (menu) + gui_menu_cb(menu); } } else if (ToggleToolbarMsgID == msgid) { [self handleToggleToolbar]; @@ -2475,22 +2409,6 @@ static int eventModifierFlagsToVimModMask(int modifierFlags) return modMask; } -static int vimModMaskToEventModifierFlags(int mods) -{ - int flags = 0; - - if (mods & MOD_MASK_SHIFT) - flags |= NSShiftKeyMask; - if (mods & MOD_MASK_CTRL) - flags |= NSControlKeyMask; - if (mods & MOD_MASK_ALT) - flags |= NSAlternateKeyMask; - if (mods & MOD_MASK_CMD) - flags |= NSCommandKeyMask; - - return flags; -} - static int eventModifierFlagsToVimMouseModMask(int modifierFlags) { int modMask = 0; @@ -2512,68 +2430,3 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber) return (buttonNumber >= 0 && buttonNumber < 3) ? mouseButton[buttonNumber] : -1; } - -static int specialKeyToNSKey(int key) -{ - if (!IS_SPECIAL(key)) - return key; - - static struct { - int special; - int nskey; - } sp2ns[] = { - { K_UP, NSUpArrowFunctionKey }, - { K_DOWN, NSDownArrowFunctionKey }, - { K_LEFT, NSLeftArrowFunctionKey }, - { K_RIGHT, NSRightArrowFunctionKey }, - { K_F1, NSF1FunctionKey }, - { K_F2, NSF2FunctionKey }, - { K_F3, NSF3FunctionKey }, - { K_F4, NSF4FunctionKey }, - { K_F5, NSF5FunctionKey }, - { K_F6, NSF6FunctionKey }, - { K_F7, NSF7FunctionKey }, - { K_F8, NSF8FunctionKey }, - { K_F9, NSF9FunctionKey }, - { K_F10, NSF10FunctionKey }, - { K_F11, NSF11FunctionKey }, - { K_F12, NSF12FunctionKey }, - { K_F13, NSF13FunctionKey }, - { K_F14, NSF14FunctionKey }, - { K_F15, NSF15FunctionKey }, - { K_F16, NSF16FunctionKey }, - { K_F17, NSF17FunctionKey }, - { K_F18, NSF18FunctionKey }, - { K_F19, NSF19FunctionKey }, - { K_F20, NSF20FunctionKey }, - { K_F21, NSF21FunctionKey }, - { K_F22, NSF22FunctionKey }, - { K_F23, NSF23FunctionKey }, - { K_F24, NSF24FunctionKey }, - { K_F25, NSF25FunctionKey }, - { K_F26, NSF26FunctionKey }, - { K_F27, NSF27FunctionKey }, - { K_F28, NSF28FunctionKey }, - { K_F29, NSF29FunctionKey }, - { K_F30, NSF30FunctionKey }, - { K_F31, NSF31FunctionKey }, - { K_F32, NSF32FunctionKey }, - { K_F33, NSF33FunctionKey }, - { K_F34, NSF34FunctionKey }, - { K_F35, NSF35FunctionKey }, - { K_DEL, NSBackspaceCharacter }, - { K_BS, NSDeleteCharacter }, - { K_HOME, NSHomeFunctionKey }, - { K_END, NSEndFunctionKey }, - { K_PAGEUP, NSPageUpFunctionKey }, - { K_PAGEDOWN, NSPageDownFunctionKey } - }; - - int i; - for (i = 0; i < sizeof(sp2ns)/sizeof(sp2ns[0]); ++i) { - if (sp2ns[i].special == key) - return sp2ns[i].nskey; - } - - return 0; -} diff --git a/src/MacVim/MMVimController.m b/src/MacVim/MMVimController.m index 72a39ba179..9d9b1ab5f4 100644 --- a/src/MacVim/MMVimController.m +++ b/src/MacVim/MMVimController.m @@ -64,18 +64,21 @@ static NSTimeInterval MMResendInterval = 0.5; - (NSMenuItem *)recurseMenuItemForTag:(int)tag rootMenu:(NSMenu *)root; - (NSMenuItem *)menuItemForTag:(int)tag; - (NSMenu *)menuForTag:(int)tag; +- (NSMenu *)parentMenuForDescriptor:(NSArray *)desc; - (NSMenu *)topLevelMenuForTitle:(NSString *)title; -- (void)addMenuWithTag:(int)tag parent:(int)parentTag title:(NSString *)title - atIndex:(int)idx; -- (void)addMenuItemWithTag:(int)tag parent:(NSMenu *)parent - title:(NSString *)title tip:(NSString *)tip - keyEquivalent:(int)key modifiers:(int)mask - action:(NSString *)action isAlternate:(int)isAlt - atIndex:(int)idx; +- (void)addMenuWithDescriptor:(NSArray *)desc atIndex:(int)index; +- (void)addMenuItemWithDescriptor:(NSArray *)desc + atIndex:(int)index + tip:(NSString *)tip + icon:(NSString *)icon + keyEquivalent:(NSString *)keyEquivalent + modifierMask:(int)modifierMask + action:(NSString *)action + isAlternate:(BOOL)isAlternate; - (NSToolbarItem *)toolbarItemForTag:(int)tag index:(int *)index; -- (void)addToolbarItemToDictionaryWithTag:(int)tag label:(NSString *)title +- (void)addToolbarItemToDictionaryWithLabel:(NSString *)title toolTip:(NSString *)tip icon:(NSString *)icon; -- (void)addToolbarItemWithTag:(int)tag label:(NSString *)label +- (void)addToolbarItemWithLabel:(NSString *)label tip:(NSString *)tip icon:(NSString *)icon atIndex:(int)idx; - (void)connectionDidDie:(NSNotification *)notification; @@ -656,6 +659,7 @@ static NSTimeInterval MMResendInterval = 0.5; [string release]; } else if (AddMenuMsgID == msgid) { +#if 0 NSString *title = nil; const void *bytes = [data bytes]; int tag = *((int*)bytes); bytes += sizeof(int); @@ -688,7 +692,13 @@ static NSTimeInterval MMResendInterval = 0.5; } [title release]; +#else + NSDictionary *attrs = [NSDictionary dictionaryWithData:data]; + [self addMenuWithDescriptor:[attrs objectForKey:@"descriptor"] + atIndex:[[attrs objectForKey:@"index"] intValue]]; +#endif } else if (AddMenuItemMsgID == msgid) { +#if 0 NSString *title = nil, *tip = nil, *icon = nil, *action = nil; const void *bytes = [data bytes]; int tag = *((int*)bytes); bytes += sizeof(int); @@ -740,7 +750,19 @@ static NSTimeInterval MMResendInterval = 0.5; [tip release]; [icon release]; [action release]; +#else + NSDictionary *attrs = [NSDictionary dictionaryWithData:data]; + [self addMenuItemWithDescriptor:[attrs objectForKey:@"descriptor"] + atIndex:[[attrs objectForKey:@"index"] intValue] + tip:[attrs objectForKey:@"tip"] + icon:[attrs objectForKey:@"icon"] + keyEquivalent:[attrs objectForKey:@"keyEquivalent"] + modifierMask:[[attrs objectForKey:@"modifierMask"] intValue] + action:[attrs objectForKey:@"action"] + isAlternate:[[attrs objectForKey:@"isAlternate"] boolValue]]; +#endif } else if (RemoveMenuItemMsgID == msgid) { +#if 0 const void *bytes = [data bytes]; int tag = *((int*)bytes); bytes += sizeof(int); @@ -767,7 +789,9 @@ static NSTimeInterval MMResendInterval = 0.5; // Reset cached menu, just to be on the safe side. lastMenuSearched = nil; +#endif } else if (EnableMenuItemMsgID == msgid) { +#if 0 const void *bytes = [data bytes]; int tag = *((int*)bytes); bytes += sizeof(int); int state = *((int*)bytes); bytes += sizeof(int); @@ -777,6 +801,7 @@ static NSTimeInterval MMResendInterval = 0.5; item = [self menuItemForTag:tag]; [item setEnabled:state]; +#endif } else if (ShowToolbarMsgID == msgid) { const void *bytes = [data bytes]; int enable = *((int*)bytes); bytes += sizeof(int); @@ -1052,6 +1077,36 @@ static NSTimeInterval MMResendInterval = 0.5; return [[self menuItemForTag:tag] submenu]; } +- (NSMenu *)parentMenuForDescriptor:(NSArray *)desc +{ + if (!(desc && [desc count] > 0)) return nil; + + NSString *rootName = [desc objectAtIndex:0]; + NSArray *rootItems = [rootName hasPrefix:@"PopUp"] ? popupMenuItems + : mainMenuItems; + + NSMenu *menu = nil; + int i, count = [rootItems count]; + for (i = 0; i < count; ++i) { + NSMenuItem *item = [rootItems objectAtIndex:i]; + if ([[item title] isEqual:rootName]) { + menu = [item submenu]; + break; + } + } + + if (!menu) return nil; + + count = [desc count] - 1; + for (i = 1; i < count; ++i) { + NSMenuItem *item = [menu itemWithTitle:[desc objectAtIndex:i]]; + menu = [item submenu]; + if (!menu) return nil; + } + + return menu; +} + - (NSMenu *)topLevelMenuForTitle:(NSString *)title { // Search only the top-level menus. @@ -1073,9 +1128,9 @@ static NSTimeInterval MMResendInterval = 0.5; return nil; } -- (void)addMenuWithTag:(int)tag parent:(int)parentTag title:(NSString *)title - atIndex:(int)idx +- (void)addMenuWithDescriptor:(NSArray *)desc atIndex:(int)idx { +#if 0 NSMenu *parent = [self menuForTag:parentTag]; NSMenuItem *item = [[NSMenuItem alloc] init]; NSMenu *menu = [[NSMenu alloc] initWithTitle:title]; @@ -1105,14 +1160,73 @@ static NSTimeInterval MMResendInterval = 0.5; [item release]; [menu release]; +#else + if (!(desc && [desc count] > 0)) return; + + NSString *rootName = [desc objectAtIndex:0]; + if ([rootName isEqual:@"ToolBar"]) { + // The toolbar only has one menu, we take this as a hint to create a + // toolbar, then we return. + if (!toolbar) { + // NOTE! Each toolbar must have a unique identifier, else each + // window will have the same toolbar. + NSString *ident = [NSString stringWithFormat:@"%d", (int)self]; + toolbar = [[NSToolbar alloc] initWithIdentifier:ident]; + + [toolbar setShowsBaselineSeparator:NO]; + [toolbar setDelegate:self]; + [toolbar setDisplayMode:NSToolbarDisplayModeIconOnly]; + [toolbar setSizeMode:NSToolbarSizeModeSmall]; + + [windowController setToolbar:toolbar]; + } + + return; + } + + // This is either a main menu item or a popup menu item. + NSString *title = [desc lastObject]; + NSMenuItem *item = [[NSMenuItem alloc] init]; + NSMenu *menu = [[NSMenu alloc] initWithTitle:title]; + + [menu setAutoenablesItems:NO]; + [item setTitle:title]; + [item setSubmenu:menu]; + + NSMenu *parent = [self parentMenuForDescriptor:desc]; + if (parent) { + if ([parent numberOfItems] <= idx) { + [parent addItem:item]; + } else { + [parent insertItem:item atIndex:idx]; + } + } else { + BOOL isPopup = [rootName hasPrefix:@"PopUp"]; + NSMutableArray *items = isPopup ? popupMenuItems : mainMenuItems; + if ([items count] <= idx) { + [items addObject:item]; + } else { + [items insertObject:item atIndex:idx]; + } + + shouldUpdateMainMenu = !isPopup; + } + + [item release]; + [menu release]; +#endif } -- (void)addMenuItemWithTag:(int)tag parent:(NSMenu *)parent - title:(NSString *)title tip:(NSString *)tip - keyEquivalent:(int)key modifiers:(int)mask - action:(NSString *)action isAlternate:(int)isAlt - atIndex:(int)idx +- (void)addMenuItemWithDescriptor:(NSArray *)desc + atIndex:(int)idx + tip:(NSString *)tip + icon:(NSString *)icon + keyEquivalent:(NSString *)keyEquivalent + modifierMask:(int)modifierMask + action:(NSString *)action + isAlternate:(BOOL)isAlternate { +#if 0 if (parent) { NSMenuItem *item = nil; if (!title || ([title hasPrefix:@"-"] && [title hasSuffix:@"-"])) { @@ -1160,6 +1274,66 @@ static NSTimeInterval MMResendInterval = 0.5; } else { NSLog(@"WARNING: Menu item '%@' (tag=%d) has no parent.", title, tag); } +#else + if (!(desc && [desc count] > 1)) return; + + NSString *title = [desc lastObject]; + NSString *rootName = [desc objectAtIndex:0]; + + if ([rootName isEqual:@"ToolBar"]) { + if (toolbar) + [self addToolbarItemWithLabel:title tip:tip icon:icon atIndex:idx]; + return; + } + + NSMenu *parent = [self parentMenuForDescriptor:desc]; + if (!parent) { + NSLog(@"WARNING: Menu item '%@' has no parent", + [desc componentsJoinedByString:@"->"]); + return; + } + + NSMenuItem *item = nil; + if (!title || ([title hasPrefix:@"-"] && [title hasSuffix:@"-"])) { + item = [NSMenuItem separatorItem]; + } else { + item = [[[NSMenuItem alloc] init] autorelease]; + [item setTitle:title]; + + if ([action isEqualToString:@"recentFilesDummy:"]) { + // Remove the recent files menu item from its current menu + // and put it in the current file menu. See -[MMAppController + // applicationWillFinishLaunching for more information. + //[[recentFilesMenuItem menu] removeItem:recentFilesMenuItem]; + //item = recentFilesMenuItem; + recentFilesDummy = [item retain]; + } else { + // TODO: Check that 'action' is a valid action (nothing will + // happen if it isn't, but it would be nice with a warning). + if ([action length] > 0) + [item setAction:NSSelectorFromString(action)]; + else + [item setAction:@selector(vimMenuItemAction:)]; + if ([tip length] > 0) [item setToolTip:tip]; + if ([keyEquivalent length] > 0) { + [item setKeyEquivalent:keyEquivalent]; + [item setKeyEquivalentModifierMask:modifierMask]; + } + [item setAlternate:isAlternate]; + } + } + + // NOTE! The tag is used to idenfity which menu items were + // added by Vim (tag != 0) and which were added by the AppKit + // (tag == 0). + [item setTag:-1]; + + if ([parent numberOfItems] <= idx) { + [parent addItem:item]; + } else { + [parent insertItem:item atIndex:idx]; + } +#endif } - (NSToolbarItem *)toolbarItemForTag:(int)tag index:(int *)index @@ -1179,7 +1353,7 @@ static NSTimeInterval MMResendInterval = 0.5; return nil; } -- (void)addToolbarItemToDictionaryWithTag:(int)tag label:(NSString *)title +- (void)addToolbarItemToDictionaryWithLabel:(NSString *)title toolTip:(NSString *)tip icon:(NSString *)icon { // If the item corresponds to a separator then do nothing, since it is @@ -1190,7 +1364,7 @@ static NSTimeInterval MMResendInterval = 0.5; return; NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:title]; - [item setTag:tag]; + [item setTag:-1]; [item setLabel:title]; [item setToolTip:tip]; [item setAction:@selector(vimMenuItemAction:)]; @@ -1213,7 +1387,7 @@ static NSTimeInterval MMResendInterval = 0.5; [item release]; } -- (void)addToolbarItemWithTag:(int)tag label:(NSString *)label tip:(NSString +- (void)addToolbarItemWithLabel:(NSString *)label tip:(NSString *)tip icon:(NSString *)icon atIndex:(int)idx { if (!toolbar) return; @@ -1234,8 +1408,7 @@ static NSTimeInterval MMResendInterval = 0.5; } } - [self addToolbarItemToDictionaryWithTag:tag label:label toolTip:tip - icon:icon]; + [self addToolbarItemToDictionaryWithLabel:label toolTip:tip icon:icon]; int maxIdx = [[toolbar items] count]; if (maxIdx < idx) idx = maxIdx; diff --git a/src/MacVim/MMWindowController.m b/src/MacVim/MMWindowController.m index c3b055e355..b1b2ecf437 100644 --- a/src/MacVim/MMWindowController.m +++ b/src/MacVim/MMWindowController.m @@ -614,12 +614,26 @@ - (IBAction)vimMenuItemAction:(id)sender { - int tag = [sender tag]; + if (![sender isKindOfClass:[NSMenuItem class]]) return; - NSMutableData *data = [NSMutableData data]; - [data appendBytes:&tag length:sizeof(int)]; + // TODO: Make into category on NSMenuItem which returns descriptor. + NSMenuItem *item = (NSMenuItem*)sender; + NSMutableArray *desc = [NSMutableArray arrayWithObject:[item title]]; - [vimController sendMessage:ExecuteMenuMsgID data:data]; + NSMenu *menu = [item menu]; + while (menu) { + [desc insertObject:[menu title] atIndex:0]; + menu = [menu supermenu]; + } + + // The "MainMenu" item is part of the Cocoa menu and should not be part of + // the descriptor. + if ([[desc objectAtIndex:0] isEqual:@"MainMenu"]) + [desc removeObjectAtIndex:0]; + + NSDictionary *attrs = [NSDictionary dictionaryWithObject:desc + forKey:@"descriptor"]; + [vimController sendMessage:ExecuteMenuMsgID data:[attrs dictionaryAsData]]; } diff --git a/src/MacVim/gui_macvim.m b/src/MacVim/gui_macvim.m index 701712d835..63a5cc09ba 100644 --- a/src/MacVim/gui_macvim.m +++ b/src/MacVim/gui_macvim.m @@ -32,6 +32,15 @@ static float MMMaxFontSize = 100.0f; static NSFont *gui_macvim_font_with_name(char_u *name); +static int specialKeyToNSKey(int key); +static int vimModMaskToEventModifierFlags(int mods); + +NSArray *descriptor_for_menu(vimmenu_T *menu); +vimmenu_T *menu_for_descriptor(NSArray *desc); + +@interface NSString (VimStrings) ++ (id)stringWithVimString:(char_u *)s; +@end @@ -606,6 +615,46 @@ clip_mch_set_selection(VimClipboard *cbd) // -- Menu ------------------------------------------------------------------ + NSArray * +descriptor_for_menu(vimmenu_T *menu) +{ + if (!menu) return nil; + + NSMutableArray *desc = [NSMutableArray array]; + while (menu) { + NSString *name = [NSString stringWithVimString:menu->dname]; + [desc insertObject:name atIndex:0]; + menu = menu->parent; + } + + return desc; +} + + vimmenu_T * +menu_for_descriptor(NSArray *desc) +{ + if (!(desc && [desc count] > 0)) return NULL; + + vimmenu_T *menu = root_menu; + int i, count = [desc count]; + + for (i = 0; i < count; ++i) { + NSString *component = [desc objectAtIndex:i]; + while (menu) { + NSString *name = [NSString stringWithVimString:menu->dname]; + if ([component isEqual:name]) { + if (i+1 == count) + return menu; // Matched all components, so return menu + menu = menu->children; + break; + } + menu = menu->next; + } + } + + return NULL; +} + /* * Add a sub menu to the menu bar. */ @@ -628,9 +677,12 @@ gui_mch_add_menu(vimmenu_T *menu, int idx) dname = CONVERT_TO_UTF8(dname); #endif - [[MMBackend sharedInstance] - addMenuWithTag:(int)menu parent:parent name:(char*)dname - atIndex:idx]; + NSArray *desc = descriptor_for_menu(menu); + [[MMBackend sharedInstance] queueMessage:AddMenuMsgID properties: + [NSDictionary dictionaryWithObjectsAndKeys: + desc, @"descriptor", + [NSNumber numberWithInt:idx], @"index", + nil]]; #ifdef FEAT_MBYTE CONVERT_TO_UTF8_FREE(dname); @@ -649,40 +701,24 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx) char_u *icon = menu->iconfile ? menu->iconfile : menu->iconidx >= 0 ? menu->dname : NULL; - //char *name = menu_is_separator(menu->name) ? NULL : (char*)menu->dname; - char_u *name = menu->dname; char_u *tip = menu->strings[MENU_INDEX_TIP] ? menu->strings[MENU_INDEX_TIP] : menu->actext; - char_u *map_str = menu->strings[MENU_INDEX_NORMAL]; - char_u *mac_action = menu->mac_action; + NSArray *desc = descriptor_for_menu(menu); + NSString *keyEquivalent = [NSString stringWithFormat:@"%C", + specialKeyToNSKey(menu->mac_key)]; + int modifierMask = vimModMaskToEventModifierFlags(menu->mac_mods); -#ifdef FEAT_MBYTE - icon = CONVERT_TO_UTF8(icon); - name = CONVERT_TO_UTF8(name); - tip = CONVERT_TO_UTF8(tip); - map_str = CONVERT_TO_UTF8(map_str); - mac_action = CONVERT_TO_UTF8(mac_action); -#endif - - [[MMBackend sharedInstance] - addMenuItemWithTag:(int)menu - parent:(int)menu->parent - name:(char*)name - tip:(char*)tip - icon:(char*)icon - keyEquivalent:menu->mac_key - modifiers:menu->mac_mods - action:(char*)mac_action - isAlternate:menu->mac_alternate - atIndex:idx]; - -#ifdef FEAT_MBYTE - CONVERT_TO_UTF8_FREE(icon); - CONVERT_TO_UTF8_FREE(name); - CONVERT_TO_UTF8_FREE(tip); - CONVERT_TO_UTF8_FREE(map_str); - CONVERT_TO_UTF8_FREE(mac_action); -#endif + [[MMBackend sharedInstance] queueMessage:AddMenuItemMsgID properties: + [NSDictionary dictionaryWithObjectsAndKeys: + desc, @"descriptor", + [NSNumber numberWithInt:idx], @"index", + [NSString stringWithVimString:tip], @"tip", + [NSString stringWithVimString:icon], @"icon", + keyEquivalent, @"keyEquivalent", + [NSNumber numberWithInt:modifierMask], @"modifierMask", + [NSString stringWithVimString:menu->mac_action], @"action", + [NSNumber numberWithBool:menu->mac_alternate], @"isAlternate", + nil]]; } @@ -692,7 +728,9 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx) void gui_mch_destroy_menu(vimmenu_T *menu) { - [[MMBackend sharedInstance] removeMenuItemWithTag:(int)menu]; + NSArray *desc = descriptor_for_menu(menu); + [[MMBackend sharedInstance] queueMessage:RemoveMenuItemMsgID properties: + [NSDictionary dictionaryWithObject:desc forKey:@"descriptor"]]; } @@ -705,12 +743,12 @@ gui_mch_menu_grey(vimmenu_T *menu, int grey) /* Only update menu if the 'grey' state has changed to avoid having to pass * lots of unnecessary data to MacVim. (Skipping this test makes MacVim * pause noticably on mode changes. */ - if (menu->was_grey != grey) - { - menu->was_grey = grey; - [[MMBackend sharedInstance] - enableMenuItemWithTag:(int)menu state:!grey]; - } + if (menu->was_grey != grey) return; + + menu->was_grey = grey; + [[MMBackend sharedInstance] queueMessage:EnableMenuItemMsgID properties: + [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:!grey] + forKey:@"enable"]]; } @@ -732,6 +770,7 @@ gui_mch_menu_hidden(vimmenu_T *menu, int hidden) void gui_mch_show_popupmenu(vimmenu_T *menu) { +#if 0 char_u *name = menu->name; #ifdef FEAT_MBYTE name = CONVERT_TO_UTF8(name); @@ -743,7 +782,7 @@ gui_mch_show_popupmenu(vimmenu_T *menu) #ifdef FEAT_MBYTE CONVERT_TO_UTF8_FREE(name); #endif - +#endif } @@ -753,6 +792,7 @@ gui_mch_show_popupmenu(vimmenu_T *menu) void gui_make_popup(char_u *path_name, int mouse_pos) { +#if 0 #ifdef FEAT_MBYTE path_name = CONVERT_TO_UTF8(path_name); #endif @@ -763,6 +803,7 @@ gui_make_popup(char_u *path_name, int mouse_pos) #ifdef FEAT_MBYTE CONVERT_TO_UTF8_FREE(path_name); #endif +#endif } @@ -1886,3 +1927,105 @@ is_valid_macaction(char_u *action) return isValid; } + +static int specialKeyToNSKey(int key) +{ + if (!IS_SPECIAL(key)) + return key; + + static struct { + int special; + int nskey; + } sp2ns[] = { + { K_UP, NSUpArrowFunctionKey }, + { K_DOWN, NSDownArrowFunctionKey }, + { K_LEFT, NSLeftArrowFunctionKey }, + { K_RIGHT, NSRightArrowFunctionKey }, + { K_F1, NSF1FunctionKey }, + { K_F2, NSF2FunctionKey }, + { K_F3, NSF3FunctionKey }, + { K_F4, NSF4FunctionKey }, + { K_F5, NSF5FunctionKey }, + { K_F6, NSF6FunctionKey }, + { K_F7, NSF7FunctionKey }, + { K_F8, NSF8FunctionKey }, + { K_F9, NSF9FunctionKey }, + { K_F10, NSF10FunctionKey }, + { K_F11, NSF11FunctionKey }, + { K_F12, NSF12FunctionKey }, + { K_F13, NSF13FunctionKey }, + { K_F14, NSF14FunctionKey }, + { K_F15, NSF15FunctionKey }, + { K_F16, NSF16FunctionKey }, + { K_F17, NSF17FunctionKey }, + { K_F18, NSF18FunctionKey }, + { K_F19, NSF19FunctionKey }, + { K_F20, NSF20FunctionKey }, + { K_F21, NSF21FunctionKey }, + { K_F22, NSF22FunctionKey }, + { K_F23, NSF23FunctionKey }, + { K_F24, NSF24FunctionKey }, + { K_F25, NSF25FunctionKey }, + { K_F26, NSF26FunctionKey }, + { K_F27, NSF27FunctionKey }, + { K_F28, NSF28FunctionKey }, + { K_F29, NSF29FunctionKey }, + { K_F30, NSF30FunctionKey }, + { K_F31, NSF31FunctionKey }, + { K_F32, NSF32FunctionKey }, + { K_F33, NSF33FunctionKey }, + { K_F34, NSF34FunctionKey }, + { K_F35, NSF35FunctionKey }, + { K_DEL, NSBackspaceCharacter }, + { K_BS, NSDeleteCharacter }, + { K_HOME, NSHomeFunctionKey }, + { K_END, NSEndFunctionKey }, + { K_PAGEUP, NSPageUpFunctionKey }, + { K_PAGEDOWN, NSPageDownFunctionKey } + }; + + int i; + for (i = 0; i < sizeof(sp2ns)/sizeof(sp2ns[0]); ++i) { + if (sp2ns[i].special == key) + return sp2ns[i].nskey; + } + + return 0; +} + +static int vimModMaskToEventModifierFlags(int mods) +{ + int flags = 0; + + if (mods & MOD_MASK_SHIFT) + flags |= NSShiftKeyMask; + if (mods & MOD_MASK_CTRL) + flags |= NSControlKeyMask; + if (mods & MOD_MASK_ALT) + flags |= NSAlternateKeyMask; + if (mods & MOD_MASK_CMD) + flags |= NSCommandKeyMask; + + return flags; +} + + + + +@implementation NSString (VimStrings) ++ (id)stringWithVimString:(char_u *)s +{ + if (s) { +#ifdef FEAT_MBYTE + s = CONVERT_TO_UTF8(s); +#endif + NSString *string = [NSString stringWithUTF8String:(char*)s]; +#ifdef FEAT_MBYTE + CONVERT_TO_UTF8_FREE(s); +#endif + return string; + } + + return [NSString string]; +} +@end