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

Unified Diff: ui/views/cocoa/cocoa_non_client_drag.mm

Issue 1146873002: [MacViews] Enable dragging a window by its caption/draggable areas. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update comments. Created 5 years, 7 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/views/cocoa/cocoa_non_client_drag.mm
diff --git a/ui/views/cocoa/cocoa_non_client_drag.mm b/ui/views/cocoa/cocoa_non_client_drag.mm
new file mode 100644
index 0000000000000000000000000000000000000000..917bdc65a72c819a649577eaf343da8e00f521ed
--- /dev/null
+++ b/ui/views/cocoa/cocoa_non_client_drag.mm
@@ -0,0 +1,160 @@
+// Copyright 2015 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.
+
+#import "ui/views/cocoa/cocoa_non_client_drag.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/logging.h"
+#import "base/mac/foundation_util.h"
+#include "base/process/process_handle.h"
+
+@implementation CocoaNonClientDragMaskView
+
+- (BOOL)mouseDownCanMoveWindow {
+ return NO;
+}
+
+- (NSView*)hitTest:(NSPoint)aPoint {
+ return nil;
+}
+
+@end
+
+namespace views {
+
+namespace {
+
+int g_ref_count = 0;
+CGEventRef g_last_reposted_event = 0;
+
+CFRunLoopSourceRef g_run_loop_source = 0;
+CFMachPortRef g_mach_port = 0;
+
+id g_event_monitor = nil;
+
+bool RepostEventIfHandledByWindow(NSWindow* window,
+ NSPoint location,
+ CGEventRef event) {
+ if ([window respondsToSelector:@selector(willReceiveLeftMouseDown:)] &&
+ [base::mac::ObjCCast<NativeWidgetMacNSWindow>(window)
+ willReceiveLeftMouseDown:location]) {
+ if (g_last_reposted_event != event) {
+ g_last_reposted_event = event;
+ CGEventPost(kCGSessionEventTap, event); // Repost event.
+ } else {
+ LOG(INFO) << "reposting already reposted event " << event;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+CGEventRef EventTapCallBack(CGEventTapProxy proxy,
+ CGEventType type,
+ CGEventRef cg_event,
+ void* refcon) {
+ LOG(INFO) << "EventTapCallBack " << cg_event;
+ // Disable CGEventTap mechanism.
+ return cg_event;
+
+ pid_t target_pid =
+ CGEventGetIntegerValueField(cg_event, kCGEventTargetUnixProcessID);
+ if (base::GetCurrentProcId() != target_pid)
+ return cg_event;
+
+ if (type != kCGEventLeftMouseDown)
+ return cg_event;
+
+ NSPoint location = NSPointFromCGPoint(CGEventGetUnflippedLocation(cg_event));
+
+ // Find the window this event lands on.
+ NSWindow* target = nil;
+ for (NSWindow* window in [NSApp windows]) {
+ if (NSPointInRect(location, [window frame])) {
+ target = window;
+ break;
+ }
+ }
+ if (!target)
+ return cg_event;
+
+ if (RepostEventIfHandledByWindow(
+ target, [target convertScreenToBase:location], cg_event)) {
+ return nil;
+ }
+
+ return cg_event;
+}
+
+} // namespace
+
+CocoaNonClientDrag::CocoaNonClientDrag() {
+ if (g_ref_count)
+ return;
+
+////////////////////////////////////////////////////////////////////////////////
+// CGEventTap setup.
+ if (!g_mach_port) {
+ // We cant use kCGAnnotatedSessionEventTap or CGEventTapCreateForPSN because
+ // they both happen after window movement happens.
+ g_mach_port = CGEventTapCreate(
+ kCGSessionEventTap, // After event has been annotated to flow to an
+ // application.
+ kCGHeadInsertEventTap,
+ kCGEventTapOptionDefault, // An active listener, can swallow events.
+ 1 << kCGEventLeftMouseDown, &EventTapCallBack, NULL);
+ }
+ if (!g_run_loop_source)
+ g_run_loop_source = CFMachPortCreateRunLoopSource(NULL, g_mach_port, 0);
+
+ CFRunLoopAddSource(CFRunLoopGetMain(), g_run_loop_source,
+ kCFRunLoopCommonModes);
+ CGEventTapEnable(g_mach_port, true);
+//
+////////////////////////////////////////////////////////////////////////////////
+// NSEvent local monitor setup.
+ NSEvent* (^monitor_callback)(NSEvent* ns_event);
+ monitor_callback = ^NSEvent*(NSEvent* ns_event) {
+ CGEventRef cg_event = [ns_event CGEvent];
+ LOG(INFO) << "MonitorCallback " << cg_event;
+ if (RepostEventIfHandledByWindow([ns_event window],
+ [ns_event locationInWindow],
+ cg_event)) {
+ return nil;
+ }
+ return ns_event;
+ };
+
+ g_event_monitor =
+ [NSEvent addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask
+ handler:monitor_callback];
+//
+////////////////////////////////////////////////////////////////////////////////
+
+ ++g_ref_count;
+}
+
+CocoaNonClientDrag::~CocoaNonClientDrag() {
+ --g_ref_count;
+ if (g_ref_count)
+ return;
+
+////////////////////////////////////////////////////////////////////////////////
+// CGEventTap cleanup.
+ CFRunLoopRemoveSource(CFRunLoopGetMain(), g_run_loop_source,
+ kCFRunLoopCommonModes);
+//
+////////////////////////////////////////////////////////////////////////////////
+// NSEvent local monitor cleanup.
+ if (g_event_monitor) {
+ [NSEvent removeMonitor:g_event_monitor];
+ g_event_monitor = nil;
+ }
+//
+////////////////////////////////////////////////////////////////////////////////
+}
+
+} // namespace views

Powered by Google App Engine
This is Rietveld 408576698