| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stddef.h> | 5 #include <stddef.h> |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/location.h" | 9 #include "base/location.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 base::RunLoop run_loop; | 149 base::RunLoop run_loop; |
| 150 run_loop.Run(); | 150 run_loop.Run(); |
| 151 return true; | 151 return true; |
| 152 } | 152 } |
| 153 | 153 |
| 154 Widget* widget_; | 154 Widget* widget_; |
| 155 | 155 |
| 156 DISALLOW_COPY_AND_ASSIGN(NestedLoopCaptureView); | 156 DISALLOW_COPY_AND_ASSIGN(NestedLoopCaptureView); |
| 157 }; | 157 }; |
| 158 | 158 |
| 159 // Spins a run loop until a Widget's active state matches a desired state. | |
| 160 class WidgetActivationWaiter : public WidgetObserver { | |
| 161 public: | |
| 162 WidgetActivationWaiter(Widget* widget, bool active) : observed_(false) { | |
| 163 #if defined(OS_WIN) | |
| 164 // On Windows, a HWND can receive a WM_ACTIVATE message without the value | |
| 165 // of ::GetActiveWindow() updating to reflect that change. This can cause | |
| 166 // the active window reported by IsActive() to get out of sync. Usually this | |
| 167 // happens after a call to HWNDMessageHandler::Deactivate() which works by | |
| 168 // activating some other window, which might be in another application. | |
| 169 // Doing this can trigger the native OS activation-blocker, causing the | |
| 170 // taskbar icon to flash instead. But since activation of native widgets on | |
| 171 // Windows is synchronous, we never have to wait anyway, so it's safe to | |
| 172 // return here. | |
| 173 if (active == widget->IsActive()) { | |
| 174 observed_ = true; | |
| 175 return; | |
| 176 } | |
| 177 #endif | |
| 178 // Always expect a change for tests using this. | |
| 179 EXPECT_NE(active, widget->IsActive()); | |
| 180 widget->AddObserver(this); | |
| 181 } | |
| 182 | |
| 183 void Wait() { | |
| 184 if (!observed_) | |
| 185 run_loop_.Run(); | |
| 186 } | |
| 187 | |
| 188 void OnWidgetActivationChanged(Widget* widget, bool active) override { | |
| 189 observed_ = true; | |
| 190 widget->RemoveObserver(this); | |
| 191 if (run_loop_.running()) | |
| 192 run_loop_.Quit(); | |
| 193 } | |
| 194 | |
| 195 private: | |
| 196 base::RunLoop run_loop_; | |
| 197 bool observed_; | |
| 198 | |
| 199 DISALLOW_COPY_AND_ASSIGN(WidgetActivationWaiter); | |
| 200 }; | |
| 201 | |
| 202 ui::WindowShowState GetWidgetShowState(const Widget* widget) { | 159 ui::WindowShowState GetWidgetShowState(const Widget* widget) { |
| 203 // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement | 160 // Use IsMaximized/IsMinimized/IsFullScreen instead of GetWindowPlacement |
| 204 // because the former is implemented on all platforms but the latter is not. | 161 // because the former is implemented on all platforms but the latter is not. |
| 205 return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN : | 162 return widget->IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN : |
| 206 widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED : | 163 widget->IsMaximized() ? ui::SHOW_STATE_MAXIMIZED : |
| 207 widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED : | 164 widget->IsMinimized() ? ui::SHOW_STATE_MINIMIZED : |
| 208 widget->IsActive() ? ui::SHOW_STATE_NORMAL : | 165 widget->IsActive() ? ui::SHOW_STATE_NORMAL : |
| 209 ui::SHOW_STATE_INACTIVE; | 166 ui::SHOW_STATE_INACTIVE; |
| 210 } | 167 } |
| 211 | 168 |
| 212 // Give the OS an opportunity to process messages for an activation change, when | 169 // Give the OS an opportunity to process messages for an activation change, when |
| 213 // there is actually no change expected (e.g. ShowInactive()). | 170 // there is actually no change expected (e.g. ShowInactive()). |
| 214 void RunPendingMessagesForActiveStatusChange() { | 171 void RunPendingMessagesForActiveStatusChange() { |
| 215 #if defined(OS_MACOSX) | 172 #if defined(OS_MACOSX) |
| 216 // On Mac, a single spin is *usually* enough. It isn't when a widget is shown | 173 // On Mac, a single spin is *usually* enough. It isn't when a widget is shown |
| 217 // and made active in two steps, so tests should follow up with a ShowSync() | 174 // and made active in two steps, so tests should follow up with a ShowSync() |
| 218 // or ActivateSync to ensure a consistent state. | 175 // or ActivateSync to ensure a consistent state. |
| 219 base::RunLoop().RunUntilIdle(); | 176 base::RunLoop().RunUntilIdle(); |
| 220 #endif | 177 #endif |
| 221 // TODO(tapted): Check for desktop aura widgets. | 178 // TODO(tapted): Check for desktop aura widgets. |
| 222 } | 179 } |
| 223 | 180 |
| 224 // Activate a widget, and wait for it to become active. On non-desktop Aura | 181 // Activate a widget, and wait for it to become active. On non-desktop Aura |
| 225 // this is just an activation. For other widgets, it means activating and then | 182 // this is just an activation. For other widgets, it means activating and then |
| 226 // spinning the run loop until the OS has activated the window. | 183 // spinning the run loop until the OS has activated the window. |
| 227 void ActivateSync(Widget* widget) { | 184 void ActivateSync(Widget* widget) { |
| 228 WidgetActivationWaiter waiter(widget, true); | 185 views::test::WidgetActivationWaiter waiter(widget, true); |
| 229 widget->Activate(); | 186 widget->Activate(); |
| 230 waiter.Wait(); | 187 waiter.Wait(); |
| 231 } | 188 } |
| 232 | 189 |
| 233 // Like for ActivateSync(), wait for a widget to become active, but Show() the | 190 // Like for ActivateSync(), wait for a widget to become active, but Show() the |
| 234 // widget rather than calling Activate(). | 191 // widget rather than calling Activate(). |
| 235 void ShowSync(Widget* widget) { | 192 void ShowSync(Widget* widget) { |
| 236 WidgetActivationWaiter waiter(widget, true); | 193 views::test::WidgetActivationWaiter waiter(widget, true); |
| 237 widget->Show(); | 194 widget->Show(); |
| 238 waiter.Wait(); | 195 waiter.Wait(); |
| 239 } | 196 } |
| 240 | 197 |
| 241 void DeactivateSync(Widget* widget) { | 198 void DeactivateSync(Widget* widget) { |
| 242 #if defined(OS_MACOSX) | 199 #if defined(OS_MACOSX) |
| 243 // Deactivation of a window isn't a concept on Mac: If an application is | 200 // Deactivation of a window isn't a concept on Mac: If an application is |
| 244 // active and it has any activatable windows, then one of them is always | 201 // active and it has any activatable windows, then one of them is always |
| 245 // active. But we can simulate deactivation (e.g. as if another application | 202 // active. But we can simulate deactivation (e.g. as if another application |
| 246 // became active) by temporarily making |widget| non-activatable, then | 203 // became active) by temporarily making |widget| non-activatable, then |
| 247 // activating (and closing) a temporary widget. | 204 // activating (and closing) a temporary widget. |
| 248 widget->widget_delegate()->set_can_activate(false); | 205 widget->widget_delegate()->set_can_activate(false); |
| 249 Widget* stealer = new Widget; | 206 Widget* stealer = new Widget; |
| 250 stealer->Init(Widget::InitParams(Widget::InitParams::TYPE_WINDOW)); | 207 stealer->Init(Widget::InitParams(Widget::InitParams::TYPE_WINDOW)); |
| 251 ShowSync(stealer); | 208 ShowSync(stealer); |
| 252 stealer->CloseNow(); | 209 stealer->CloseNow(); |
| 253 widget->widget_delegate()->set_can_activate(true); | 210 widget->widget_delegate()->set_can_activate(true); |
| 254 #else | 211 #else |
| 255 WidgetActivationWaiter waiter(widget, false); | 212 views::test::WidgetActivationWaiter waiter(widget, false); |
| 256 widget->Deactivate(); | 213 widget->Deactivate(); |
| 257 waiter.Wait(); | 214 waiter.Wait(); |
| 258 #endif | 215 #endif |
| 259 } | 216 } |
| 260 | 217 |
| 261 #if defined(OS_WIN) | 218 #if defined(OS_WIN) |
| 262 void ActivatePlatformWindow(Widget* widget) { | 219 void ActivatePlatformWindow(Widget* widget) { |
| 263 ::SetActiveWindow( | 220 ::SetActiveWindow( |
| 264 widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget()); | 221 widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget()); |
| 265 } | 222 } |
| (...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 919 modal_dialog_widget->Show(); | 876 modal_dialog_widget->Show(); |
| 920 | 877 |
| 921 gfx::NativeView modal_native_view = modal_dialog_widget->GetNativeView(); | 878 gfx::NativeView modal_native_view = modal_dialog_widget->GetNativeView(); |
| 922 ASSERT_EQ(3u, focus_changes.size()); | 879 ASSERT_EQ(3u, focus_changes.size()); |
| 923 EXPECT_EQ(nullptr, focus_changes[1]); | 880 EXPECT_EQ(nullptr, focus_changes[1]); |
| 924 EXPECT_EQ(modal_native_view, focus_changes[2]); | 881 EXPECT_EQ(modal_native_view, focus_changes[2]); |
| 925 | 882 |
| 926 #if defined(OS_MACOSX) | 883 #if defined(OS_MACOSX) |
| 927 // Window modal dialogs on Mac are "sheets", which animate to close before | 884 // Window modal dialogs on Mac are "sheets", which animate to close before |
| 928 // activating their parent widget. | 885 // activating their parent widget. |
| 929 WidgetActivationWaiter waiter(&top_level_widget, true); | 886 views::test::WidgetActivationWaiter waiter(&top_level_widget, true); |
| 930 modal_dialog_widget->Close(); | 887 modal_dialog_widget->Close(); |
| 931 waiter.Wait(); | 888 waiter.Wait(); |
| 932 #else | 889 #else |
| 933 modal_dialog_widget->CloseNow(); | 890 modal_dialog_widget->CloseNow(); |
| 934 #endif | 891 #endif |
| 935 | 892 |
| 936 ASSERT_EQ(5u, focus_changes.size()); | 893 ASSERT_EQ(5u, focus_changes.size()); |
| 937 EXPECT_EQ(nullptr, focus_changes[3]); | 894 EXPECT_EQ(nullptr, focus_changes[3]); |
| 938 EXPECT_EQ(top_level_native_view, focus_changes[4]); | 895 EXPECT_EQ(top_level_native_view, focus_changes[4]); |
| 939 | 896 |
| (...skipping 919 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1859 | 1816 |
| 1860 ui::KeyEvent key_event2(key_event); | 1817 ui::KeyEvent key_event2(key_event); |
| 1861 widget->OnKeyEvent(&key_event2); | 1818 widget->OnKeyEvent(&key_event2); |
| 1862 EXPECT_FALSE(key_event2.stopped_propagation()); | 1819 EXPECT_FALSE(key_event2.stopped_propagation()); |
| 1863 | 1820 |
| 1864 widget->CloseNow(); | 1821 widget->CloseNow(); |
| 1865 } | 1822 } |
| 1866 | 1823 |
| 1867 } // namespace test | 1824 } // namespace test |
| 1868 } // namespace views | 1825 } // namespace views |
| OLD | NEW |