From 1f7a4b4566b12aed664afa35ce3c537918e9bc99 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Sat, 9 Apr 2011 16:54:59 +0000 Subject: [PATCH] Mac: - Implement the WebExternalPopupMenu interface to fix select popup menu display. - Remove the kCFRunLoopBeforeTimers option from CFRunLoopObserverCreate to reduce CPU usage (issue #211). git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@218 5089003a-bbd8-11dd-ad1f-f1f9622dbc98 --- cef.gyp | 2 + libcef/browser_webview_delegate.h | 13 ++-- libcef/browser_webview_delegate_mac.mm | 86 +++++--------------------- libcef/browser_webview_delegate_win.cc | 7 ++- libcef/cef_process_ui_thread_mac.mm | 6 +- libcef/external_popup_menu_mac.h | 36 +++++++++++ libcef/external_popup_menu_mac.mm | 66 ++++++++++++++++++++ 7 files changed, 138 insertions(+), 78 deletions(-) create mode 100644 libcef/external_popup_menu_mac.h create mode 100644 libcef/external_popup_menu_mac.mm diff --git a/cef.gyp b/cef.gyp index e5a57fec7..252011d0c 100644 --- a/cef.gyp +++ b/cef.gyp @@ -686,6 +686,8 @@ 'libcef/browser_webview_mac.h', 'libcef/browser_webview_mac.mm', 'libcef/cef_process_ui_thread_mac.mm', + 'libcef/external_popup_menu_mac.h', + 'libcef/external_popup_menu_mac.mm', 'libcef/external_protocol_handler_mac.mm', 'libcef/webview_host_mac.mm', 'libcef/webwidget_host_mac.mm', diff --git a/libcef/browser_webview_delegate.h b/libcef/browser_webview_delegate.h index f45263efa..30b3b1906 100644 --- a/libcef/browser_webview_delegate.h +++ b/libcef/browser_webview_delegate.h @@ -29,6 +29,7 @@ #if defined(OS_MACOSX) #include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenuInfo.h" +#include "external_popup_menu_mac.h" #endif #if defined(OS_WIN) @@ -55,8 +56,9 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient, WebKit::WebFrame* creator, const WebKit::WebURLRequest& request, const WebKit::WebWindowFeatures& features, const WebKit::WebString& name); virtual WebKit::WebWidget* createPopupMenu(WebKit::WebPopupType popup_type); - virtual WebKit::WebWidget* createPopupMenu( - const WebKit::WebPopupMenuInfo& info); + virtual WebKit::WebExternalPopupMenu* createExternalPopupMenu( + const WebKit::WebPopupMenuInfo& info, + WebKit::WebExternalPopupMenuClient* client); virtual WebKit::WebStorageNamespace* createSessionStorageNamespace( unsigned quota); virtual void didAddMessageToConsole( @@ -247,7 +249,8 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient, CefBrowserImpl* GetBrowser() { return browser_; } #if defined(OS_MACOSX) - void SetPopupMenuInfo(const WebKit::WebPopupMenuInfo& info); + // Called after the external popup menu has been dismissed. + void ClosePopupMenu(); #endif // Called after dragging has finished. @@ -322,8 +325,8 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient, #endif #if defined(OS_MACOSX) - scoped_ptr popup_menu_info_; - WebKit::WebRect popup_bounds_; + // The external popup menu for the currently showing select popup. + scoped_ptr external_popup_menu_; #endif // true if we want to enable smart insert/delete. diff --git a/libcef/browser_webview_delegate_mac.mm b/libcef/browser_webview_delegate_mac.mm index 605b7e1ec..deda7ccd1 100644 --- a/libcef/browser_webview_delegate_mac.mm +++ b/libcef/browser_webview_delegate_mac.mm @@ -17,19 +17,29 @@ #include "webkit/glue/webmenurunner_mac.h" using WebKit::WebCursorInfo; +using WebKit::WebExternalPopupMenu; +using WebKit::WebExternalPopupMenuClient; using WebKit::WebNavigationPolicy; -using WebKit::WebPopupMenu; using WebKit::WebPopupMenuInfo; using WebKit::WebRect; using WebKit::WebWidget; // WebViewClient -------------------------------------------------------------- -WebWidget* BrowserWebViewDelegate::createPopupMenu( - const WebPopupMenuInfo& info) { - WebWidget* webwidget = browser_->UIT_CreatePopupWidget(); - browser_->UIT_GetPopupDelegate()->SetPopupMenuInfo(info); - return webwidget; +WebExternalPopupMenu* BrowserWebViewDelegate::createExternalPopupMenu( + const WebPopupMenuInfo& info, + WebExternalPopupMenuClient* client) { + DCHECK(!external_popup_menu_.get()); + external_popup_menu_.reset(new ExternalPopupMenu(this, info, client)); + return external_popup_menu_.get(); +} + +void BrowserWebViewDelegate::ClosePopupMenu() { + if (external_popup_menu_ == NULL) { + NOTREACHED(); + return; + } + external_popup_menu_.reset(); } void BrowserWebViewDelegate::showContextMenu( @@ -40,64 +50,6 @@ void BrowserWebViewDelegate::showContextMenu( // WebWidgetClient ------------------------------------------------------------ void BrowserWebViewDelegate::show(WebNavigationPolicy policy) { - if (!popup_menu_info_.get()) - return; - if (this != browser_->UIT_GetPopupDelegate()) - return; - // Display a HTML select menu. - - std::vector items; - for (size_t i = 0; i < popup_menu_info_->items.size(); ++i) - items.push_back(popup_menu_info_->items[i]); - - int item_height = popup_menu_info_->itemHeight; - double font_size = popup_menu_info_->itemFontSize; - int selected_index = popup_menu_info_->selectedIndex; - bool right_aligned = popup_menu_info_->rightAligned; - popup_menu_info_.reset(); // No longer needed. - - const WebRect& bounds = popup_bounds_; - - // Set up the menu position. - NSView* web_view = browser_->UIT_GetWebViewWndHandle(); - 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. - scoped_nsobject menu_runner; - menu_runner.reset([[WebMenuRunner alloc] initWithItems:items - fontSize:font_size - rightAligned:right_aligned]); - - [menu_runner runMenuInView:browser_->UIT_GetWebViewWndHandle() - 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 = browser_->UIT_GetPopupHost(); - NSWindow* window = [browser_->UIT_GetMainWndHandle() window]; - int window_num = [window windowNumber]; - NSEvent* event = - webkit_glue::EventWithMenuAction([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. - popup->MouseEvent(event); - } else { - // Fake an ESC key event (keyCode = 0x1B, from webinputevent_mac.mm) and - // forward that to WebKit. - popup->KeyEvent(event); - } - - browser_->UIT_ClosePopupWidget(); } void BrowserWebViewDelegate::didChangeCursor(const WebCursorInfo& cursor_info) { @@ -117,8 +69,6 @@ WebRect BrowserWebViewDelegate::windowRect() { void BrowserWebViewDelegate::setWindowRect(const WebRect& rect) { if (this == browser_->UIT_GetWebViewDelegate()) { // TODO(port): Set the window rectangle. - } else if (this == browser_->UIT_GetPopupDelegate()) { - popup_bounds_ = rect; // The initial position of the popup. } } @@ -189,10 +139,6 @@ void BrowserWebViewDelegate::DidMovePlugin( // Protected methods ---------------------------------------------------------- -void BrowserWebViewDelegate::SetPopupMenuInfo(const WebPopupMenuInfo& info) { - popup_menu_info_.reset(new WebPopupMenuInfo(info)); -} - void BrowserWebViewDelegate::ShowJavaScriptAlert( WebKit::WebFrame* webframe, const CefString& message) { std::string messageStr(message); diff --git a/libcef/browser_webview_delegate_win.cc b/libcef/browser_webview_delegate_win.cc index 4fa001873..194775f8f 100644 --- a/libcef/browser_webview_delegate_win.cc +++ b/libcef/browser_webview_delegate_win.cc @@ -38,6 +38,8 @@ using webkit::npapi::WebPluginDelegateImpl; using WebKit::WebContextMenuData; using WebKit::WebCursorInfo; +using WebKit::WebExternalPopupMenu; +using WebKit::WebExternalPopupMenuClient; using WebKit::WebFrame; using WebKit::WebNavigationPolicy; using WebKit::WebPopupMenuInfo; @@ -48,8 +50,9 @@ static const wchar_t kPluginWindowClassName[] = L"WebPluginHost"; // WebViewClient -------------------------------------------------------------- -WebWidget* BrowserWebViewDelegate::createPopupMenu( - const WebPopupMenuInfo& info) { +WebExternalPopupMenu* BrowserWebViewDelegate::createExternalPopupMenu( + const WebPopupMenuInfo& info, + WebExternalPopupMenuClient* client) { NOTREACHED(); return NULL; } diff --git a/libcef/cef_process_ui_thread_mac.mm b/libcef/cef_process_ui_thread_mac.mm index 9e9ead7de..831e44b7c 100644 --- a/libcef/cef_process_ui_thread_mac.mm +++ b/libcef/cef_process_ui_thread_mac.mm @@ -7,6 +7,7 @@ #include "cef_process_ui_thread.h" #include "browser_webkit_glue.h" #include "base/message_pump_mac.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "third_party/WebKit/Source/WebKit/mac/WebCoreSupport/WebSystemInterface.h" // CrAppProtocol implementation. @@ -53,7 +54,7 @@ void CefProcessUIThread::PlatformInit() { // Register the run loop observer. CFRunLoopObserverRef observer = CFRunLoopObserverCreate(NULL, - kCFRunLoopBeforeTimers | kCFRunLoopBeforeWaiting, + kCFRunLoopBeforeWaiting, YES, /* repeat */ 0, &RunLoopObserver, @@ -64,6 +65,9 @@ void CefProcessUIThread::PlatformInit() { } webkit_glue::InitializeDataPak(); + + // On Mac, the select popup menus are rendered by the browser. + WebKit::WebView::setUseExternalPopupMenus(true); } void CefProcessUIThread::PlatformCleanUp() { diff --git a/libcef/external_popup_menu_mac.h b/libcef/external_popup_menu_mac.h new file mode 100644 index 000000000..721f0ac32 --- /dev/null +++ b/libcef/external_popup_menu_mac.h @@ -0,0 +1,36 @@ +// Copyright (c) 2011 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2010 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 _EXTERNAL_POPUP_MENU_MAC_H +#define _EXTERNAL_POPUP_MENU_MAC_H + +#include "base/basictypes.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebExternalPopupMenu.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenuInfo.h" + +class BrowserWebViewDelegate; +namespace WebKit { +class WebExternalPopupMenuClient; +} + +class ExternalPopupMenu : public WebKit::WebExternalPopupMenu { + public: + ExternalPopupMenu(BrowserWebViewDelegate* delegate, + const WebKit::WebPopupMenuInfo& popup_menu_info, + WebKit::WebExternalPopupMenuClient* popup_menu_client); + + // WebKit::WebExternalPopupMenu implementation: + virtual void show(const WebKit::WebRect& bounds); + virtual void close(); + + private: + BrowserWebViewDelegate* delegate_; + WebKit::WebPopupMenuInfo popup_menu_info_; + WebKit::WebExternalPopupMenuClient* popup_menu_client_; + + DISALLOW_COPY_AND_ASSIGN(ExternalPopupMenu); +}; + +#endif // _EXTERNAL_POPUP_MENU_MAC_H diff --git a/libcef/external_popup_menu_mac.mm b/libcef/external_popup_menu_mac.mm new file mode 100644 index 000000000..5f1c5987c --- /dev/null +++ b/libcef/external_popup_menu_mac.mm @@ -0,0 +1,66 @@ +// Copyright (c) 2011 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2010 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 "external_popup_menu_mac.h" +#include "browser_impl.h" + +#include "content/common/view_messages.h" +#include "content/renderer/render_view.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebExternalPopupMenuClient.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenuInfo.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h" +#include "webkit/glue/webmenurunner_mac.h" + +ExternalPopupMenu::ExternalPopupMenu( + BrowserWebViewDelegate* delegate, + const WebKit::WebPopupMenuInfo& popup_menu_info, + WebKit::WebExternalPopupMenuClient* popup_menu_client) + : delegate_(delegate), + popup_menu_info_(popup_menu_info), + popup_menu_client_(popup_menu_client) { +} + +void ExternalPopupMenu::show(const WebKit::WebRect& bounds) { + // Display a HTML select menu. + + std::vector items; + for (size_t i = 0; i < popup_menu_info_.items.size(); ++i) + items.push_back(popup_menu_info_.items[i]); + + double font_size = popup_menu_info_.itemFontSize; + int selected_index = popup_menu_info_.selectedIndex; + bool right_aligned = popup_menu_info_.rightAligned; + + CefBrowserImpl* browser = delegate_->GetBrowser(); + + // Set up the menu position. + NSView* web_view = browser->UIT_GetWebViewWndHandle(); + 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. + scoped_nsobject menu_runner; + menu_runner.reset([[WebMenuRunner alloc] initWithItems:items + fontSize:font_size + rightAligned:right_aligned]); + + [menu_runner runMenuInView:browser->UIT_GetWebViewWndHandle() + withBounds:position + initialIndex:selected_index]; + + if ([menu_runner menuItemWasChosen]) + popup_menu_client_->didAcceptIndex([menu_runner indexOfSelectedItem]); + else + popup_menu_client_->didCancel(); + + delegate_->ClosePopupMenu(); +} + +void ExternalPopupMenu::close() { + popup_menu_client_ = NULL; + delegate_ = NULL; +}