1 // Copyright 2014 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/ui/views/javascript_app_modal_event_blocker_x11.h" 6 7 #include "chrome/browser/ui/views/frame/browser_view.h" 8 #include "ui/aura/env.h" 9 #include "ui/aura/window.h" 10 #include "ui/events/event.h" 11 #include "ui/wm/core/window_animations.h" 12 #include "ui/wm/core/window_util.h" 13 14 namespace { 15 16 // Returns the toplevel window for the deepest transient ancestor of |window|. 17 aura::Window* GetTopmostTransientParent(aura::Window* window) { 18 aura::Window* topmost = wm::GetToplevelWindow(window); 19 while (topmost && wm::GetTransientParent(topmost)) 20 topmost = wm::GetToplevelWindow(wm::GetTransientParent(topmost)); 21 return topmost; 22 } 23 24 } // namespace 25 26 JavascriptAppModalEventBlockerX11::JavascriptAppModalEventBlockerX11( 27 aura::Window* modal_window) 28 : modal_window_(modal_window), 29 browser_view_with_modal_dialog_(NULL) { 30 aura::Window* topmost_transient_parent = 31 GetTopmostTransientParent(modal_window); 32 browser_view_with_modal_dialog_ = 33 BrowserView::GetBrowserViewForNativeWindow(topmost_transient_parent); 34 // |browser_view_with_modal_dialog_| is NULL if the dialog was opened by an 35 // extension background page. 36 37 aura::Env::GetInstance()->PrependPreTargetHandler(this); 38 39 // WindowModalityController will cancel touches as appropriate. 40 } 41 42 JavascriptAppModalEventBlockerX11::~JavascriptAppModalEventBlockerX11() { 43 aura::Env::GetInstance()->RemovePreTargetHandler(this); 44 } 45 46 bool JavascriptAppModalEventBlockerX11::ShouldStopPropagationTo( 47 ui::EventTarget* target) { 48 // Stop propagation if: 49 // -|target| is a browser window or a transient child of a browser window. 50 // -|target| is not the browser window which hosts |modal_window_| and not 51 // a transient child of that browser window. 52 // WindowModalityController will stop the transient parent from handling the 53 // event if the user clicks the modal window's transient parent (as opposed to 54 // clicking the modal window itself). 55 aura::Window* window = 56 GetTopmostTransientParent(static_cast<aura::Window*>(target)); 57 if (!window) 58 return false; 59 BrowserView* browser_view = 60 BrowserView::GetBrowserViewForNativeWindow(window); 61 return browser_view && browser_view != browser_view_with_modal_dialog_; 62 } 63 64 void JavascriptAppModalEventBlockerX11::OnKeyEvent(ui::KeyEvent* event) { 65 if (ShouldStopPropagationTo(event->target())) 66 event->StopPropagation(); 67 } 68 69 void JavascriptAppModalEventBlockerX11::OnMouseEvent(ui::MouseEvent* event) { 70 if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED && 71 ShouldStopPropagationTo(event->target())) { 72 if (event->type() == ui::ET_MOUSE_PRESSED) 73 wm::AnimateWindow(modal_window_, wm::WINDOW_ANIMATION_TYPE_BOUNCE); 74 event->StopPropagation(); 75 } 76 } 77 78 void JavascriptAppModalEventBlockerX11::OnScrollEvent(ui::ScrollEvent* event) { 79 if (ShouldStopPropagationTo(event->target())) 80 event->StopPropagation(); 81 } 82 83 void JavascriptAppModalEventBlockerX11::OnTouchEvent(ui::TouchEvent* event) { 84 if (event->type() != ui::ET_TOUCH_CANCELLED && 85 ShouldStopPropagationTo(event->target())) { 86 if (event->type() == ui::ET_TOUCH_PRESSED) 87 wm::AnimateWindow(modal_window_, wm::WINDOW_ANIMATION_TYPE_BOUNCE); 88 event->StopPropagation(); 89 } 90 } 91