Commit 5fa7a281 authored by andresantoso's avatar andresantoso Committed by Commit bot

MacViews: Implement event monitoring for a specific window (Reland)

ManagePasswordBubbleView wants to monitor events on a specific window,
currently using aura specific code that won't work for MacViews.
views::EventMonitor is enhanced to support monitoring events on a window,
with both Mac and Aura implementations.

Also includes minor compile fixes in ZoomBubbleView and StatusBubbleView.

Originally reviewed in https://crrev.com/730833006/

BUG=425229

Review URL: https://codereview.chromium.org/793003004

Cr-Commit-Position: refs/heads/master@{#308112}
parent 5eea7412
......@@ -93,7 +93,7 @@ void ZoomBubbleView::ShowBubble(content::WebContents* web_contents,
// If we do not have an anchor view, parent the bubble to the content area.
if (!anchor_to_view)
zoom_bubble_->set_parent_window(web_contents->GetTopLevelNativeWindow());
zoom_bubble_->set_parent_window(web_contents->GetNativeView());
views::BubbleDelegateView::CreateBubble(zoom_bubble_);
......
......@@ -20,7 +20,6 @@
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/controls/button/blue_button.h"
......@@ -32,6 +31,7 @@
#include "ui/views/controls/separator.h"
#include "ui/views/controls/styled_label.h"
#include "ui/views/controls/styled_label_listener.h"
#include "ui/views/event_monitor.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/layout/layout_constants.h"
......@@ -915,15 +915,13 @@ class ManagePasswordsBubbleView::WebContentMouseHandler
: public ui::EventHandler {
public:
explicit WebContentMouseHandler(ManagePasswordsBubbleView* bubble);
~WebContentMouseHandler() override;
void OnKeyEvent(ui::KeyEvent* event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
private:
aura::Window* GetWebContentsWindow();
ManagePasswordsBubbleView* bubble_;
scoped_ptr<views::EventMonitor> event_monitor_;
DISALLOW_COPY_AND_ASSIGN(WebContentMouseHandler);
};
......@@ -931,17 +929,15 @@ class ManagePasswordsBubbleView::WebContentMouseHandler
ManagePasswordsBubbleView::WebContentMouseHandler::WebContentMouseHandler(
ManagePasswordsBubbleView* bubble)
: bubble_(bubble) {
GetWebContentsWindow()->AddPreTargetHandler(this);
}
ManagePasswordsBubbleView::WebContentMouseHandler::~WebContentMouseHandler() {
if (aura::Window* window = GetWebContentsWindow())
window->RemovePreTargetHandler(this);
content::WebContents* web_contents = bubble_->web_contents();
DCHECK(web_contents);
event_monitor_ = views::EventMonitor::CreateWindowMonitor(
this, web_contents->GetTopLevelNativeWindow());
}
void ManagePasswordsBubbleView::WebContentMouseHandler::OnKeyEvent(
ui::KeyEvent* event) {
content::WebContents* web_contents = bubble_->model()->web_contents();
content::WebContents* web_contents = bubble_->web_contents();
content::RenderViewHost* rvh = web_contents->GetRenderViewHost();
if (rvh->IsFocusedElementEditable() &&
event->type() == ui::ET_KEY_PRESSED)
......@@ -954,12 +950,6 @@ void ManagePasswordsBubbleView::WebContentMouseHandler::OnMouseEvent(
bubble_->Close();
}
aura::Window*
ManagePasswordsBubbleView::WebContentMouseHandler::GetWebContentsWindow() {
content::WebContents* web_contents = bubble_->model()->web_contents();
return web_contents ? web_contents->GetNativeView() : NULL;
}
// ManagePasswordsBubbleView --------------------------------------------------
// static
......@@ -986,10 +976,8 @@ void ManagePasswordsBubbleView::ShowBubble(content::WebContents* web_contents,
manage_passwords_bubble_ = new ManagePasswordsBubbleView(
web_contents, anchor_view, reason);
if (is_fullscreen) {
manage_passwords_bubble_->set_parent_window(
web_contents->GetTopLevelNativeWindow());
}
if (is_fullscreen)
manage_passwords_bubble_->set_parent_window(web_contents->GetNativeView());
views::BubbleDelegateView::CreateBubble(manage_passwords_bubble_);
......
......@@ -6,7 +6,6 @@
#include <algorithm>
#include "ash/wm/window_state.h"
#include "base/bind.h"
#include "base/i18n/rtl.h"
#include "base/message_loop/message_loop.h"
......@@ -17,7 +16,6 @@
#include "net/base/net_util.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkRect.h"
#include "ui/aura/window.h"
#include "ui/base/theme_provider.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/gfx/animation/linear_animation.h"
......@@ -35,6 +33,10 @@
#include "ui/views/widget/widget.h"
#include "url/gurl.h"
#if defined(USE_ASH)
#include "ash/wm/window_state.h"
#endif
// The alpha and color of the bubble's shadow.
static const SkColor kShadowColor = SkColorSetARGB(30, 0, 0, 0);
......@@ -580,13 +582,14 @@ void StatusBubbleViews::Init() {
params.parent = frame->GetNativeView();
params.context = frame->GetNativeWindow();
popup_->Init(params);
popup_->GetNativeView()->SetName("StatusBubbleViews");
// We do our own animation and don't want any from the system.
popup_->SetVisibilityChangedAnimationsEnabled(false);
popup_->SetOpacity(0x00);
popup_->SetContentsView(view_);
#if defined(USE_ASH)
ash::wm::GetWindowState(popup_->GetNativeWindow())->
set_ignored_by_shelf(true);
#endif
RepositionPopup();
}
}
......
......@@ -147,7 +147,7 @@ class EscapeTracker : public ui::EventHandler {
public:
explicit EscapeTracker(const base::Closure& callback)
: escape_callback_(callback),
event_monitor_(views::EventMonitor::Create(this)) {
event_monitor_(views::EventMonitor::CreateApplicationMonitor(this)) {
}
private:
......
......@@ -72,6 +72,8 @@ EventGeneratorDelegateAura::~EventGeneratorDelegateAura() {
ui::EventTarget* EventGeneratorDelegateAura::GetTargetAt(
const gfx::Point& location) {
// TODO(andresantoso): Add support for EventGenerator::targeting_application()
// if needed for Ash.
return GetHostAt(location)->window();
}
......
......@@ -66,6 +66,7 @@ EventGenerator::EventGenerator(gfx::NativeWindow root_window)
flags_(0),
grab_(false),
async_(false),
targeting_application_(false),
tick_clock_(new base::DefaultTickClock()) {
Init(root_window, NULL);
}
......@@ -77,6 +78,7 @@ EventGenerator::EventGenerator(gfx::NativeWindow root_window,
flags_(0),
grab_(false),
async_(false),
targeting_application_(false),
tick_clock_(new base::DefaultTickClock()) {
Init(root_window, NULL);
}
......@@ -87,6 +89,7 @@ EventGenerator::EventGenerator(gfx::NativeWindow root_window,
flags_(0),
grab_(false),
async_(false),
targeting_application_(false),
tick_clock_(new base::DefaultTickClock()) {
Init(root_window, window);
}
......@@ -97,6 +100,7 @@ EventGenerator::EventGenerator(EventGeneratorDelegate* delegate)
flags_(0),
grab_(false),
async_(false),
targeting_application_(false),
tick_clock_(new base::DefaultTickClock()) {
Init(NULL, NULL);
}
......
......@@ -129,6 +129,13 @@ class EventGenerator {
void set_async(bool async) { async_ = async; }
bool async() const { return async_; }
// Dispatch events through the application instead of directly to the
// target window. Currently only supported on Mac.
void set_targeting_application(bool targeting_application) {
targeting_application_ = targeting_application;
}
bool targeting_application() const { return targeting_application_; }
// Resets the event flags bitmask.
void set_flags(int flags) { flags_ = flags; }
int flags() const { return flags_; }
......@@ -383,6 +390,7 @@ class EventGenerator {
std::list<Event*> pending_events_;
// Set to true to cause events to be posted asynchronously.
bool async_;
bool targeting_application_;
scoped_ptr<base::TickClock> tick_clock_;
DISALLOW_COPY_AND_ASSIGN(EventGenerator);
......
......@@ -5,7 +5,9 @@
#ifndef UI_VIEWS_EVENT_MONITOR_H_
#define UI_VIEWS_EVENT_MONITOR_H_
#include "base/memory/scoped_ptr.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/views_export.h"
namespace ui {
......@@ -14,13 +16,25 @@ class EventHandler;
namespace views {
// RAII-style class that forwards events posted to the application to
// |event_handler| before they are dispatched.
// RAII-style class that forwards events to |event_handler| before they are
// dispatched.
class VIEWS_EXPORT EventMonitor {
public:
virtual ~EventMonitor() {}
static EventMonitor* Create(ui::EventHandler* event_handler);
// Create an instance for monitoring application events.
// Events will be forwarded to |event_handler| before they are dispatched to
// the application.
static scoped_ptr<EventMonitor> CreateApplicationMonitor(
ui::EventHandler* event_handler);
// Create an instance for monitoring events on a specific window.
// Events will be forwarded to |event_handler| before they are dispatched to
// |target_window|.
// The EventMonitor instance must be destroyed before |target_window|.
static scoped_ptr<EventMonitor> CreateWindowMonitor(
ui::EventHandler* event_handler,
gfx::NativeWindow target_window);
// Returns the last mouse location seen in a mouse event in screen
// coordinates.
......
......@@ -6,12 +6,24 @@
#include "base/logging.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/events/event_target.h"
namespace views {
// static
EventMonitor* EventMonitor::Create(ui::EventHandler* event_handler) {
return new EventMonitorAura(event_handler);
scoped_ptr<EventMonitor> EventMonitor::CreateApplicationMonitor(
ui::EventHandler* event_handler) {
return scoped_ptr<EventMonitor>(
new EventMonitorAura(event_handler, aura::Env::GetInstance()));
}
// static
scoped_ptr<EventMonitor> EventMonitor::CreateWindowMonitor(
ui::EventHandler* event_handler,
gfx::NativeWindow target_window) {
return scoped_ptr<EventMonitor>(
new EventMonitorAura(event_handler, target_window));
}
// static
......@@ -19,14 +31,16 @@ gfx::Point EventMonitor::GetLastMouseLocation() {
return aura::Env::GetInstance()->last_mouse_location();
}
EventMonitorAura::EventMonitorAura(ui::EventHandler* event_handler)
: event_handler_(event_handler) {
EventMonitorAura::EventMonitorAura(ui::EventHandler* event_handler,
ui::EventTarget* event_target)
: event_handler_(event_handler), event_target_(event_target) {
DCHECK(event_handler_);
aura::Env::GetInstance()->AddPreTargetHandler(event_handler_);
DCHECK(event_target_);
event_target_->AddPreTargetHandler(event_handler_);
}
EventMonitorAura::~EventMonitorAura() {
aura::Env::GetInstance()->RemovePreTargetHandler(event_handler_);
event_target_->RemovePreTargetHandler(event_handler_);
}
} // namespace views
......@@ -8,15 +8,21 @@
#include "base/macros.h"
#include "ui/views/event_monitor.h"
namespace ui {
class EventTarget;
}
namespace views {
class EventMonitorAura : public EventMonitor {
public:
explicit EventMonitorAura(ui::EventHandler* event_handler);
EventMonitorAura(ui::EventHandler* event_handler,
ui::EventTarget* event_target);
virtual ~EventMonitorAura();
private:
ui::EventHandler* event_handler_; // Weak. Owned by our owner.
ui::EventTarget* event_target_; // Weak.
DISALLOW_COPY_AND_ASSIGN(EventMonitorAura);
};
......
......@@ -6,15 +6,15 @@
#define UI_VIEWS_EVENT_MONITOR_MAC_H_
#include "base/macros.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/event_monitor.h"
#import <Cocoa/Cocoa.h>
namespace views {
class EventMonitorMac : public EventMonitor {
public:
explicit EventMonitorMac(ui::EventHandler* event_handler);
EventMonitorMac(ui::EventHandler* event_handler,
gfx::NativeWindow target_window);
virtual ~EventMonitorMac();
private:
......
......@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/event_monitor_mac.h"
#import "ui/views/event_monitor_mac.h"
#import <Cocoa/Cocoa.h>
#include "base/logging.h"
#include "ui/events/event.h"
......@@ -12,8 +14,17 @@
namespace views {
// static
EventMonitor* EventMonitor::Create(ui::EventHandler* event_handler) {
return new EventMonitorMac(event_handler);
scoped_ptr<EventMonitor> EventMonitor::CreateApplicationMonitor(
ui::EventHandler* event_handler) {
return scoped_ptr<EventMonitor>(new EventMonitorMac(event_handler, nullptr));
}
// static
scoped_ptr<EventMonitor> EventMonitor::CreateWindowMonitor(
ui::EventHandler* event_handler,
gfx::NativeWindow target_window) {
return scoped_ptr<EventMonitor>(
new EventMonitorMac(event_handler, target_window));
}
// static
......@@ -25,14 +36,17 @@ gfx::Point EventMonitor::GetLastMouseLocation() {
return gfx::Point(mouseLocation.x, mouseLocation.y);
}
EventMonitorMac::EventMonitorMac(ui::EventHandler* event_handler) {
EventMonitorMac::EventMonitorMac(ui::EventHandler* event_handler,
gfx::NativeWindow target_window) {
DCHECK(event_handler);
monitor_ = [NSEvent addLocalMonitorForEventsMatchingMask:NSAnyEventMask
handler:^NSEvent*(NSEvent* event){
scoped_ptr<ui::Event> ui_event = ui::EventFromNative(event);
event_handler->OnEvent(ui_event.get());
return event;
}];
handler:^NSEvent*(NSEvent* event) {
if (!target_window || [event window] == target_window) {
scoped_ptr<ui::Event> ui_event = ui::EventFromNative(event);
event_handler->OnEvent(ui_event.get());
}
return event;
}];
}
EventMonitorMac::~EventMonitorMac() {
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/event_monitor_mac.h"
#include "ui/events/event.h"
#include "ui/events/event_handler.h"
#include "ui/events/event_constants.h"
#import "ui/events/test/cocoa_test_event_utils.h"
#import "ui/gfx/test/ui_cocoa_test_helper.h"
namespace views {
namespace {
class EventMonitorMacTest : public ui::CocoaTest {
public:
EventMonitorMacTest() {}
private:
DISALLOW_COPY_AND_ASSIGN(EventMonitorMacTest);
};
class EventCounter : public ui::EventHandler {
public:
EventCounter() : event_count_(0), last_event_type_(ui::ET_UNKNOWN) {}
int event_count() const { return event_count_; }
ui::EventType last_event_type() { return last_event_type_; }
// ui::EventHandler implementation:
virtual void OnEvent(ui::Event* event) override {
++event_count_;
last_event_type_ = event->type();
}
private:
int event_count_;
ui::EventType last_event_type_;
};
} // namespace
TEST_F(EventMonitorMacTest, CountEvents) {
EventCounter counter;
NSEvent* event =
cocoa_test_event_utils::EnterExitEventWithType(NSMouseExited);
// No monitor installed yet, should not receive events.
[NSApp sendEvent:event];
EXPECT_EQ(0, counter.event_count());
EXPECT_EQ(ui::ET_UNKNOWN, counter.last_event_type());
// Install monitor, should start receiving event.
scoped_ptr<EventMonitor> event_monitor(EventMonitor::Create(&counter));
[NSApp sendEvent:event];
EXPECT_EQ(1, counter.event_count());
EXPECT_EQ(ui::ET_MOUSE_EXITED, counter.last_event_type());
// Uninstall monitor, should stop receiving events.
event_monitor.reset();
[NSApp sendEvent:event];
EXPECT_EQ(1, counter.event_count());
EXPECT_EQ(ui::ET_MOUSE_EXITED, counter.last_event_type());
}
} // namespace views
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/events/test/event_generator.h"
#include "ui/events/test/test_event_handler.h"
#include "ui/views/event_monitor.h"
#include "ui/views/test/widget_test.h"
namespace views {
namespace test {
class EventMonitorTest : public WidgetTest {
public:
EventMonitorTest() : widget_(nullptr) {}
// testing::Test:
void SetUp() override {
WidgetTest::SetUp();
widget_ = CreateTopLevelNativeWidget();
widget_->SetSize(gfx::Size(100, 100));
widget_->Show();
generator_.reset(
new ui::test::EventGenerator(GetContext(), widget_->GetNativeWindow()));
generator_->set_targeting_application(true);
}
void TearDown() override {
widget_->CloseNow();
WidgetTest::TearDown();
}
protected:
Widget* widget_;
scoped_ptr<ui::test::EventGenerator> generator_;
ui::test::TestEventHandler handler_;
private:
DISALLOW_COPY_AND_ASSIGN(EventMonitorTest);
};
TEST_F(EventMonitorTest, ShouldReceiveAppEventsWhileInstalled) {
scoped_ptr<EventMonitor> monitor(
EventMonitor::CreateApplicationMonitor(&handler_));
generator_->ClickLeftButton();
EXPECT_EQ(2, handler_.num_mouse_events());
monitor.reset();
generator_->ClickLeftButton();
EXPECT_EQ(2, handler_.num_mouse_events());
}
TEST_F(EventMonitorTest, ShouldReceiveWindowEventsWhileInstalled) {
scoped_ptr<EventMonitor> monitor(
EventMonitor::CreateWindowMonitor(&handler_, widget_->GetNativeWindow()));
generator_->ClickLeftButton();
EXPECT_EQ(2, handler_.num_mouse_events());
monitor.reset();
generator_->ClickLeftButton();
EXPECT_EQ(2, handler_.num_mouse_events());
}
TEST_F(EventMonitorTest, ShouldNotReceiveEventsFromOtherWindow) {
Widget* widget2 = CreateTopLevelNativeWidget();
scoped_ptr<EventMonitor> monitor(
EventMonitor::CreateWindowMonitor(&handler_, widget2->GetNativeWindow()));
generator_->ClickLeftButton();
EXPECT_EQ(0, handler_.num_mouse_events());
monitor.reset();
widget2->CloseNow();
}
} // namespace test
} // namespace views
......@@ -25,7 +25,7 @@ class MouseWatcher::Observer : public ui::EventHandler {
public:
explicit Observer(MouseWatcher* mouse_watcher)
: mouse_watcher_(mouse_watcher),
event_monitor_(views::EventMonitor::Create(this)),
event_monitor_(EventMonitor::CreateApplicationMonitor(this)),
notify_listener_factory_(this) {
}
......
......@@ -28,6 +28,9 @@ ui::test::EventGenerator* g_active_generator = NULL;
// Donate +[NSEvent pressedMouseButtons] by retrieving the flags from the
// active generator.
+ (NSUInteger)pressedMouseButtons {
if (!g_active_generator)
return [NSEventDonor pressedMouseButtons]; // Call original implementation.
int flags = g_active_generator->flags();
NSUInteger bitmask = 0;
if (flags & ui::EF_LEFT_MOUSE_BUTTON)
......@@ -197,10 +200,10 @@ void EmulateSendEvent(NSWindow* window, NSEvent* event) {
}
}
void DispatchMouseEventInWindow(NSWindow* window,
ui::EventType event_type,
const gfx::Point& point_in_root,
int flags) {
NSEvent* CreateMouseEventInWindow(NSWindow* window,
ui::EventType event_type,
const gfx::Point& point_in_root,
int flags) {
NSUInteger click_count = 0;
if (event_type == ui::ET_MOUSE_PRESSED ||
event_type == ui::ET_MOUSE_RELEASED) {
......@@ -214,19 +217,15 @@ void DispatchMouseEventInWindow(NSWindow* window,
NSPoint point = ConvertRootPointToTarget(window, point_in_root);
NSUInteger modifiers = 0;
NSEventType type = EventTypeToNative(event_type, flags, &modifiers);
NSEvent* event = [NSEvent mouseEventWithType:type
location:point
modifierFlags:modifiers
timestamp:0
windowNumber:[window windowNumber]
context:nil
eventNumber:0
clickCount:click_count
pressure:1.0];
// Typically events go through NSApplication. For tests, dispatch the event
// directly to make things more predicatble.
EmulateSendEvent(window, event);
return [NSEvent mouseEventWithType:type
location:point
modifierFlags:modifiers
timestamp:0
windowNumber:[window windowNumber]
context:nil
eventNumber:0
clickCount:click_count
pressure:1.0];
}
// Implementation of ui::test::EventGeneratorDelegate for Mac. Everything
......@@ -319,10 +318,14 @@ EventGeneratorDelegateMac::GetChildIterator() const {
void EventGeneratorDelegateMac::OnMouseEvent(ui::MouseEvent* event) {
// For mouse drag events, ensure the swizzled methods return the right flags.
base::AutoReset<ui::test::EventGenerator*> reset(&g_active_generator, owner_);
DispatchMouseEventInWindow(window_,
event->type(),
event->location(),
event->changed_button_flags());
NSEvent* ns_event = CreateMouseEventInWindow(window_,
event->type(),
event->location(),
event->changed_button_flags());
if (owner_->targeting_application())
[NSApp sendEvent:ns_event];
else
EmulateSendEvent(window_, ns_event);
}
void EventGeneratorDelegateMac::SetContext(ui::test::EventGenerator* owner,
......
......@@ -537,7 +537,7 @@
'controls/textfield/textfield_unittest.cc',
'controls/textfield/textfield_model_unittest.cc',
'controls/tree/tree_view_unittest.cc',
'event_monitor_mac_unittest.mm',
'event_monitor_unittest.cc',
'focus/focus_manager_unittest.cc',
'focus/focus_traversal_unittest.cc',
'ime/input_method_bridge_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment