diff options
Diffstat (limited to 'chrome/browser/chromeos/views')
| -rw-r--r-- | chrome/browser/chromeos/views/domui_menu_widget.cc | 169 | ||||
| -rw-r--r-- | chrome/browser/chromeos/views/domui_menu_widget.h | 13 | ||||
| -rw-r--r-- | chrome/browser/chromeos/views/native_menu_domui.cc | 55 | ||||
| -rw-r--r-- | chrome/browser/chromeos/views/native_menu_domui.h | 19 |
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); }; |
