• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "chrome/browser/automation/testing_automation_provider.h"
6 
7 #include "chrome/browser/automation/automation_browser_tracker.h"
8 #include "chrome/browser/automation/automation_window_tracker.h"
9 #include "chrome/browser/ui/browser_window.h"
10 #include "chrome/browser/ui/views/frame/browser_view.h"
11 #include "chrome/browser/ui/views/toolbar_view.h"
12 #include "chrome/common/automation_messages.h"
13 #include "ui/gfx/point.h"
14 #include "views/controls/menu/menu_wrapper.h"
15 #include "views/view.h"
16 #include "views/widget/native_widget.h"
17 #include "views/widget/root_view.h"
18 #include "views/widget/widget.h"
19 
20 namespace {
21 
22 // Helper class that waits until the focus has changed to a view other
23 // than the one with the provided view id.
24 class ViewFocusChangeWaiter : public views::FocusChangeListener {
25  public:
ViewFocusChangeWaiter(views::FocusManager * focus_manager,int previous_view_id,AutomationProvider * automation,IPC::Message * reply_message)26   ViewFocusChangeWaiter(views::FocusManager* focus_manager,
27                         int previous_view_id,
28                         AutomationProvider* automation,
29                         IPC::Message* reply_message)
30       : focus_manager_(focus_manager),
31         previous_view_id_(previous_view_id),
32         automation_(automation),
33         reply_message_(reply_message),
34         ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
35     focus_manager_->AddFocusChangeListener(this);
36     // Call the focus change notification once in case the focus has
37     // already changed.
38     FocusWillChange(NULL, focus_manager_->GetFocusedView());
39   }
40 
~ViewFocusChangeWaiter()41   ~ViewFocusChangeWaiter() {
42     focus_manager_->RemoveFocusChangeListener(this);
43   }
44 
45   // Inherited from FocusChangeListener
FocusWillChange(views::View * focused_before,views::View * focused_now)46   virtual void FocusWillChange(views::View* focused_before,
47                                views::View* focused_now) {
48     // This listener is called before focus actually changes. Post a task
49     // that will get run after focus changes.
50     MessageLoop::current()->PostTask(
51         FROM_HERE,
52         method_factory_.NewRunnableMethod(
53             &ViewFocusChangeWaiter::FocusChanged,
54             focused_before,
55             focused_now));
56   }
57 
58  private:
FocusChanged(views::View * focused_before,views::View * focused_now)59   void FocusChanged(views::View* focused_before,
60                     views::View* focused_now) {
61     if (focused_now && focused_now->GetID() != previous_view_id_) {
62       AutomationMsg_WaitForFocusedViewIDToChange::WriteReplyParams(
63           reply_message_, true, focused_now->GetID());
64 
65       automation_->Send(reply_message_);
66       delete this;
67     }
68   }
69 
70   views::FocusManager* focus_manager_;
71   int previous_view_id_;
72   AutomationProvider* automation_;
73   IPC::Message* reply_message_;
74   ScopedRunnableMethodFactory<ViewFocusChangeWaiter> method_factory_;
75 
76   DISALLOW_COPY_AND_ASSIGN(ViewFocusChangeWaiter);
77 };
78 
79 }  // namespace
80 
81 class TestingAutomationProvider::PopupMenuWaiter : public views::MenuListener {
82  public:
PopupMenuWaiter(ToolbarView * toolbar_view,TestingAutomationProvider * automation)83   PopupMenuWaiter(ToolbarView* toolbar_view,
84                   TestingAutomationProvider* automation)
85       : toolbar_view_(toolbar_view),
86         automation_(automation),
87         reply_message_(NULL) {
88     toolbar_view_->AddMenuListener(this);
89   }
90 
91   // Implementation of views::MenuListener
OnMenuOpened()92   virtual void OnMenuOpened() {
93     toolbar_view_->RemoveMenuListener(this);
94     automation_->popup_menu_opened_ = true;
95     automation_->popup_menu_waiter_ = NULL;
96     if (reply_message_) {
97       AutomationMsg_WaitForPopupMenuToOpen::WriteReplyParams(
98           reply_message_, true);
99       automation_->Send(reply_message_);
100     }
101     delete this;
102   }
103 
set_reply_message(IPC::Message * reply_message)104   void set_reply_message(IPC::Message* reply_message) {
105     reply_message_ = reply_message;
106   }
107 
108  private:
109   ToolbarView* toolbar_view_;
110   TestingAutomationProvider* automation_;
111   IPC::Message* reply_message_;
112 
113   DISALLOW_COPY_AND_ASSIGN(PopupMenuWaiter);
114 };
115 
WindowGetViewBounds(int handle,int view_id,bool screen_coordinates,bool * success,gfx::Rect * bounds)116 void TestingAutomationProvider::WindowGetViewBounds(int handle,
117                                                     int view_id,
118                                                     bool screen_coordinates,
119                                                     bool* success,
120                                                     gfx::Rect* bounds) {
121   *success = false;
122 
123   if (window_tracker_->ContainsHandle(handle)) {
124     gfx::NativeWindow window = window_tracker_->GetResource(handle);
125     views::NativeWidget* native_widget =
126         views::NativeWidget::GetNativeWidgetForNativeWindow(window);
127     if (native_widget) {
128       views::View* root_view = native_widget->GetWidget()->GetRootView();
129       views::View* view = root_view->GetViewByID(view_id);
130       if (view) {
131         *success = true;
132         gfx::Point point;
133         if (screen_coordinates)
134           views::View::ConvertPointToScreen(view, &point);
135         else
136           views::View::ConvertPointToView(view, root_view, &point);
137         *bounds = view->GetContentsBounds();
138         bounds->set_origin(point);
139       }
140     }
141   }
142 }
143 
GetFocusedViewID(int handle,int * view_id)144 void TestingAutomationProvider::GetFocusedViewID(int handle, int* view_id) {
145   *view_id = -1;
146   if (window_tracker_->ContainsHandle(handle)) {
147     gfx::NativeWindow window = window_tracker_->GetResource(handle);
148     views::FocusManager* focus_manager =
149         views::FocusManager::GetFocusManagerForNativeWindow(window);
150     DCHECK(focus_manager);
151     views::View* focused_view = focus_manager->GetFocusedView();
152     if (focused_view)
153       *view_id = focused_view->GetID();
154   }
155 }
156 
WaitForFocusedViewIDToChange(int handle,int previous_view_id,IPC::Message * reply_message)157 void TestingAutomationProvider::WaitForFocusedViewIDToChange(
158     int handle, int previous_view_id, IPC::Message* reply_message) {
159   if (!window_tracker_->ContainsHandle(handle))
160     return;
161   gfx::NativeWindow window = window_tracker_->GetResource(handle);
162   views::FocusManager* focus_manager =
163       views::FocusManager::GetFocusManagerForNativeWindow(window);
164 
165   // The waiter will respond to the IPC and delete itself when done.
166   new ViewFocusChangeWaiter(focus_manager,
167                             previous_view_id,
168                             this,
169                             reply_message);
170 }
171 
StartTrackingPopupMenus(int browser_handle,bool * success)172 void TestingAutomationProvider::StartTrackingPopupMenus(
173     int browser_handle, bool* success) {
174   if (browser_tracker_->ContainsHandle(browser_handle)) {
175     Browser* browser = browser_tracker_->GetResource(browser_handle);
176     BrowserView* browser_view = reinterpret_cast<BrowserView*>(
177         browser->window());
178     ToolbarView* toolbar_view = browser_view->GetToolbarView();
179     popup_menu_opened_ = false;
180     popup_menu_waiter_ = new PopupMenuWaiter(toolbar_view, this);
181     *success = true;
182   }
183 }
184 
WaitForPopupMenuToOpen(IPC::Message * reply_message)185 void TestingAutomationProvider::WaitForPopupMenuToOpen(
186     IPC::Message* reply_message) {
187   // See if the menu already opened and return true if so.
188   if (popup_menu_opened_) {
189     AutomationMsg_WaitForPopupMenuToOpen::WriteReplyParams(
190           reply_message, true);
191     Send(reply_message);
192     return;
193   }
194 
195   // Otherwise, register this reply message with the waiter,
196   // which will handle responding to this IPC when the popup
197   // menu opens.
198   popup_menu_waiter_->set_reply_message(reply_message);
199 }
200