diff options
author | paul@chromium.org <paul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-24 21:12:11 +0000 |
---|---|---|
committer | paul@chromium.org <paul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-24 21:12:11 +0000 |
commit | e344a05a48730f00fe670e6ceb00afdc8b1be414 (patch) | |
tree | 7d0ef6750ff61630da9eb1c5e52091711e4a950d | |
parent | 35e6071b402c63474795843629533a2444f8e8ad (diff) | |
download | chromium_src-e344a05a48730f00fe670e6ceb00afdc8b1be414.zip chromium_src-e344a05a48730f00fe670e6ceb00afdc8b1be414.tar.gz chromium_src-e344a05a48730f00fe670e6ceb00afdc8b1be414.tar.bz2 |
Implement HTML selects as native Cocoa controls for Chrome.
BUG=8389 (http://crbug.com/8389)
Review URL: http://codereview.chromium.org/57032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14471 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.cc | 18 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host.h | 1 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view.h | 13 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view_mac.h | 9 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view_mac.mm | 40 | ||||
-rw-r--r-- | chrome/browser/renderer_host/test_render_view_host.h | 6 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_view_mac.mm | 3 | ||||
-rw-r--r-- | chrome/common/render_messages.h | 105 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 5 | ||||
-rw-r--r-- | chrome/renderer/render_widget.cc | 11 |
10 files changed, 205 insertions, 6 deletions
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 64fb609..9e07de7 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -114,6 +114,7 @@ IPC_DEFINE_MESSAGE_MAP(RenderWidgetHost) IPC_MESSAGE_HANDLER(ViewHostMsg_Blur, OnMsgBlur) IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnMsgSetCursor) IPC_MESSAGE_HANDLER(ViewHostMsg_ImeUpdateStatus, OnMsgImeUpdateStatus) + IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_ShowPopup, OnMsgShowPopup(msg)) IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() @@ -662,6 +663,23 @@ void RenderWidgetHost::OnMsgImeUpdateStatus(int control, } } +void RenderWidgetHost::OnMsgShowPopup(const IPC::Message& message) { +#if defined(OS_MACOSX) + void* iter = NULL; + ViewHostMsg_ShowPopup_Params validated_params; + if (!IPC::ParamTraits<ViewHostMsg_ShowPopup_Params>::Read(&message, &iter, + &validated_params)) + return; + + view_->ShowPopupWithItems(validated_params.bounds, + validated_params.item_height, + validated_params.selected_item, + validated_params.popup_items); +#else // OS_WIN || OS_LINUX + NOTREACHED(); +#endif +} + void RenderWidgetHost::PaintBackingStoreRect(TransportDIB* bitmap, const gfx::Rect& bitmap_rect, const gfx::Size& view_size) { diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index ad81ad8..0e93a84 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -318,6 +318,7 @@ class RenderWidgetHost : public IPC::Channel::Listener { // Using int instead of ViewHostMsg_ImeControl for control's type to avoid // having to bring in render_messages.h in a header file. void OnMsgImeUpdateStatus(int control, const gfx::Rect& caret_rect); + void OnMsgShowPopup(const IPC::Message& message); // Paints the given bitmap to the current backing store at the given location. void PaintBackingStoreRect(TransportDIB* dib, diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h index beec90e..7053150 100644 --- a/chrome/browser/renderer_host/render_widget_host_view.h +++ b/chrome/browser/renderer_host/render_widget_host_view.h @@ -7,8 +7,9 @@ #include "base/gfx/native_widget_types.h" #include "base/shared_memory.h" -#include "webkit/glue/webplugin.h" #include "skia/include/SkBitmap.h" +#include "webkit/glue/webplugin.h" +#include "webkit/glue/webwidget_delegate.h" namespace gfx { class Rect; @@ -136,6 +137,14 @@ class RenderWidgetHostView { // Allocate a backing store for this view virtual BackingStore* AllocBackingStore(const gfx::Size& size) = 0; +#if defined(OS_MACOSX) + // Display a native control popup menu for WebKit. + virtual void ShowPopupWithItems(gfx::Rect bounds, + int item_height, + int selected_item, + const std::vector<WebMenuItem>& items) = 0; +#endif + void set_activatable(bool activatable) { activatable_ = activatable; } @@ -151,7 +160,7 @@ class RenderWidgetHostView { protected: // Interface class only, do not construct. RenderWidgetHostView() : activatable_(true) {} - + // Whether the window can be activated. Autocomplete popup windows for example // cannot be activated. Default is true. bool activatable_; diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h index 4c1e266..e04b822 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -82,9 +82,15 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { virtual void Destroy(); virtual void SetTooltipText(const std::wstring& tooltip_text); virtual BackingStore* AllocBackingStore(const gfx::Size& size); + virtual void ShowPopupWithItems(gfx::Rect bounds, + int item_height, + int selected_item, + const std::vector<WebMenuItem>& items); void KillSelf(); + void set_parent_view(BaseView* parent_view) { parent_view_ = parent_view; } + // These member variables should be private, but the associated ObjC class // needs access to them and can't be made a friend. @@ -131,6 +137,9 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { // Factory used to safely scope delayed calls to ShutdownHost(). ScopedRunnableMethodFactory<RenderWidgetHostViewMac> shutdown_factory_; + // Used for positioning a popup menu. + BaseView* parent_view_; + DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMac); }; diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm index bfe0bfc..9e6b88f 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -14,6 +14,7 @@ #include "skia/ext/platform_canvas.h" #include "third_party/WebKit/WebKit/chromium/public/mac/WebInputEventFactory.h" #include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" +#include "webkit/glue/webmenurunner_mac.h" using WebKit::WebInputEventFactory; using WebKit::WebMouseEvent; @@ -46,7 +47,8 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget) about_to_validate_and_paint_(false), is_loading_(false), is_hidden_(false), - shutdown_factory_(this) { + shutdown_factory_(this), + parent_view_(NULL) { cocoa_view_ = [[[RenderWidgetHostViewCocoa alloc] initWithRenderWidgetHostViewMac:this] autorelease]; render_widget_host_->set_view(this); @@ -267,6 +269,42 @@ BackingStore* RenderWidgetHostViewMac::AllocBackingStore( return new BackingStore(size); } +// Display a popup menu for WebKit using Cocoa widgets. +void RenderWidgetHostViewMac::ShowPopupWithItems( + gfx::Rect bounds, + int item_height, + int selected_item, + const std::vector<WebMenuItem>& items) { + NSRect view_rect = [cocoa_view_ bounds]; + NSRect position = NSMakeRect(bounds.x(), bounds.y() - bounds.height(), + bounds.width(), bounds.height()); + + // Display the menu. + WebMenuRunner* menu_runner = + [[[WebMenuRunner alloc] initWithItems:items] autorelease]; + + [menu_runner runMenuInView:parent_view_ + withBounds:position + initialIndex:selected_item]; + + int window_num = [[parent_view_ window] windowNumber]; + NSEvent* event = CreateEventForMenuAction([menu_runner menuItemWasChosen], + window_num, item_height, + [menu_runner indexOfSelectedItem], + position, view_rect); + + if ([menu_runner menuItemWasChosen]) { + // Simulate a menu selection event. + const WebMouseEvent& mouse_event = + WebInputEventFactory::mouseEvent(event, cocoa_view_); + render_widget_host_->ForwardMouseEvent(mouse_event); + } else { + // Simulate a menu dismiss event. + NativeWebKeyboardEvent keyboard_event(event); + render_widget_host_->ForwardKeyboardEvent(keyboard_event); + } +} + void RenderWidgetHostViewMac::KillSelf() { if (shutdown_factory_.empty()) { [cocoa_view_ setHidden:YES]; diff --git a/chrome/browser/renderer_host/test_render_view_host.h b/chrome/browser/renderer_host/test_render_view_host.h index 5f67ec1..0e93526 100644 --- a/chrome/browser/renderer_host/test_render_view_host.h +++ b/chrome/browser/renderer_host/test_render_view_host.h @@ -72,6 +72,12 @@ class TestRenderWidgetHostView : public RenderWidgetHostView { virtual void PrepareToDestroy() {} virtual void SetTooltipText(const std::wstring& tooltip_text) {} virtual BackingStore* AllocBackingStore(const gfx::Size& size); +#if defined(OS_MACOSX) + virtual void ShowPopupWithItems(gfx::Rect bounds, + int item_height, + int selected_item, + const std::vector<WebMenuItem>& items) {} +#endif bool is_showing() const { return is_showing_; } diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.mm b/chrome/browser/tab_contents/tab_contents_view_mac.mm index 2f08d70..3d894c8 100644 --- a/chrome/browser/tab_contents/tab_contents_view_mac.mm +++ b/chrome/browser/tab_contents/tab_contents_view_mac.mm @@ -148,6 +148,9 @@ RenderWidgetHostView* TabContentsViewMac::CreateNewWidgetInternal( static_cast<RenderWidgetHostViewMac*>(widget_view); [widget_view_mac->native_view() retain]; + // |widget_view_mac| needs to know how to position itself in our view. + widget_view_mac->set_parent_view(cocoa_view_); + return widget_view; } diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index f711cf6..e0c6004 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -374,6 +374,23 @@ struct ViewHostMsg_Audio_CreateStream { size_t packet_size; }; +// This message is used for supporting popup menus on Mac OS X using native +// Cocoa controls. The renderer sends us this message which we use to populate +// the popup menu. +struct ViewHostMsg_ShowPopup_Params { + // Position on the screen. + gfx::Rect bounds; + + // The height of each item in the menu. + int item_height; + + // The currently selected (displayed) item in the menu. + int selected_item; + + // The entire list of items in the popup menu. + std::vector<WebMenuItem> popup_items; +}; + namespace IPC { template <> @@ -1832,6 +1849,94 @@ struct ParamTraits<WebAppCacheContext::ContextType> { } }; +template<> +struct ParamTraits<WebMenuItem::Type> { + typedef WebMenuItem::Type param_type; + static void Write(Message* m, const param_type& p) { + m->WriteInt(p); + } + static bool Read(const Message* m, void** iter, param_type* p) { + int type; + if (!m->ReadInt(iter, &type)) + return false; + *p = static_cast<WebMenuItem::Type>(type); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring type; + switch (p) { + case WebMenuItem::OPTION: + type = L"OPTION"; + break; + case WebMenuItem::GROUP: + type = L"GROUP"; + break; + case WebMenuItem::SEPARATOR: + type = L"SEPARATOR"; + break; + default: + type = L"UNKNOWN"; + break; + } + LogParam(type, l); + } +}; + +template<> +struct ParamTraits<WebMenuItem> { + typedef WebMenuItem param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.label); + WriteParam(m, p.type); + WriteParam(m, p.enabled); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->label) && + ReadParam(m, iter, &p->type) && + ReadParam(m, iter, &p->enabled); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.label, l); + l->append(L", "); + LogParam(p.type, l); + l->append(L", "); + LogParam(p.enabled, l); + l->append(L")"); + } +}; + +// Traits for ViewHostMsg_ShowPopup_Params. +template <> +struct ParamTraits<ViewHostMsg_ShowPopup_Params> { + typedef ViewHostMsg_ShowPopup_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.bounds); + WriteParam(m, p.item_height); + WriteParam(m, p.selected_item); + WriteParam(m, p.popup_items); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->bounds) && + ReadParam(m, iter, &p->item_height) && + ReadParam(m, iter, &p->selected_item) && + ReadParam(m, iter, &p->popup_items); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.bounds, l); + l->append(L", "); + LogParam(p.item_height, l); + l->append(L", "); + LogParam(p.selected_item, l); + l->append(L", "); + LogParam(p.popup_items, l); + l->append(L")"); + } +}; + } // namespace IPC diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index fe0161e..ae14335 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1337,4 +1337,9 @@ IPC_BEGIN_MESSAGES(ViewHost) IPC_MESSAGE_CONTROL2(ViewHostMsg_ExtensionPostMessage, int /* port_id */, std::string /* message */) + + // Message to show a popup menu using native cocoa controls (Mac only). + IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowPopup, + ViewHostMsg_ShowPopup_Params) + IPC_END_MESSAGES(ViewHost) diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc index 23f27da..105ce11 100644 --- a/chrome/renderer/render_widget.cc +++ b/chrome/renderer/render_widget.cc @@ -313,7 +313,7 @@ void RenderWidget::PaintRect(const gfx::Rect& rect, // If there is a custom background, tile it. if (!background_.empty()) { canvas->save(); - + SkIRect clipRect = { rect.x(), rect.y(), rect.right(), rect.bottom() }; canvas->setClipRegion(SkRegion(clipRect)); @@ -589,8 +589,13 @@ void RenderWidget::ShowAsPopupWithItems(WebWidget* webwidget, int item_height, int selected_index, const std::vector<WebMenuItem>& items) { - // TODO(paulg): Implement this for Mac HTML select menus in Chromium, bug - // number: http://crbug.com/8389 + ViewHostMsg_ShowPopup_Params params; + params.bounds = bounds; + params.item_height = item_height; + params.selected_item = selected_index; + params.popup_items = items; + + Send(new ViewHostMsg_ShowPopup(routing_id_, params)); } void RenderWidget::Focus(WebWidget* webwidget) { |