Commit 354a8f276e25f9182f758fd3cf672064bc12b9bc

Sam Lantinga 2016-11-26T10:26:22

SDL for Mac - only enable global event tap when actually necessary (app has focus and has requested relative mouse mode or has asked for a mouse grab). in other situations the event tap impacts system performance and battery life with no benefit.

diff --git a/src/video/cocoa/SDL_cocoamousetap.h b/src/video/cocoa/SDL_cocoamousetap.h
index af92314..795248a 100644
--- a/src/video/cocoa/SDL_cocoamousetap.h
+++ b/src/video/cocoa/SDL_cocoamousetap.h
@@ -26,6 +26,7 @@
 #include "SDL_cocoamouse.h"
 
 extern void Cocoa_InitMouseEventTap(SDL_MouseData *driverdata);
+extern void Cocoa_EnableMouseEventTap(SDL_MouseData *driverdata, SDL_bool enabled);
 extern void Cocoa_QuitMouseEventTap(SDL_MouseData *driverdata);
 
 #endif /* _SDL_cocoamousetap_h */
diff --git a/src/video/cocoa/SDL_cocoamousetap.m b/src/video/cocoa/SDL_cocoamousetap.m
index 48abbca..a36e423 100644
--- a/src/video/cocoa/SDL_cocoamousetap.m
+++ b/src/video/cocoa/SDL_cocoamousetap.m
@@ -142,15 +142,12 @@ Cocoa_MouseTapThread(void *data)
 {
     SDL_MouseEventTapData *tapdata = (SDL_MouseEventTapData*)data;
 
-    /* Create a tap. */
-    CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap,
-                                              kCGEventTapOptionDefault, allGrabbedEventsMask,
-                                              &Cocoa_MouseTapCallback, tapdata);
+    /* Tap was created on main thread but we own it now. */
+    CFMachPortRef eventTap = tapdata->tap;
     if (eventTap) {
         /* Try to create a runloop source we can schedule. */
         CFRunLoopSourceRef runloopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
         if  (runloopSource) {
-            tapdata->tap = eventTap;
             tapdata->runloopSource = runloopSource;
         } else {
             CFRelease(eventTap);
@@ -202,15 +199,30 @@ Cocoa_InitMouseEventTap(SDL_MouseData* driverdata)
 
     tapdata->runloopStartedSemaphore = SDL_CreateSemaphore(0);
     if (tapdata->runloopStartedSemaphore) {
-        tapdata->thread = SDL_CreateThreadInternal(&Cocoa_MouseTapThread, "Event Tap Loop", 512 * 1024, tapdata);
-        if (!tapdata->thread) {
-            SDL_DestroySemaphore(tapdata->runloopStartedSemaphore);
+        tapdata->tap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap,
+                                        kCGEventTapOptionDefault, allGrabbedEventsMask,
+                                        &Cocoa_MouseTapCallback, tapdata);
+        if (tapdata->tap) {
+            tapdata->thread = SDL_CreateThreadInternal(&Cocoa_MouseTapThread, "Event Tap Loop", 512 * 1024, tapdata);
+            if (tapdata->thread) {
+                /* Success - early out. Ownership transferred to thread. */
+            	return;
+            }
+            CFRelease(tapdata->tap);
         }
+        SDL_DestroySemaphore(tapdata->runloopStartedSemaphore);
     }
+    SDL_free(driverdata->tapdata);
+    driverdata->tapdata = NULL;
+}
 
-    if (!tapdata->thread) {
-        SDL_free(driverdata->tapdata);
-        driverdata->tapdata = NULL;
+void
+Cocoa_EnableMouseEventTap(SDL_MouseData *driverdata, SDL_bool enabled)
+{
+    SDL_MouseEventTapData *tapdata = (SDL_MouseEventTapData*)driverdata->tapdata;
+    if (tapdata && tapdata->tap)
+    {
+        CGEventTapEnable(tapdata->tap, enabled);
     }
 }
 
@@ -246,6 +258,11 @@ Cocoa_InitMouseEventTap(SDL_MouseData *unused)
 }
 
 void
+Cocoa_EnableMouseEventTap(SDL_MouseData *driverdata, SDL_bool enabled)
+{
+}
+
+void
 Cocoa_QuitMouseEventTap(SDL_MouseData *driverdata)
 {
 }
diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m
index cfad548..f705a6c 100644
--- a/src/video/cocoa/SDL_cocoawindow.m
+++ b/src/video/cocoa/SDL_cocoawindow.m
@@ -38,6 +38,7 @@
 #include "SDL_cocoavideo.h"
 #include "SDL_cocoashape.h"
 #include "SDL_cocoamouse.h"
+#include "SDL_cocoamousetap.h"
 #include "SDL_cocoaopengl.h"
 #include "SDL_assert.h"
 
@@ -1634,8 +1635,13 @@ Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
 void
 Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
 {
-    /* Move the cursor to the nearest point in the window */
+    SDL_Mouse *mouse = SDL_GetMouse();
     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+
+    /* Enable or disable the event tap as necessary */
+    Cocoa_EnableMouseEventTap(mouse->driverdata, grabbed);
+
+    /* Move the cursor to the nearest point in the window */
     if (grabbed && data && ![data->listener isMoving]) {
         int x, y;
         CGPoint cgpoint;