diff options
author | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-05 04:00:59 +0000 |
---|---|---|
committer | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-05 04:00:59 +0000 |
commit | 7443494b88d2c04f3c07ebf98f0e6d68478eed7d (patch) | |
tree | 9211568b7d60a93dc8bf03a57a725dc8c8d967b7 /views | |
parent | 6f7e1d63f9c97c7f8f11af86f78f80934064a9a9 (diff) | |
download | chromium_src-7443494b88d2c04f3c07ebf98f0e6d68478eed7d.zip chromium_src-7443494b88d2c04f3c07ebf98f0e6d68478eed7d.tar.gz chromium_src-7443494b88d2c04f3c07ebf98f0e6d68478eed7d.tar.bz2 |
A non-GTK version of menus for touchui.
For the menus to work correctly, the X messge pump also needs updating to allow
nested event dispatching.
BUG=None
TEST=On a touchui build, non-GTK context menus in web-pages should work correctly.
Review URL: http://codereview.chromium.org/5110011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@68309 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/controls/menu/menu_controller.cc | 10 | ||||
-rw-r--r-- | views/controls/menu/menu_controller.h | 2 | ||||
-rw-r--r-- | views/controls/menu/menu_item_view.cc | 38 | ||||
-rw-r--r-- | views/controls/menu/menu_item_view.h | 11 | ||||
-rw-r--r-- | views/controls/menu/native_menu_x.cc | 162 | ||||
-rw-r--r-- | views/controls/menu/native_menu_x.h | 56 | ||||
-rw-r--r-- | views/controls/menu/nested_dispatcher_gtk.cc | 5 | ||||
-rw-r--r-- | views/controls/menu/nested_dispatcher_gtk.h | 3 | ||||
-rw-r--r-- | views/focus/accelerator_handler.h | 2 | ||||
-rw-r--r-- | views/focus/accelerator_handler_touch.cc | 22 | ||||
-rw-r--r-- | views/views.gyp | 5 |
11 files changed, 296 insertions, 20 deletions
diff --git a/views/controls/menu/menu_controller.cc b/views/controls/menu/menu_controller.cc index e0701a2..b324d64 100644 --- a/views/controls/menu/menu_controller.cc +++ b/views/controls/menu/menu_controller.cc @@ -860,8 +860,14 @@ bool MenuController::Dispatch(GdkEvent* event) { } #if defined(TOUCH_UI) -bool MenuController::Dispatch(XEvent* xev) { - return DispatchXEvent(xev); +base::MessagePumpGlibXDispatcher::DispatchStatus MenuController::Dispatch( + XEvent* xev) { + if (!DispatchXEvent(xev)) + return EVENT_IGNORED; + + return exit_type_ != EXIT_NONE ? + base::MessagePumpGlibXDispatcher::EVENT_QUIT : + base::MessagePumpGlibXDispatcher::EVENT_PROCESSED; } #endif diff --git a/views/controls/menu/menu_controller.h b/views/controls/menu/menu_controller.h index 539c2ee..234529e 100644 --- a/views/controls/menu/menu_controller.h +++ b/views/controls/menu/menu_controller.h @@ -193,7 +193,7 @@ class MenuController : public MessageLoopForUI::Dispatcher { #endif #if defined(TOUCH_UI) - virtual bool Dispatch(XEvent* xevent); + virtual MessagePumpGlibXDispatcher::DispatchStatus Dispatch(XEvent* xevent); #endif // Key processing. The return value of this is returned from Dispatch. diff --git a/views/controls/menu/menu_item_view.cc b/views/controls/menu/menu_item_view.cc index cdc0421..e0bd038 100644 --- a/views/controls/menu/menu_item_view.cc +++ b/views/controls/menu/menu_item_view.cc @@ -5,6 +5,7 @@ #include "views/controls/menu/menu_item_view.h" #include "app/l10n_util.h" +#include "app/menus/menu_model.h" #include "base/utf_string_conversions.h" #include "gfx/canvas.h" #include "grit/app_strings.h" @@ -237,6 +238,43 @@ void MenuItemView::Cancel() { } } +MenuItemView* MenuItemView::AppendMenuItemFromModel(menus::MenuModel* model, + int index, + int id) { + SkBitmap icon; + std::wstring label; + MenuItemView::Type type; + menus::MenuModel::ItemType menu_type = model->GetTypeAt(index); + switch (menu_type) { + case menus::MenuModel::TYPE_COMMAND: + model->GetIconAt(index, &icon); + type = MenuItemView::NORMAL; + label = UTF16ToWide(model->GetLabelAt(index)); + break; + case menus::MenuModel::TYPE_CHECK: + type = MenuItemView::CHECKBOX; + label = UTF16ToWide(model->GetLabelAt(index)); + break; + case menus::MenuModel::TYPE_RADIO: + type = MenuItemView::RADIO; + label = UTF16ToWide(model->GetLabelAt(index)); + break; + case menus::MenuModel::TYPE_SEPARATOR: + type = MenuItemView::SEPARATOR; + break; + case menus::MenuModel::TYPE_SUBMENU: + type = MenuItemView::SUBMENU; + label = UTF16ToWide(model->GetLabelAt(index)); + break; + default: + NOTREACHED(); + type = MenuItemView::NORMAL; + break; + } + + return AppendMenuItemImpl(id, label, icon, type); +} + MenuItemView* MenuItemView::AppendMenuItemImpl(int item_id, const std::wstring& label, const SkBitmap& icon, diff --git a/views/controls/menu/menu_item_view.h b/views/controls/menu/menu_item_view.h index 66540b7..0a19870 100644 --- a/views/controls/menu/menu_item_view.h +++ b/views/controls/menu/menu_item_view.h @@ -19,6 +19,10 @@ #include "gfx/native_theme_win.h" #endif +namespace menus { +class MenuModel; +} + namespace views { class MenuButton; @@ -175,6 +179,13 @@ class MenuItemView : public View { AppendMenuItemImpl(item_id, label, icon, NORMAL); } + // Creates a menu item for the specified entry in the model and appends it as + // a child. |index| should be offset by GetFirstItemIndex() before calling + // this function. + MenuItemView* AppendMenuItemFromModel(menus::MenuModel* model, + int index, + int id); + // All the AppendXXX methods funnel into this. MenuItemView* AppendMenuItemImpl(int item_id, const std::wstring& label, diff --git a/views/controls/menu/native_menu_x.cc b/views/controls/menu/native_menu_x.cc new file mode 100644 index 0000000..5653def --- /dev/null +++ b/views/controls/menu/native_menu_x.cc @@ -0,0 +1,162 @@ +// 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 "views/controls/menu/native_menu_x.h" + +#include "base/logging.h" +#include "base/utf_string_conversions.h" +#include "gfx/canvas_skia.h" +#include "gfx/skia_util.h" +#include "views/controls/menu/menu_2.h" +#include "views/controls/menu/submenu_view.h" + +namespace views { + +NativeMenuX::NativeMenuX(Menu2* menu) + : model_(menu->model()), + ALLOW_THIS_IN_INITIALIZER_LIST(root_(new MenuItemView(this))) { +} + +NativeMenuX::~NativeMenuX() { +} + +// MenuWrapper implementation: +void NativeMenuX::RunMenuAt(const gfx::Point& point, int alignment) { + UpdateStates(); + root_->RunMenuAt(NULL, NULL, gfx::Rect(point, gfx::Size()), + alignment == Menu2::ALIGN_TOPLEFT ? MenuItemView::TOPLEFT : + MenuItemView::TOPRIGHT, true); +} + +void NativeMenuX::CancelMenu() { + NOTIMPLEMENTED(); +} + +void NativeMenuX::Rebuild() { + if (SubmenuView* submenu = root_->GetSubmenu()) { + submenu->RemoveAllChildViews(true); + } + AddMenuItemsFromModel(root_.get(), model_); +} + +void NativeMenuX::UpdateStates() { + SubmenuView* submenu = root_->CreateSubmenu(); + UpdateMenuFromModel(submenu, model_); +} + +gfx::NativeMenu NativeMenuX::GetNativeMenu() const { + NOTIMPLEMENTED(); + return NULL; +} + +MenuWrapper::MenuAction NativeMenuX::GetMenuAction() const { + NOTIMPLEMENTED(); + return MENU_ACTION_NONE; +} + +void NativeMenuX::AddMenuListener(MenuListener* listener) { + NOTIMPLEMENTED(); +} + +void NativeMenuX::RemoveMenuListener(MenuListener* listener) { + NOTIMPLEMENTED(); +} + +void NativeMenuX::SetMinimumWidth(int width) { + NOTIMPLEMENTED(); +} + +// MenuDelegate implementation + +bool NativeMenuX::IsItemChecked(int cmd) const { + int index; + menus::MenuModel* model = model_; + if (!menus::MenuModel::GetModelAndIndexForCommandId(cmd, &model, &index)) + return false; + return model->IsItemCheckedAt(index); +} + +bool NativeMenuX::IsCommandEnabled(int cmd) const { + int index; + menus::MenuModel* model = model_; + if (!menus::MenuModel::GetModelAndIndexForCommandId(cmd, &model, &index)) + return false; + return model->IsEnabledAt(index); +} + +void NativeMenuX::ExecuteCommand(int cmd) { + int index; + menus::MenuModel* model = model_; + if (!menus::MenuModel::GetModelAndIndexForCommandId(cmd, &model, &index)) + return; + model->ActivatedAt(index); +} + +bool NativeMenuX::GetAccelerator(int id, views::Accelerator* accelerator) { + int index; + menus::MenuModel* model = model_; + if (!menus::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) + return false; + + menus::Accelerator menu_accelerator; + if (!model->GetAcceleratorAt(index, &menu_accelerator)) + return false; + + *accelerator = views::Accelerator(menu_accelerator.GetKeyCode(), + menu_accelerator.modifiers()); + return true; +} + +// private +void NativeMenuX::AddMenuItemsFromModel(MenuItemView* parent, + menus::MenuModel* model) { + for (int i = 0; i < model->GetItemCount(); ++i) { + int index = i + model->GetFirstItemIndex(NULL); + MenuItemView* child = parent->AppendMenuItemFromModel(model, index, + model->GetCommandIdAt(index)); + + if (child && child->GetType() == MenuItemView::SUBMENU) { + AddMenuItemsFromModel(child, model->GetSubmenuModelAt(index)); + } + } +} + +void NativeMenuX::UpdateMenuFromModel(SubmenuView* menu, + menus::MenuModel* model) { + for (int i = 0, sep = 0; i < model->GetItemCount(); ++i) { + int index = i + model->GetFirstItemIndex(NULL); + if (model->GetTypeAt(index) == menus::MenuModel::TYPE_SEPARATOR) { + ++sep; + continue; + } + + // The submenu excludes the separators when counting the menu-items + // in it. So exclude the number of separators to get the correct index. + MenuItemView* mitem = menu->GetMenuItemAt(index - sep); + mitem->SetVisible(model->IsVisibleAt(index)); + mitem->SetEnabled(model->IsEnabledAt(index)); + if (model->IsLabelDynamicAt(index)) { + mitem->SetTitle(UTF16ToWide(model->GetLabelAt(index))); + } + + SkBitmap icon; + if (model->GetIconAt(index, &icon)) { + mitem->SetIcon(icon); + } + + if (model->GetTypeAt(index) == menus::MenuModel::TYPE_SUBMENU) { + DCHECK(mitem->HasSubmenu()); + UpdateMenuFromModel(mitem->GetSubmenu(), model->GetSubmenuModelAt(index)); + } + } +} + +// MenuWrapper, public: + +// static +MenuWrapper* MenuWrapper::CreateWrapper(Menu2* menu) { + return new NativeMenuX(menu); +} + +} // namespace views diff --git a/views/controls/menu/native_menu_x.h b/views/controls/menu/native_menu_x.h new file mode 100644 index 0000000..b13f33e --- /dev/null +++ b/views/controls/menu/native_menu_x.h @@ -0,0 +1,56 @@ +// 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 VIEWS_CONTROLS_MENU_NATIVE_MENU_X_H_ +#define VIEWS_CONTROLS_MENU_NATIVE_MENU_X_H_ +#pragma once + +#include "views/controls/menu/menu_delegate.h" +#include "views/controls/menu/menu_item_view.h" +#include "views/controls/menu/menu_wrapper.h" + +namespace menus { +class MenuModel; +} + +namespace views { + +// A non-GTK implementation of MenuWrapper, used currently for touchui. +class NativeMenuX : public MenuWrapper, + public MenuDelegate { + public: + explicit NativeMenuX(Menu2* menu); + virtual ~NativeMenuX(); + + // Overridden from MenuWrapper: + virtual void RunMenuAt(const gfx::Point& point, int alignment); + virtual void CancelMenu(); + virtual void Rebuild(); + virtual void UpdateStates(); + virtual gfx::NativeMenu GetNativeMenu() const; + virtual MenuAction GetMenuAction() const; + virtual void AddMenuListener(MenuListener* listener); + virtual void RemoveMenuListener(MenuListener* listener); + virtual void SetMinimumWidth(int width); + + // Overridden from MenuDelegate: + virtual bool IsItemChecked(int id) const; + virtual bool IsCommandEnabled(int id) const; + virtual void ExecuteCommand(int id); + virtual bool GetAccelerator(int id, views::Accelerator* accelerator); + + private: + void AddMenuItemsFromModel(MenuItemView* parent, menus::MenuModel* model); + void UpdateMenuFromModel(SubmenuView* menu, menus::MenuModel* model); + + // The attached model and delegate. Does not assume ownership. + menus::MenuModel* model_; + scoped_ptr<MenuItemView> root_; + + DISALLOW_COPY_AND_ASSIGN(NativeMenuX); +}; + +} // namespace views + +#endif // VIEWS_CONTROLS_MENU_NATIVE_MENU_X_H_ diff --git a/views/controls/menu/nested_dispatcher_gtk.cc b/views/controls/menu/nested_dispatcher_gtk.cc index ba7a7b2..890385c 100644 --- a/views/controls/menu/nested_dispatcher_gtk.cc +++ b/views/controls/menu/nested_dispatcher_gtk.cc @@ -46,8 +46,9 @@ bool NestedDispatcherGtk::Dispatch(GdkEvent* event) { } #if defined(TOUCH_UI) -bool NestedDispatcherGtk::Dispatch(XEvent* xevent) { - return creator_ ? creator_->Dispatch(xevent) : false; +base::MessagePumpGlibXDispatcher::DispatchStatus NestedDispatcherGtk::Dispatch( + XEvent* xevent) { + return creator_->Dispatch(xevent); } #endif diff --git a/views/controls/menu/nested_dispatcher_gtk.h b/views/controls/menu/nested_dispatcher_gtk.h index f17e9a4..c8a6563 100644 --- a/views/controls/menu/nested_dispatcher_gtk.h +++ b/views/controls/menu/nested_dispatcher_gtk.h @@ -41,7 +41,8 @@ class NestedDispatcherGtk : public MessageLoopForUI::Dispatcher { virtual bool Dispatch(GdkEvent* event); #if defined(TOUCH_UI) - virtual bool Dispatch(XEvent* xevent); + virtual base::MessagePumpGlibXDispatcher::DispatchStatus Dispatch( + XEvent* xevent); #endif // Creator of the nested loop. diff --git a/views/focus/accelerator_handler.h b/views/focus/accelerator_handler.h index 2d08e47..9774922 100644 --- a/views/focus/accelerator_handler.h +++ b/views/focus/accelerator_handler.h @@ -43,7 +43,7 @@ class AcceleratorHandler : public MessageLoopForUI::Dispatcher { #else virtual bool Dispatch(GdkEvent* event); #if defined(TOUCH_UI) - virtual bool Dispatch(XEvent* xev); + virtual MessagePumpGlibXDispatcher::DispatchStatus Dispatch(XEvent* xev); #endif #endif diff --git a/views/focus/accelerator_handler_touch.cc b/views/focus/accelerator_handler_touch.cc index a35fc45..dc880b8 100644 --- a/views/focus/accelerator_handler_touch.cc +++ b/views/focus/accelerator_handler_touch.cc @@ -143,14 +143,9 @@ bool DispatchXEvent(XEvent* xev) { #if defined(HAVE_XINPUT2) if (xev->type == GenericEvent) { - if (XGetEventData(xev->xgeneric.display, &xev->xcookie)) { - XGenericEventCookie* cookie = &xev->xcookie; - XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(cookie->data); - xwindow = xiev->event; - } else { - DLOG(WARNING) << "Error fetching XGenericEventCookie for event."; - return false; - } + XGenericEventCookie* cookie = &xev->xcookie; + XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(cookie->data); + xwindow = xiev->event; } #endif @@ -202,9 +197,7 @@ bool DispatchXEvent(XEvent* xev) { #if defined(HAVE_XINPUT2) case GenericEvent: { - bool ret = DispatchX2Event(root, xev); - XFreeEventData(xev->xgeneric.display, &xev->xcookie); - return ret; + return DispatchX2Event(root, xev); } #endif } @@ -226,8 +219,11 @@ bool AcceleratorHandler::Dispatch(GdkEvent* event) { return true; } -bool AcceleratorHandler::Dispatch(XEvent* xev) { - return DispatchXEvent(xev); +base::MessagePumpGlibXDispatcher::DispatchStatus AcceleratorHandler::Dispatch( + XEvent* xev) { + return DispatchXEvent(xev) ? + base::MessagePumpGlibXDispatcher::EVENT_PROCESSED : + base::MessagePumpGlibXDispatcher::EVENT_IGNORED; } } // namespace views diff --git a/views/views.gyp b/views/views.gyp index d523633..5cb7b55 100644 --- a/views/views.gyp +++ b/views/views.gyp @@ -33,6 +33,8 @@ ]}], ['touchui==0', {'sources/': [ ['exclude', 'event_x.cc$'], + ['exclude', 'native_menu_x.cc$'], + ['exclude', 'native_menu_x.h$'], ['exclude', 'touchui/'], ['exclude', '_(touch)\\.cc$'], ]}], @@ -146,6 +148,8 @@ 'controls/menu/native_menu_gtk.h', 'controls/menu/native_menu_win.cc', 'controls/menu/native_menu_win.h', + 'controls/menu/native_menu_x.cc', + 'controls/menu/native_menu_x.h', 'controls/menu/nested_dispatcher_gtk.cc', 'controls/menu/nested_dispatcher_gtk.h', 'controls/menu/radio_button_image_gtk.cc', @@ -380,6 +384,7 @@ 'defines': ['TOUCH_UI=1'], 'sources/': [ ['exclude', 'focus/accelerator_handler_gtk.cc'], + ['exclude', 'controls/menu/native_menu_gtk.cc'], ], }], ['OS=="win"', { |