diff options
-rw-r--r-- | webkit/glue/webmenurunner_mac.h | 71 | ||||
-rw-r--r-- | webkit/glue/webmenurunner_mac.mm | 130 | ||||
-rwxr-xr-x | webkit/tools/test_shell/mac/test_webview_delegate.mm | 131 | ||||
-rw-r--r-- | webkit/webkit.gyp | 2 |
4 files changed, 217 insertions, 117 deletions
diff --git a/webkit/glue/webmenurunner_mac.h b/webkit/glue/webmenurunner_mac.h new file mode 100644 index 0000000..eceaa3f --- /dev/null +++ b/webkit/glue/webmenurunner_mac.h @@ -0,0 +1,71 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_GLUE_WEBMENURUNNER_MAC_H_ +#define WEBKIT_GLUE_WEBMENURUNNER_MAC_H_ + +#import <Cocoa/Cocoa.h> + +#include <vector> + +#include "webkit/glue/webwidget_delegate.h" + + +// WebMenuRunner --------------------------------------------------------------- +// A class for determining whether an item was selected from an HTML select +// control, or if the menu was dismissed without making a selection. If a menu +// item is selected, MenuDelegate is informed and sets a flag which can be +// queried after the menu has finished running. + +@interface WebMenuRunner : NSObject { + @private + // The actual menu object, which we own. + NSMenu* menu_; + + // A flag set to YES if a menu item was chosen, or NO if the menu was + // dismissed without selecting an item. + BOOL menuItemWasChosen_; + + // The index of the selected menu item. + int index_; +} + +// Initializes the MenuDelegate with a list of items sent from WebKit. +- (id)initWithItems:(const std::vector<WebMenuItem>&)items; +- (void)dealloc; + +// Worker function used during initialization. +- (void)addItem:(const WebMenuItem&)item; + +// Returns YES if an item was selected from the menu, NO if the menu was +// dismissed. +- (BOOL)menuItemWasChosen; + +// A callback for the menu controller object to call when an item is selected +// from the menu. This is not called if the menu is dismissed without a +// selection. +- (void)menuItemSelected:(id)sender; + +// Displays and runs a native popup menu. +- (void)runMenuInView:(NSView*)view + withBounds:(NSRect)bounds + initialIndex:(int)index; + +// Returns the index of selected menu item, or its initial value (-1) if no item +// was selected. +- (int)indexOfSelectedItem; + +@end // @interface WebMenuRunner + +// Helper function for manufacturing input events to send to WebKit. If +// |item_chosen| is YES, we manufacture a mouse click event that corresponds to +// the menu item that was selected, |selected_index|, based on the position of +// the mouse click. Of |item_chosen| is NO, we create a keyboard event that +// simulates an ESC (menu dismissal) action. The event is designed to be sent to +// WebKit for processing by the PopupMenu class. +NSEvent* CreateEventForMenuAction(BOOL item_chosen, int window_num, + int item_height, int selected_index, + NSRect menu_bounds, NSRect view_bounds); + +#endif // WEBKIT_GLUE_WEBMENURUNNER_MAC_H_ diff --git a/webkit/glue/webmenurunner_mac.mm b/webkit/glue/webmenurunner_mac.mm new file mode 100644 index 0000000..32bedf3 --- /dev/null +++ b/webkit/glue/webmenurunner_mac.mm @@ -0,0 +1,130 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/glue/webmenurunner_mac.h" + +#include "base/sys_string_conversions.h" + +@implementation WebMenuRunner + +- (id)initWithItems:(const std::vector<WebMenuItem>&)items { + if ((self = [super init])) { + menu_ = [[NSMenu alloc] initWithTitle:@""]; + [menu_ setAutoenablesItems:NO]; + menuItemWasChosen_ = NO; + index_ = -1; + for (int i = 0; i < static_cast<int>(items.size()); ++i) + [self addItem:items[i]]; + } + return self; +} + +- (void)dealloc { + [menu_ release]; + [super dealloc]; +} + +- (void)addItem:(const WebMenuItem&)item { + if (item.type == WebMenuItem::SEPARATOR) { + [menu_ addItem:[NSMenuItem separatorItem]]; + return; + } + + NSString* title = base::SysUTF16ToNSString(item.label); + NSMenuItem* menu_item = [menu_ addItemWithTitle:title + action:@selector(menuItemSelected:) + keyEquivalent:@""]; + [menu_item setEnabled:(item.enabled && item.type != WebMenuItem::GROUP)]; + [menu_item setTarget:self]; +} + +// Reflects the result of the user's interaction with the popup menu. If NO, the +// menu was dismissed without the user choosing an item, which can happen if the +// user clicked outside the menu region or hit the escape key. If YES, the user +// selected an item from the menu. +- (BOOL)menuItemWasChosen { + return menuItemWasChosen_; +} + +- (void)menuItemSelected:(id)sender { + menuItemWasChosen_ = YES; +} + +- (void)runMenuInView:(NSView*)view + withBounds:(NSRect)bounds + initialIndex:(int)index { + // Set up the button cell, converting to NSView coordinates. The menu is + // positioned such that the currently selected menu item appears over the + // popup button, which is the expected Mac popup menu behavior. + NSPopUpButtonCell* button = [[NSPopUpButtonCell alloc] initTextCell:@"" + pullsDown:NO]; + [button autorelease]; + [button setMenu:menu_]; + [button selectItemAtIndex:index]; + + // Display the menu, and set a flag if a menu item was chosen. + [button performClickWithFrame:bounds inView:view]; + + if ([self menuItemWasChosen]) + index_ = [button indexOfSelectedItem]; +} + +- (int)indexOfSelectedItem { + return index_; +} + +@end // WebMenuRunner + +// Helper function for manufacturing input events to send to WebKit. +NSEvent* CreateEventForMenuAction(BOOL item_chosen, int window_num, + int item_height, int selected_index, + NSRect menu_bounds, NSRect view_bounds) { + NSEvent* event = nil; + double event_time = (double)(AbsoluteToDuration(UpTime())) / 1000.0; + + if (item_chosen) { + // Construct a mouse up event to simulate the selection of an appropriate + // menu item. + NSPoint click_pos; + click_pos.x = menu_bounds.size.width / 2; + + // This is going to be hard to calculate since the button is painted by + // WebKit, the menu by Cocoa, and we have to translate the selected_item + // index to a coordinate that WebKit's PopupMenu expects which uses a + // different font *and* expects to draw the menu below the button like we do + // on Windows. + // The WebKit popup menu thinks it will draw just below the button, so + // create the click at the offset based on the selected item's index and + // account for the different coordinate system used by NSView. + int item_offset = selected_index * item_height + item_height / 2; + click_pos.y = view_bounds.size.height - item_offset; + event = [NSEvent mouseEventWithType:NSLeftMouseUp + location:click_pos + modifierFlags:0 + timestamp:event_time + windowNumber:window_num + context:nil + eventNumber:0 + clickCount:1 + pressure:1.0]; + } else { + // Fake an ESC key event (keyCode = 0x1B, from webinputevent_mac.mm) and + // forward that to WebKit. + NSPoint key_pos; + key_pos.x = 0; + key_pos.y = 0; + event = [NSEvent keyEventWithType:NSKeyUp + location:key_pos + modifierFlags:0 + timestamp:event_time + windowNumber:window_num + context:nil + characters:@"" + charactersIgnoringModifiers:@"" + isARepeat:NO + keyCode:0x1B]; + } + + return event; +} diff --git a/webkit/tools/test_shell/mac/test_webview_delegate.mm b/webkit/tools/test_shell/mac/test_webview_delegate.mm index 8df8d40..a1d1815 100755 --- a/webkit/tools/test_shell/mac/test_webview_delegate.mm +++ b/webkit/tools/test_shell/mac/test_webview_delegate.mm @@ -12,70 +12,11 @@ #include "webkit/glue/webview.h" #include "webkit/glue/plugins/plugin_list.h" #include "webkit/glue/plugins/webplugin_delegate_impl.h" +#include "webkit/glue/webmenurunner_mac.h" #include "webkit/tools/test_shell/test_shell.h" using WebKit::WebRect; -// MenuDelegate ---------------------------------------------------------------- -// A class for determining whether an item was selected from an HTML select -// control, or if the menu was dismissed without making a selection. If a menu -// item is selected, MenuDelegate is informed and sets a flag which can be -// queried after the menu has finished running. - -@interface MenuDelegate : NSObject { - @private - NSMenu* menu_; // Non-owning - BOOL menuItemWasChosen_; -} -- (id)initWithItems:(const std::vector<WebMenuItem>&)items - forMenu:(NSMenu*)menu; -- (void)addItem:(const WebMenuItem&)item; -- (BOOL)menuItemWasChosen; -- (void)menuItemSelected:(id)sender; -@end - -@implementation MenuDelegate - -- (id)initWithItems:(const std::vector<WebMenuItem>&)items - forMenu:(NSMenu*)menu { - if ((self = [super init])) { - menu_ = menu; - menuItemWasChosen_ = NO; - for (int i = 0; i < static_cast<int>(items.size()); ++i) - [self addItem:items[i]]; - } - return self; -} - -- (void)addItem:(const WebMenuItem&)item { - if (item.type == WebMenuItem::SEPARATOR) { - [menu_ addItem:[NSMenuItem separatorItem]]; - return; - } - - NSString* title = base::SysUTF16ToNSString(item.label); - NSMenuItem* menu_item = [menu_ addItemWithTitle:title - action:@selector(menuItemSelected:) - keyEquivalent:@""]; - [menu_item setEnabled:(item.enabled && item.type != WebMenuItem::GROUP)]; - [menu_item setTarget:self]; -} - -// Reflects the result of the user's interaction with the popup menu. If NO, the -// menu was dismissed without the user choosing an item, which can happen if the -// user clicked outside the menu region or hit the escape key. If YES, the user -// selected an item from the menu. -- (BOOL)menuItemWasChosen { - return menuItemWasChosen_; -} - -- (void)menuItemSelected:(id)sender { - menuItemWasChosen_ = YES; -} - -@end // MenuDelegate - - // WebViewDelegate ----------------------------------------------------------- TestWebViewDelegate::~TestWebViewDelegate() { @@ -130,82 +71,38 @@ void TestWebViewDelegate::ShowAsPopupWithItems( int item_height, int selected_index, const std::vector<WebMenuItem>& items) { - // Populate the menu. - NSMenu* menu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; - [menu setAutoenablesItems:NO]; - MenuDelegate* menu_delegate = - [[[MenuDelegate alloc] initWithItems:items forMenu:menu] autorelease]; - - // Set up the button cell, converting to NSView coordinates. The menu is - // positioned such that the currently selected menu item appears over the - // popup button, which is the expected Mac popup menu behavior. - NSPopUpButtonCell* button = [[NSPopUpButtonCell alloc] initTextCell:@"" - pullsDown:NO]; - [button autorelease]; - [button setMenu:menu]; - [button selectItemAtIndex:selected_index]; + // Set up the menu position. NSView* web_view = shell_->webViewWnd(); NSRect view_rect = [web_view bounds]; int y_offset = bounds.y + bounds.height; NSRect position = NSMakeRect(bounds.x, view_rect.size.height - y_offset, bounds.width, bounds.height); - // Display the menu, and set a flag to determine if something was chosen. If - // nothing was chosen (i.e., the user dismissed the popup by the "ESC" key or - // clicking outside popup's region), send a dismiss message to WebKit. - [button performClickWithFrame:position inView:shell_->webViewWnd()]; + // Display the menu. + WebMenuRunner* menu_runner = + [[[WebMenuRunner alloc] initWithItems:items] autorelease]; + + [menu_runner runMenuInView:shell_->webViewWnd() + withBounds:position + initialIndex:selected_index]; // Get the selected item and forward to WebKit. WebKit expects an input event // (mouse down, keyboard activity) for this, so we calculate the proper // position based on the selected index and provided bounds. WebWidgetHost* popup = shell_->popupHost(); - NSEvent* event = nil; - double event_time = (double)(AbsoluteToDuration(UpTime())) / 1000.0; int window_num = [shell_->mainWnd() windowNumber]; - if ([menu_delegate menuItemWasChosen]) { + NSEvent* event = CreateEventForMenuAction([menu_runner menuItemWasChosen], + window_num, item_height, + [menu_runner indexOfSelectedItem], + position, view_rect); + if ([menu_runner menuItemWasChosen]) { // Construct a mouse up event to simulate the selection of an appropriate // menu item. - NSPoint click_pos; - click_pos.x = position.size.width / 2; - - // This is going to be hard to calculate since the button is painted by - // WebKit, the menu by Cocoa, and we have to translate the selected_item - // index to a coordinate that WebKit's PopupMenu expects which uses a - // different font *and* expects to draw the menu below the button like we do - // on Windows. - // The WebKit popup menu thinks it will draw just below the button, so - // create the click at the offset based on the selected item's index and - // account for the different coordinate system used by NSView. - int item_offset = [button indexOfSelectedItem] * item_height + - item_height / 2; - click_pos.y = view_rect.size.height - item_offset; - event = [NSEvent mouseEventWithType:NSLeftMouseUp - location:click_pos - modifierFlags:0 - timestamp:event_time - windowNumber:window_num - context:nil - eventNumber:0 - clickCount:1 - pressure:1.0]; popup->MouseEvent(event); } else { // Fake an ESC key event (keyCode = 0x1B, from webinputevent_mac.mm) and // forward that to WebKit. - NSPoint key_pos; - key_pos.x = 0; - key_pos.y = 0; - event = [NSEvent keyEventWithType:NSKeyUp - location:key_pos - modifierFlags:0 - timestamp:event_time - windowNumber:window_num - context:nil - characters:@"" - charactersIgnoringModifiers:@"" - isARepeat:NO - keyCode:0x1B]; popup->KeyEvent(event); } } diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index 954fe6a..22d6ab7 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -4474,6 +4474,8 @@ 'glue/webmediaplayer_delegate.h', 'glue/webmediaplayer_impl.cc', 'glue/webmediaplayer_impl.h', + 'glue/webmenurunner_mac.h', + 'glue/webmenurunner_mac.mm', 'glue/webplugin.h', 'glue/webplugin_delegate.cc', 'glue/webplugin_delegate.h', |