summaryrefslogtreecommitdiffstats
path: root/chrome/browser/chromeos/views
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/chromeos/views')
-rw-r--r--chrome/browser/chromeos/views/domui_menu_widget.cc169
-rw-r--r--chrome/browser/chromeos/views/domui_menu_widget.h13
-rw-r--r--chrome/browser/chromeos/views/native_menu_domui.cc55
-rw-r--r--chrome/browser/chromeos/views/native_menu_domui.h19
4 files changed, 84 insertions, 172 deletions
diff --git a/chrome/browser/chromeos/views/domui_menu_widget.cc b/chrome/browser/chromeos/views/domui_menu_widget.cc
index 1657ddc..6231d6a 100644
--- a/chrome/browser/chromeos/views/domui_menu_widget.cc
+++ b/chrome/browser/chromeos/views/domui_menu_widget.cc
@@ -103,137 +103,6 @@ class InsetsLayout : public views::LayoutManager {
DISALLOW_COPY_AND_ASSIGN(InsetsLayout);
};
-const int kDOMViewWarmUpDelayMs = 1000 * 5;
-
-// A delayed task to initialize a cache. This is
-// create when a profile is switched.
-// (incognito, oobe/login has different profile).
-class WarmUpTask : public Task {
- public:
- WarmUpTask() {}
- virtual ~WarmUpTask() {}
-
- virtual void Run();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WarmUpTask);
-};
-
-// DOMViewCache holds single cache instance of DOMView.
-class DOMViewCache : NotificationObserver {
- public:
- DOMViewCache()
- : current_profile_(NULL),
- cache_(NULL),
- warmup_enabled_(true) {
- registrar_.Add(this, NotificationType::APP_TERMINATING,
- NotificationService::AllSources());
- }
- virtual ~DOMViewCache() {}
-
- // Returns a DOMView for given profile. If there is
- // matching cache,
- DOMView* Get(Profile* profile) {
- if (cache_ &&
- cache_->tab_contents()->profile() == profile) {
- DOMView* c = cache_;
- cache_ = NULL;
- CheckClassInvariant();
- return c;
- }
- DOMView* dom_view = new DOMView();
- dom_view->Init(profile, NULL);
- CheckClassInvariant();
- return dom_view;
- }
-
- // Release a dom_view. A dom view is reused if its profile matches
- // the current profile, or gets deleted otherwise.
- void Release(DOMView* dom_view) {
- if (cache_ == NULL &&
- current_profile_ == dom_view->tab_contents()->profile()) {
- cache_ = dom_view;
- } else {
- delete dom_view;
- }
- CheckClassInvariant();
- }
-
- // (Re)Initiailzes the cache with profile.
- // If the current profile does not match the new profile,
- // it deletes the existing cache (if any) and creates new one.
- void Init(Profile* profile) {
- if (current_profile_ != profile) {
- delete cache_;
- cache_ = NULL;
- current_profile_ = profile;
- BrowserThread::PostDelayedTask(BrowserThread::UI,
- FROM_HERE,
- new WarmUpTask(),
- kDOMViewWarmUpDelayMs);
- }
- CheckClassInvariant();
- }
-
- // Create a cache if one does not exist yet.
- void WarmUp() {
- // skip if domui is created in delay, or
- // chromeos is shutting down.
- if (cache_ || !current_profile_ || !warmup_enabled_) {
- CheckClassInvariant();
- return;
- }
- cache_ = new DOMView();
- cache_->Init(current_profile_, NULL);
- /**
- * Tentative workaround for the failing tests that expects
- * page loads.
- cache_->LoadURL(
- GURL(StringPrintf("chrome://%s", chrome::kChromeUIMenu)));
- */
- CheckClassInvariant();
- }
-
- // Deletes cached DOMView instance if any.
- void Shutdown() {
- delete cache_;
- cache_ = NULL;
- // Reset current_profile_ as well so that a domview that
- // is currently in use will be deleted in Release as well.
- current_profile_ = NULL;
- }
-
- // Enable/disable warmup. This has to be called
- // before WarmUp method is invoked.
- void set_warmup_enabled(bool enabled) {
- warmup_enabled_ = enabled;
- }
-
- private:
- // NotificationObserver impelmentation:
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK_EQ(NotificationType::APP_TERMINATING, type.value);
- Shutdown();
- }
-
- // Tests the class invariant condition.
- void CheckClassInvariant() {
- DCHECK(!cache_ ||
- cache_->tab_contents()->profile() == current_profile_);
- }
-
- Profile* current_profile_;
- DOMView* cache_;
- NotificationRegistrar registrar_;
- bool warmup_enabled_;
-};
-
-void WarmUpTask::Run() {
- Singleton<DOMViewCache>::get()->WarmUp();
-}
-
// A gtk widget key used to test if a given WidgetGtk instance is
// DOMUIMenuWidgetKey.
const char* kDOMUIMenuWidgetKey = "__DOMUI_MENU_WIDGET__";
@@ -260,14 +129,12 @@ DOMUIMenuWidget::DOMUIMenuWidget(chromeos::NativeMenuDOMUI* domui_menu,
: views::WidgetGtk(views::WidgetGtk::TYPE_POPUP),
domui_menu_(domui_menu),
dom_view_(NULL),
- did_pointer_grab_(false),
+ did_input_grab_(false),
is_root_(root) {
DCHECK(domui_menu_);
// TODO(oshima): Disabling transparent until we migrate bookmark
// menus to DOMUI. See crosbug.com/7718.
// MakeTransparent();
-
- Singleton<DOMViewCache>::get()->Init(domui_menu->GetProfile());
}
DOMUIMenuWidget::~DOMUIMenuWidget() {
@@ -291,7 +158,7 @@ void DOMUIMenuWidget::Hide() {
void DOMUIMenuWidget::Close() {
if (dom_view_ != NULL) {
dom_view_->GetParent()->RemoveChildView(dom_view_);
- Singleton<DOMViewCache>::get()->Release(dom_view_);
+ delete dom_view_;
dom_view_ = NULL;
}
@@ -302,9 +169,10 @@ void DOMUIMenuWidget::Close() {
void DOMUIMenuWidget::ReleaseGrab() {
WidgetGtk::ReleaseGrab();
- if (did_pointer_grab_) {
- did_pointer_grab_ = false;
+ if (did_input_grab_) {
+ did_input_grab_ = false;
gdk_pointer_ungrab(GDK_CURRENT_TIME);
+ gdk_keyboard_ungrab(GDK_CURRENT_TIME);
ClearGrabWidget();
}
@@ -312,7 +180,7 @@ void DOMUIMenuWidget::ReleaseGrab() {
gboolean DOMUIMenuWidget::OnGrabBrokeEvent(GtkWidget* widget,
GdkEvent* event) {
- did_pointer_grab_ = false;
+ did_input_grab_ = false;
Hide();
return WidgetGtk::OnGrabBrokeEvent(widget, event);
}
@@ -392,7 +260,10 @@ void DOMUIMenuWidget::ShowAt(chromeos::MenuLocator* locator) {
DCHECK(domui_menu_);
menu_locator_.reset(locator);
if (!dom_view_) {
- dom_view_ = Singleton<DOMViewCache>::get()->Get(domui_menu_->GetProfile());
+ // TODO(oshima): Replace DOMView with direct use of RVH for beta.
+ // DOMView should be refactored to use RVH directly, but
+ // it'll require a lot of change and will take time.
+ dom_view_ = new DOMView();
dom_view_->Init(domui_menu_->GetProfile(), NULL);
// TODO(oshima): remove extra view to draw rounded corner.
views::View* container = new views::View();
@@ -440,16 +311,22 @@ void DOMUIMenuWidget::CaptureGrab() {
// Release the current grab.
ClearGrabWidget();
- // NOTE: we do this to ensure we get mouse events from other apps, a grab
- // done with gtk_grab_add doesn't get events from other apps.
- GdkGrabStatus grab_status =
+ // NOTE: we do this to ensure we get mouse/keyboard events from
+ // other apps, a grab done with gtk_grab_add doesn't get events from
+ // other apps.
+ GdkGrabStatus pointer_grab_status =
gdk_pointer_grab(window_contents()->window, FALSE,
static_cast<GdkEventMask>(
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK),
NULL, NULL, GDK_CURRENT_TIME);
- did_pointer_grab_ = (grab_status == GDK_GRAB_SUCCESS);
- DCHECK(did_pointer_grab_);
+ GdkGrabStatus keyboard_grab_status =
+ gdk_keyboard_grab(window_contents()->window, FALSE,
+ GDK_CURRENT_TIME);
+
+ did_input_grab_ = pointer_grab_status == GDK_GRAB_SUCCESS &&
+ keyboard_grab_status == GDK_GRAB_SUCCESS;
+ DCHECK(did_input_grab_);
EnableInput(false /* no selection */);
}
@@ -460,8 +337,4 @@ void DOMUIMenuWidget::ClearGrabWidget() {
gtk_grab_remove(grab_widget);
}
-void DOMUIMenuWidget::DisableWarmUp() {
- Singleton<DOMViewCache>::get()->set_warmup_enabled(false);
-}
-
} // namespace chromeos
diff --git a/chrome/browser/chromeos/views/domui_menu_widget.h b/chrome/browser/chromeos/views/domui_menu_widget.h
index 13fa579..095d4c4 100644
--- a/chrome/browser/chromeos/views/domui_menu_widget.h
+++ b/chrome/browser/chromeos/views/domui_menu_widget.h
@@ -45,8 +45,8 @@ class DOMUIMenuWidget : public views::WidgetGtk {
}
// Returns true if the menu widget has input grab.
- bool did_pointer_grab() const {
- return did_pointer_grab_;
+ bool did_input_grab() const {
+ return did_input_grab_;
}
// Enables/Disables menu scroll.
@@ -77,11 +77,6 @@ class DOMUIMenuWidget : public views::WidgetGtk {
static DOMUIMenuWidget* FindDOMUIMenuWidget(gfx::NativeView native);
private:
- friend class ::ExtensionApiTest;
- // Disable warming up domview. This is to avoid confusing Extension
- // API tests which listens to load notification with AllSources().
- static void DisableWarmUp();
-
// Capture the X pointer grab. This also enables input on the widget by
// calling EnableInput(false).
void CaptureGrab();
@@ -98,8 +93,8 @@ class DOMUIMenuWidget : public views::WidgetGtk {
// MenuLocator that controls the position of this menu widget.
scoped_ptr<chromeos::MenuLocator> menu_locator_;
- // True if the widget has pointer grab.
- bool did_pointer_grab_;
+ // True if the widget has input grab.
+ bool did_input_grab_;
// True if the widget is for root menu (very first menu in
// submenu chain).
diff --git a/chrome/browser/chromeos/views/native_menu_domui.cc b/chrome/browser/chromeos/views/native_menu_domui.cc
index d421f5f..5ce238c 100644
--- a/chrome/browser/chromeos/views/native_menu_domui.cc
+++ b/chrome/browser/chromeos/views/native_menu_domui.cc
@@ -20,9 +20,17 @@
#include "gfx/rect.h"
#include "views/controls/menu/menu_2.h"
#include "views/controls/menu/native_menu_gtk.h"
+#include "views/controls/menu/nested_dispatcher_gtk.h"
+
+#if defined(TOUCH_UI)
+#include "views/focus/accelerator_handler.h"
+#endif
namespace {
+using chromeos::NativeMenuDOMUI;
+using chromeos::DOMUIMenuWidget;
+
// Returns true if the menu item type specified can be executed as a command.
bool MenuTypeCanExecute(menus::MenuModel::ItemType type) {
return type == menus::MenuModel::TYPE_COMMAND ||
@@ -31,9 +39,11 @@ bool MenuTypeCanExecute(menus::MenuModel::ItemType type) {
}
gboolean Destroy(GtkWidget* widget, gpointer data) {
- chromeos::NativeMenuDOMUI* domui_menu =
- static_cast<chromeos::NativeMenuDOMUI*>(data);
- domui_menu->Hide();
+ DOMUIMenuWidget* menu_widget = static_cast<DOMUIMenuWidget*>(data);
+ NativeMenuDOMUI* domui_menu = menu_widget->domui_menu();
+ // domui_menu can be NULL if widget is destroyed by signal.
+ if (domui_menu)
+ domui_menu->Hide();
return true;
}
@@ -51,7 +61,7 @@ gfx::NativeWindow FindActiveToplevelWindow() {
}
// Currently opened menu. See RunMenuAt for reason why we need this.
-chromeos::NativeMenuDOMUI* current_ = NULL;
+NativeMenuDOMUI* current_ = NULL;
} // namespace
@@ -83,7 +93,8 @@ NativeMenuDOMUI::NativeMenuDOMUI(menus::MenuModel* menu_model, bool root)
activated_index_(-1),
menu_action_(MENU_ACTION_NONE),
menu_url_(StringPrintf("chrome://%s", chrome::kChromeUIMenu)),
- on_menu_opened_called_(false) {
+ on_menu_opened_called_(false),
+ nested_dispatcher_(NULL) {
menu_widget_ = new DOMUIMenuWidget(this, root);
// Set the initial location off the screen not to show small
// window with dropshadow.
@@ -91,7 +102,12 @@ NativeMenuDOMUI::NativeMenuDOMUI(menus::MenuModel* menu_model, bool root)
}
NativeMenuDOMUI::~NativeMenuDOMUI() {
- DCHECK(!menu_shown_) << "Deleting while the menu is shown";
+ if (nested_dispatcher_) {
+ // Menu is destroyed while its in message loop.
+ // Let nested dispatcher know the creator is deleted.
+ nested_dispatcher_->CreatorDestroyed();
+ Hide();
+ }
if (menu_widget_) {
menu_widget_->Close();
menu_widget_ = NULL;
@@ -141,15 +157,20 @@ void NativeMenuDOMUI::RunMenuAt(const gfx::Point& point, int alignment) {
if (parent) {
handle = g_signal_connect(G_OBJECT(parent), "destroy",
G_CALLBACK(&Destroy),
- this);
+ menu_widget_);
}
-
// We need to turn on nestable tasks as a renderer uses tasks internally.
// Without this, renderer cannnot finish loading page.
- bool nestable = MessageLoopForUI::current()->NestableTasksAllowed();
- MessageLoopForUI::current()->SetNestableTasksAllowed(true);
- MessageLoopForUI::current()->Run(this);
- MessageLoopForUI::current()->SetNestableTasksAllowed(nestable);
+ nested_dispatcher_ =
+ new views::NestedDispatcherGtk(this, true /* allow nested */);
+ bool deleted = nested_dispatcher_->RunAndSelfDestruct();
+ current_ = NULL; // this is static and safe to access.
+ if (deleted) {
+ // The menu was destryed while menu is shown, so return immediately.
+ // Don't touch the instance which is already deleted.
+ return;
+ }
+ nested_dispatcher_ = NULL;
if (menu_shown_) {
// If this happens it means we haven't yet gotten the hide signal and
// someone else quit the message loop on us.
@@ -162,7 +183,6 @@ void NativeMenuDOMUI::RunMenuAt(const gfx::Point& point, int alignment) {
menu_widget_->Hide();
// Close All submenus.
submenu_.reset();
- current_ = NULL;
ProcessActivate();
}
@@ -228,6 +248,12 @@ bool NativeMenuDOMUI::Dispatch(GdkEvent* event) {
return true;
}
+#if defined(TOUCH_UI)
+bool NativeMenuDOMUI::Dispatch(XEvent* xevent) {
+ return views::DispatchXEvent(xevent);
+}
+#endif
+
////////////////////////////////////////////////////////////////////////////////
// NativeMenuDOMUI, MenuControl implementation:
@@ -359,7 +385,8 @@ void NativeMenuDOMUI::ShowAt(MenuLocator* locator) {
NativeMenuDOMUI* NativeMenuDOMUI::FindMenuAt(const gfx::Point& point) {
if (submenu_.get()) {
NativeMenuDOMUI* found = submenu_->FindMenuAt(point);
- if (found) return found;
+ if (found)
+ return found;
}
gfx::Rect bounds;
menu_widget_->GetBounds(&bounds, false);
diff --git a/chrome/browser/chromeos/views/native_menu_domui.h b/chrome/browser/chromeos/views/native_menu_domui.h
index 2c5e216..03a6b92 100644
--- a/chrome/browser/chromeos/views/native_menu_domui.h
+++ b/chrome/browser/chromeos/views/native_menu_domui.h
@@ -10,6 +10,7 @@
#include "base/message_loop.h"
#include "base/observer_list.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/chromeos/dom_ui/domui_menu_control.h"
#include "googleurl/src/gurl.h"
#include "views/controls/menu/menu_wrapper.h"
@@ -22,6 +23,14 @@ namespace menus {
class MenuModel;
} // namespace menus
+namespace views {
+class NestedDispatcherGtk;
+} // namespace views;
+
+#if defined(TOUCH_UI)
+typedef union _XEvent XEvent;
+#endif
+
namespace chromeos {
class MenuLocator;
@@ -30,7 +39,7 @@ class DOMUIMenuWidget;
// A DOMUI implementation of MenuWrapper.
class NativeMenuDOMUI : public views::MenuWrapper,
public DOMUIMenuControl,
- public MessageLoopForUI::Dispatcher {
+ public MessageLoop::Dispatcher {
public:
NativeMenuDOMUI(menus::MenuModel* menu_model, bool root);
virtual ~NativeMenuDOMUI();
@@ -54,6 +63,9 @@ class NativeMenuDOMUI : public views::MenuWrapper,
// Overriden from MessageLoopForUI::Dispatcher:
virtual bool Dispatch(GdkEvent* event);
+#if defined(TOUCH_UI)
+ virtual bool Dispatch(XEvent* xevent);
+#endif
// Overriden from DOMUIMenuControl;
virtual menus::MenuModel* GetMenuModel() { return model_; }
@@ -140,6 +152,11 @@ class NativeMenuDOMUI : public views::MenuWrapper,
// A guard flag to avoid calling MenuListener::OnMenuOpened twice.
bool on_menu_opened_called_;
+ // Nested dispatcher object that can outlive this object.
+ // This is to deal with the menu being deleted while the nested
+ // message loop is handled. see http://crosbug.com/7929 .
+ views::NestedDispatcherGtk* nested_dispatcher_;
+
DISALLOW_COPY_AND_ASSIGN(NativeMenuDOMUI);
};