Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(855)

Unified Diff: ui/base/test/ui_controls_mac.mm

Issue 1747803003: MacViews: Implement Tab Dragging (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/base/test/ui_controls_mac.mm
diff --git a/ui/base/test/ui_controls_mac.mm b/ui/base/test/ui_controls_mac.mm
index 15cdb7963b019d11df0e749c13239fb6a40faafe..dad3ad1f9ebacd185ddadc516bc15ad4f187371b 100644
--- a/ui/base/test/ui_controls_mac.mm
+++ b/ui/base/test/ui_controls_mac.mm
@@ -9,9 +9,15 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/mac/scoped_objc_class_swizzler.h"
#include "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
#include "ui/events/keycodes/keyboard_code_conversion_mac.h"
#import "ui/events/test/cocoa_test_event_utils.h"
+#include "ui/gfx/mac/coordinate_conversion.h"
+#include "ui/gfx/screen.h"
// Implementation details: We use [NSApplication sendEvent:] instead
// of [NSApplication postEvent:atStart:] so that the event gets sent
@@ -50,6 +56,7 @@ namespace {
// Stores the current mouse location on the screen. So that we can use it
// when firing keyboard and mouse click events.
NSPoint g_mouse_location = { 0, 0 };
+bool g_mouse_button_down[3] = { false, false, false };
tapted 2016/03/01 08:11:58 comment (mention that it's indexed by ui_controls:
themblsha 2016/03/09 17:40:22 Done.
bool g_ui_controls_enabled = false;
@@ -172,6 +179,83 @@ NSWindow* WindowAtCurrentMouseLocation() {
} // namespace
+namespace {
+int kEventDeletedTaskRunnerKey;
tapted 2016/03/01 08:11:58 can be merged with the namespace above. needs a co
themblsha 2016/03/09 17:40:22 Done.
+} // namespace
+
+@interface EventDeletedTaskRunner : NSObject {
tapted 2016/03/01 08:11:58 What's the reason why EventQueueWatcher couldn't s
themblsha 2016/03/01 18:41:53 I'm spawning these on a separate thread, as the ma
+ @private
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ base::Closure finish_closure_;
+}
+- (id)initWithClosure:(const base::Closure&)task;
+@end
+
+@implementation EventDeletedTaskRunner
+- (id)initWithClosure:(const base::Closure&)task {
+ if (self = [super init]) {
+ task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ finish_closure_ = task;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ task_runner_->PostTask(FROM_HERE, finish_closure_);
+ [super dealloc];
+}
+@end
+
+// Donates testing implementations of NSEvent methods.
+@interface FakeNSEventTestingDonor : NSObject
+@end
+
+@implementation FakeNSEventTestingDonor
++ (NSPoint)mouseLocation {
+ return g_mouse_location;
+}
+
++ (NSUInteger)pressedMouseButtons {
+ NSUInteger result = 0;
+ const int buttons[3] = {
+ ui_controls::LEFT, ui_controls::RIGHT, ui_controls::MIDDLE};
+ for (unsigned int i = 0; i < arraysize(buttons); ++i) {
+ if (g_mouse_button_down[buttons[i]])
+ result |= (1 << i);
+ }
+ return result;
+}
+@end
+
+namespace {
+class ScopedNSEventSwizzler {
+ public:
+ static void Install() {
+ static ScopedNSEventSwizzler* swizzler = nullptr;
+ if (!swizzler) {
+ swizzler = new ScopedNSEventSwizzler();
+ }
+ }
+
+ protected:
+ ScopedNSEventSwizzler()
+ : mouse_location_swizzler_(new base::mac::ScopedObjCClassSwizzler(
+ [NSEvent class],
+ [FakeNSEventTestingDonor class],
+ @selector(mouseLocation))),
+ pressed_mouse_buttons_swizzler_(new base::mac::ScopedObjCClassSwizzler(
+ [NSEvent class],
+ [FakeNSEventTestingDonor class],
+ @selector(pressedMouseButtons))) {
+ }
+
+ private:
+ scoped_ptr<base::mac::ScopedObjCClassSwizzler> mouse_location_swizzler_;
+ scoped_ptr<base::mac::ScopedObjCClassSwizzler>
+ pressed_mouse_buttons_swizzler_;
+};
+} // namespace
+
namespace ui_controls {
void EnableUIControls() {
@@ -202,10 +286,24 @@ bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
CHECK(g_ui_controls_enabled);
DCHECK(base::MessageLoopForUI::IsCurrent());
+ // we want to destroy the autoreleased event ASAP
tapted 2016/03/01 08:11:58 Comments should all be complete sentences. Capital
themblsha 2016/03/09 17:40:22 Done.
+ base::mac::ScopedNSAutoreleasePool pool;
+
std::vector<NSEvent*> events;
SynthesizeKeyEventsSequence(
window, key, control, shift, alt, command, &events);
+ if (!task.is_null()) {
+ base::scoped_nsobject<EventDeletedTaskRunner> task_runner =
+ [[EventDeletedTaskRunner alloc] initWithClosure:task];
+
+ // event will be deleted when the last event is deleted
+ for (std::vector<NSEvent*>::iterator iter = events.begin();
tapted 2016/03/01 08:11:58 for (NSEvent* event : events)
+ iter != events.end(); ++iter)
+ objc_setAssociatedObject(*iter, &kEventDeletedTaskRunnerKey,
+ task_runner.get(), OBJC_ASSOCIATION_RETAIN);
+ }
+
// TODO(suzhe): Using [NSApplication postEvent:atStart:] here causes
// BrowserKeyEventsTest.CommandKeyEvents to fail. See http://crbug.com/49270
// But using [NSApplication sendEvent:] should be safe for keyboard events,
@@ -215,11 +313,6 @@ bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
iter != events.end(); ++iter)
[[NSApplication sharedApplication] sendEvent:*iter];
- if (!task.is_null()) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&EventQueueWatcher, task));
- }
-
return true;
}
@@ -234,9 +327,8 @@ bool SendMouseMove(long x, long y) {
// platforms. E.g. (0,0) is upper-left.
bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) {
CHECK(g_ui_controls_enabled);
- CGFloat screenHeight =
- [[[NSScreen screens] firstObject] frame].size.height;
- g_mouse_location = NSMakePoint(x, screenHeight - y); // flip!
+ g_mouse_location = gfx::ScreenPointToNSPoint(gfx::Point(x, y)); // flip!
+ ScopedNSEventSwizzler::Install();
NSWindow* window = WindowAtCurrentMouseLocation();
@@ -245,23 +337,37 @@ bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) {
pointInWindow = [window convertScreenToBase:pointInWindow];
NSTimeInterval timestamp = TimeIntervalSinceSystemStartup();
- NSEvent* event =
- [NSEvent mouseEventWithType:NSMouseMoved
- location:pointInWindow
- modifierFlags:0
- timestamp:timestamp
- windowNumber:[window windowNumber]
- context:nil
- eventNumber:0
- clickCount:0
- pressure:0.0];
- [[NSApplication sharedApplication] postEvent:event atStart:NO];
+ NSEventType etype = NSMouseMoved;
tapted 2016/03/01 08:11:58 etype -> event_type
themblsha 2016/03/09 17:40:22 Done.
+ if (g_mouse_button_down[LEFT]) {
+ etype = NSLeftMouseDragged;
+ } else if (g_mouse_button_down[RIGHT]) {
+ etype = NSRightMouseDragged;
+ } else if (g_mouse_button_down[MIDDLE]) {
+ etype = NSOtherMouseDragged;
+ }
+
+ // we want to destroy the autoreleased event ASAP
+ base::mac::ScopedNSAutoreleasePool pool;
+
+ NSEvent* event = [NSEvent mouseEventWithType:etype
+ location:pointInWindow
+ modifierFlags:0
+ timestamp:timestamp
+ windowNumber:[window windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:0
+ pressure:0.0];
if (!task.is_null()) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&EventQueueWatcher, task));
+ base::scoped_nsobject<EventDeletedTaskRunner> task_runner =
+ [[EventDeletedTaskRunner alloc] initWithClosure:task];
+ objc_setAssociatedObject(event, &kEventDeletedTaskRunnerKey,
+ task_runner.get(), OBJC_ASSOCIATION_RETAIN);
}
+ [[NSApplication sharedApplication] postEvent:event atStart:NO];
+
return true;
}
@@ -283,20 +389,26 @@ bool SendMouseEventsNotifyWhenDone(MouseButton type, int state,
if (type == LEFT) {
if (state == UP) {
etype = NSLeftMouseUp;
+ g_mouse_button_down[LEFT] = false;
} else {
etype = NSLeftMouseDown;
+ g_mouse_button_down[LEFT] = true;
}
} else if (type == MIDDLE) {
if (state == UP) {
etype = NSOtherMouseUp;
+ g_mouse_button_down[MIDDLE] = false;
} else {
etype = NSOtherMouseDown;
+ g_mouse_button_down[MIDDLE] = true;
}
} else if (type == RIGHT) {
if (state == UP) {
etype = NSRightMouseUp;
+ g_mouse_button_down[RIGHT] = false;
} else {
etype = NSRightMouseDown;
+ g_mouse_button_down[RIGHT] = true;
tapted 2016/03/01 08:11:58 these can all be collapsed into g_mouse_button_do
themblsha 2016/03/09 17:40:22 Done.
}
} else {
return false;
@@ -306,6 +418,11 @@ bool SendMouseEventsNotifyWhenDone(MouseButton type, int state,
if (window)
pointInWindow = [window convertScreenToBase:pointInWindow];
+ ScopedNSEventSwizzler::Install();
+
+ // we want to destroy the autoreleased event ASAP
+ base::mac::ScopedNSAutoreleasePool pool;
+
NSEvent* event =
[NSEvent mouseEventWithType:etype
location:pointInWindow
@@ -316,13 +433,16 @@ bool SendMouseEventsNotifyWhenDone(MouseButton type, int state,
eventNumber:0
clickCount:1
pressure:(state == DOWN ? 1.0 : 0.0 )];
- [[NSApplication sharedApplication] postEvent:event atStart:NO];
if (!task.is_null()) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&EventQueueWatcher, task));
+ base::scoped_nsobject<EventDeletedTaskRunner> task_runner =
+ [[EventDeletedTaskRunner alloc] initWithClosure:task];
+ objc_setAssociatedObject(event, &kEventDeletedTaskRunnerKey,
+ task_runner.get(), OBJC_ASSOCIATION_RETAIN);
}
+ [[NSApplication sharedApplication] postEvent:event atStart:NO];
+
return true;
}

Powered by Google App Engine
This is Rietveld 408576698