Home | History | Annotate | Download | only in menu
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/views/controls/menu/menu_controller.h"
      6 
      7 #include "base/run_loop.h"
      8 #include "ui/aura/client/activation_change_observer.h"
      9 #include "ui/aura/client/activation_client.h"
     10 #include "ui/aura/client/dispatcher_client.h"
     11 #include "ui/aura/client/drag_drop_client.h"
     12 #include "ui/aura/root_window.h"
     13 #include "ui/aura/window_observer.h"
     14 #include "ui/gfx/screen.h"
     15 #include "ui/views/widget/widget.h"
     16 
     17 namespace views {
     18 
     19 namespace {
     20 
     21 // ActivationChangeObserverImpl is used to observe activation changes and close
     22 // the menu. Additionally it listens for the root window to be destroyed and
     23 // cancel the menu as well.
     24 class ActivationChangeObserverImpl
     25     : public aura::client::ActivationChangeObserver,
     26       public aura::WindowObserver,
     27       public ui::EventHandler {
     28  public:
     29   ActivationChangeObserverImpl(MenuController* controller,
     30                                aura::RootWindow* root)
     31       : controller_(controller),
     32         root_(root) {
     33     aura::client::GetActivationClient(root_)->AddObserver(this);
     34     root_->AddObserver(this);
     35     root_->AddPreTargetHandler(this);
     36   }
     37 
     38   virtual ~ActivationChangeObserverImpl() {
     39     Cleanup();
     40   }
     41 
     42   // aura::client::ActivationChangeObserver overrides:
     43   virtual void OnWindowActivated(aura::Window* gained_active,
     44                                  aura::Window* lost_active) OVERRIDE {
     45     if (!controller_->drag_in_progress())
     46       controller_->CancelAll();
     47   }
     48 
     49   // aura::WindowObserver overrides:
     50   virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
     51     Cleanup();
     52   }
     53 
     54   // ui::EventHandler overrides:
     55   virtual void OnCancelMode(ui::CancelModeEvent* event) OVERRIDE {
     56     controller_->CancelAll();
     57   }
     58 
     59  private:
     60   void Cleanup() {
     61     if (!root_)
     62       return;
     63     // The ActivationClient may have been destroyed by the time we get here.
     64     aura::client::ActivationClient* client =
     65         aura::client::GetActivationClient(root_);
     66     if (client)
     67       client->RemoveObserver(this);
     68     root_->RemovePreTargetHandler(this);
     69     root_->RemoveObserver(this);
     70     root_ = NULL;
     71   }
     72 
     73   MenuController* controller_;
     74   aura::RootWindow* root_;
     75 
     76   DISALLOW_COPY_AND_ASSIGN(ActivationChangeObserverImpl);
     77 };
     78 
     79 aura::RootWindow* GetOwnerRootWindow(views::Widget* owner) {
     80   return owner ? owner->GetNativeWindow()->GetRootWindow() : NULL;
     81 }
     82 
     83 }  // namespace
     84 
     85 void MenuController::RunMessageLoop(bool nested_menu) {
     86   // |owner_| may be NULL.
     87   aura::RootWindow* root = GetOwnerRootWindow(owner_);
     88   if (root) {
     89     scoped_ptr<ActivationChangeObserverImpl> observer;
     90     if (!nested_menu)
     91       observer.reset(new ActivationChangeObserverImpl(this, root));
     92     aura::client::GetDispatcherClient(root)->
     93         RunWithDispatcher(this, owner_->GetNativeWindow(), true);
     94   } else {
     95     base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
     96     base::MessageLoop::ScopedNestableTaskAllower allow(loop);
     97     base::RunLoop run_loop(this);
     98     run_loop.Run();
     99   }
    100 }
    101 
    102 bool MenuController::ShouldQuitNow() const {
    103   aura::RootWindow* root = GetOwnerRootWindow(owner_);
    104   return !aura::client::GetDragDropClient(root) ||
    105       !aura::client::GetDragDropClient(root)->IsDragDropInProgress();
    106 }
    107 
    108 gfx::Screen* MenuController::GetScreen() {
    109   aura::RootWindow* root = GetOwnerRootWindow(owner_);
    110   return root ?
    111       gfx::Screen::GetScreenFor(root) : gfx::Screen::GetNativeScreen();
    112 }
    113 
    114 
    115 }  // namespace views
    116