summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorsadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-05 04:00:59 +0000
committersadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-05 04:00:59 +0000
commit7443494b88d2c04f3c07ebf98f0e6d68478eed7d (patch)
tree9211568b7d60a93dc8bf03a57a725dc8c8d967b7 /views
parent6f7e1d63f9c97c7f8f11af86f78f80934064a9a9 (diff)
downloadchromium_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.cc10
-rw-r--r--views/controls/menu/menu_controller.h2
-rw-r--r--views/controls/menu/menu_item_view.cc38
-rw-r--r--views/controls/menu/menu_item_view.h11
-rw-r--r--views/controls/menu/native_menu_x.cc162
-rw-r--r--views/controls/menu/native_menu_x.h56
-rw-r--r--views/controls/menu/nested_dispatcher_gtk.cc5
-rw-r--r--views/controls/menu/nested_dispatcher_gtk.h3
-rw-r--r--views/focus/accelerator_handler.h2
-rw-r--r--views/focus/accelerator_handler_touch.cc22
-rw-r--r--views/views.gyp5
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"', {