diff options
author | paul@chromium.org <paul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-24 19:39:00 +0000 |
---|---|---|
committer | paul@chromium.org <paul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-24 19:39:00 +0000 |
commit | 5dee2add09d2e6f3a397f567a82791c37a747509 (patch) | |
tree | b0a6a05c3ec4cf275375235576a2d8ebfd46900c | |
parent | ef921826834b693e83ebe3a4ae6984b9b39b723b (diff) | |
download | chromium_src-5dee2add09d2e6f3a397f567a82791c37a747509.zip chromium_src-5dee2add09d2e6f3a397f567a82791c37a747509.tar.gz chromium_src-5dee2add09d2e6f3a397f567a82791c37a747509.tar.bz2 |
Clean up cocoa popup menu handling in test_shell.
The cocoa menu delegate, previously local to test_shell
on Mac, now has the added responsibility of running the
popup menu and processing the menu's actions. It is moved
into its own files in order to use this class as-is in
Chrome.
BUG=8389 (http://crbug.com/8389)
Review URL: http://codereview.chromium.org/92062
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14452 0039d316-1c4b-4281-b951-d872f2087c98
-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', |