| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2015 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 #import "ui/views/cocoa/cocoa_non_client_drag.h" |
| 6 |
| 7 #import <Cocoa/Cocoa.h> |
| 8 |
| 9 #include "base/logging.h" |
| 10 #import "base/mac/foundation_util.h" |
| 11 #include "base/process/process_handle.h" |
| 12 |
| 13 @implementation CocoaNonClientDragMaskView |
| 14 |
| 15 - (BOOL)mouseDownCanMoveWindow { |
| 16 return NO; |
| 17 } |
| 18 |
| 19 - (NSView*)hitTest:(NSPoint)aPoint { |
| 20 return nil; |
| 21 } |
| 22 |
| 23 @end |
| 24 |
| 25 namespace views { |
| 26 |
| 27 namespace { |
| 28 |
| 29 int g_ref_count = 0; |
| 30 CGEventRef g_last_reposted_event = 0; |
| 31 |
| 32 CFRunLoopSourceRef g_run_loop_source = 0; |
| 33 CFMachPortRef g_mach_port = 0; |
| 34 |
| 35 id g_event_monitor = nil; |
| 36 |
| 37 bool RepostEventIfHandledByWindow(NSWindow* window, |
| 38 NSPoint location, |
| 39 CGEventRef event) { |
| 40 if ([window respondsToSelector:@selector(willReceiveLeftMouseDown:)] && |
| 41 [base::mac::ObjCCast<NativeWidgetMacNSWindow>(window) |
| 42 willReceiveLeftMouseDown:location]) { |
| 43 if (g_last_reposted_event != event) { |
| 44 g_last_reposted_event = event; |
| 45 CGEventPost(kCGSessionEventTap, event); // Repost event. |
| 46 } else { |
| 47 LOG(INFO) << "reposting already reposted event " << event; |
| 48 } |
| 49 return true; |
| 50 } |
| 51 |
| 52 return false; |
| 53 } |
| 54 |
| 55 CGEventRef EventTapCallBack(CGEventTapProxy proxy, |
| 56 CGEventType type, |
| 57 CGEventRef cg_event, |
| 58 void* refcon) { |
| 59 LOG(INFO) << "EventTapCallBack " << cg_event; |
| 60 // Disable CGEventTap mechanism. |
| 61 return cg_event; |
| 62 |
| 63 pid_t target_pid = |
| 64 CGEventGetIntegerValueField(cg_event, kCGEventTargetUnixProcessID); |
| 65 if (base::GetCurrentProcId() != target_pid) |
| 66 return cg_event; |
| 67 |
| 68 if (type != kCGEventLeftMouseDown) |
| 69 return cg_event; |
| 70 |
| 71 NSPoint location = NSPointFromCGPoint(CGEventGetUnflippedLocation(cg_event)); |
| 72 |
| 73 // Find the window this event lands on. |
| 74 NSWindow* target = nil; |
| 75 for (NSWindow* window in [NSApp windows]) { |
| 76 if (NSPointInRect(location, [window frame])) { |
| 77 target = window; |
| 78 break; |
| 79 } |
| 80 } |
| 81 if (!target) |
| 82 return cg_event; |
| 83 |
| 84 if (RepostEventIfHandledByWindow( |
| 85 target, [target convertScreenToBase:location], cg_event)) { |
| 86 return nil; |
| 87 } |
| 88 |
| 89 return cg_event; |
| 90 } |
| 91 |
| 92 } // namespace |
| 93 |
| 94 CocoaNonClientDrag::CocoaNonClientDrag() { |
| 95 if (g_ref_count) |
| 96 return; |
| 97 |
| 98 //////////////////////////////////////////////////////////////////////////////// |
| 99 // CGEventTap setup. |
| 100 if (!g_mach_port) { |
| 101 // We cant use kCGAnnotatedSessionEventTap or CGEventTapCreateForPSN because |
| 102 // they both happen after window movement happens. |
| 103 g_mach_port = CGEventTapCreate( |
| 104 kCGSessionEventTap, // After event has been annotated to flow to an |
| 105 // application. |
| 106 kCGHeadInsertEventTap, |
| 107 kCGEventTapOptionDefault, // An active listener, can swallow events. |
| 108 1 << kCGEventLeftMouseDown, &EventTapCallBack, NULL); |
| 109 } |
| 110 if (!g_run_loop_source) |
| 111 g_run_loop_source = CFMachPortCreateRunLoopSource(NULL, g_mach_port, 0); |
| 112 |
| 113 CFRunLoopAddSource(CFRunLoopGetMain(), g_run_loop_source, |
| 114 kCFRunLoopCommonModes); |
| 115 CGEventTapEnable(g_mach_port, true); |
| 116 // |
| 117 //////////////////////////////////////////////////////////////////////////////// |
| 118 // NSEvent local monitor setup. |
| 119 NSEvent* (^monitor_callback)(NSEvent* ns_event); |
| 120 monitor_callback = ^NSEvent*(NSEvent* ns_event) { |
| 121 CGEventRef cg_event = [ns_event CGEvent]; |
| 122 LOG(INFO) << "MonitorCallback " << cg_event; |
| 123 if (RepostEventIfHandledByWindow([ns_event window], |
| 124 [ns_event locationInWindow], |
| 125 cg_event)) { |
| 126 return nil; |
| 127 } |
| 128 return ns_event; |
| 129 }; |
| 130 |
| 131 g_event_monitor = |
| 132 [NSEvent addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask |
| 133 handler:monitor_callback]; |
| 134 // |
| 135 //////////////////////////////////////////////////////////////////////////////// |
| 136 |
| 137 ++g_ref_count; |
| 138 } |
| 139 |
| 140 CocoaNonClientDrag::~CocoaNonClientDrag() { |
| 141 --g_ref_count; |
| 142 if (g_ref_count) |
| 143 return; |
| 144 |
| 145 //////////////////////////////////////////////////////////////////////////////// |
| 146 // CGEventTap cleanup. |
| 147 CFRunLoopRemoveSource(CFRunLoopGetMain(), g_run_loop_source, |
| 148 kCFRunLoopCommonModes); |
| 149 // |
| 150 //////////////////////////////////////////////////////////////////////////////// |
| 151 // NSEvent local monitor cleanup. |
| 152 if (g_event_monitor) { |
| 153 [NSEvent removeMonitor:g_event_monitor]; |
| 154 g_event_monitor = nil; |
| 155 } |
| 156 // |
| 157 //////////////////////////////////////////////////////////////////////////////// |
| 158 } |
| 159 |
| 160 } // namespace views |
| OLD | NEW |