From 9b44ce8935d2de362c074a1dd567dd2054790738 Mon Sep 17 00:00:00 2001 From: Chi-kwan Chan Date: Sun, 5 Apr 2015 22:58:39 -0400 Subject: [PATCH 1/2] Fix bug for fullscreen window on Yosemite with multiple monitors This is a quick-and-dirty fix to issue #492. It checks if window->monitor->ns.screen points to a valid screen, and update it when necessary. --- src/cocoa_window.m | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index b5bb4662a..5b08fe688 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -87,6 +87,32 @@ static GLboolean enterFullscreenMode(_GLFWwindow* window) status = _glfwSetVideoMode(window->monitor, &window->videoMode); + // NOTE: Apple's documentation of [NSScreen screens] mentions that, + // "The [screens] array should not be cached. Screens can be + // added, removed, or dynamically reconfigured at any time." + // Because of this, window->monitor->ns.screen may not point + // to a valid object so [window->monitor->ns.screen frame] + // used below can crash an application. The follow code + // provides a quick-and-dirty fix to this problem. + NSScreen *cached = window->monitor->ns.screen; + NSArray *current = [NSScreen screens]; + + bool updated = YES; + for (NSScreen *screen in current) + if (cached == screen) + updated = NO; + + if (updated) + for(NSScreen *screen in current) { + NSDictionary* dictionary = [screen deviceDescription]; + NSNumber *number = [dictionary objectForKey:@"NSScreenNumber"]; + if ([number unsignedIntegerValue] == + window->monitor->ns.displayID) { + window->monitor->ns.screen = screen; + break; + } + } + // NOTE: The window is resized despite mode setting failure to make // glfwSetWindowSize more robust [window->ns.object setFrame:[window->monitor->ns.screen frame] @@ -1286,4 +1312,3 @@ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle) _GLFW_REQUIRE_INIT_OR_RETURN(nil); return window->ns.object; } - From 676a9eafeebf43c5415615f836bbd9509a894c65 Mon Sep 17 00:00:00 2001 From: Chi-kwan Chan Date: Tue, 7 Apr 2015 21:02:48 -0400 Subject: [PATCH 2/2] Obtain screen object from displayID only when we need it Apple's documentation of [NSScreen screens] mentions that, "The (screens) array should not be cached. Screens can be added, removed, or dynamically reconfigured at any time." Because of this, we simply obtain the screen from a displayID whenever we need it. --- src/cocoa_init.m | 1 - src/cocoa_monitor.m | 2 -- src/cocoa_platform.h | 1 - src/cocoa_window.m | 53 ++++++++++++++++++++------------------------ 4 files changed, 24 insertions(+), 33 deletions(-) diff --git a/src/cocoa_init.m b/src/cocoa_init.m index 8779cdfab..06746d4c1 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -269,4 +269,3 @@ const char* _glfwPlatformGetVersionString(void) return version; } - diff --git a/src/cocoa_monitor.m b/src/cocoa_monitor.m index 50b72a4fb..14c7ed4b8 100644 --- a/src/cocoa_monitor.m +++ b/src/cocoa_monitor.m @@ -286,7 +286,6 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) monitor = _glfwAllocMonitor(name, size.width, size.height); monitor->ns.displayID = displays[i]; - monitor->ns.screen = [screens objectAtIndex:j]; free(name); @@ -427,4 +426,3 @@ GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle) _GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay); return monitor->ns.displayID; } - diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 7e131be66..32d1c213b 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -92,7 +92,6 @@ typedef struct _GLFWmonitorNS { CGDirectDisplayID displayID; CGDisplayModeRef previousMode; - id screen; } _GLFWmonitorNS; diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 5b08fe688..78a50eb9f 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -32,6 +32,27 @@ #include +// Returns the screen that is specified by a displayID +// +static NSScreen *getScreen(CGDirectDisplayID displayID) +{ + // NOTE: Apple's documentation of [NSScreen screens] mentions that, + // "The (screens) array should not be cached. Screens can be + // added, removed, or dynamically reconfigured at any time." + // Because of this, we simply obtain the screen from a + // displayID whenever we need it. + NSArray *screens = [NSScreen screens]; + + for(NSScreen *screen in screens) { + NSDictionary *dictionary = [screen deviceDescription]; + NSNumber *number = [dictionary objectForKey:@"NSScreenNumber"]; + if ([number unsignedIntegerValue] == displayID) + return screen; + } + + return nil; +} + // Returns the specified standard cursor // static NSCursor* getStandardCursor(int shape) @@ -87,36 +108,10 @@ static GLboolean enterFullscreenMode(_GLFWwindow* window) status = _glfwSetVideoMode(window->monitor, &window->videoMode); - // NOTE: Apple's documentation of [NSScreen screens] mentions that, - // "The [screens] array should not be cached. Screens can be - // added, removed, or dynamically reconfigured at any time." - // Because of this, window->monitor->ns.screen may not point - // to a valid object so [window->monitor->ns.screen frame] - // used below can crash an application. The follow code - // provides a quick-and-dirty fix to this problem. - NSScreen *cached = window->monitor->ns.screen; - NSArray *current = [NSScreen screens]; - - bool updated = YES; - for (NSScreen *screen in current) - if (cached == screen) - updated = NO; - - if (updated) - for(NSScreen *screen in current) { - NSDictionary* dictionary = [screen deviceDescription]; - NSNumber *number = [dictionary objectForKey:@"NSScreenNumber"]; - if ([number unsignedIntegerValue] == - window->monitor->ns.displayID) { - window->monitor->ns.screen = screen; - break; - } - } - // NOTE: The window is resized despite mode setting failure to make // glfwSetWindowSize more robust - [window->ns.object setFrame:[window->monitor->ns.screen frame] - display:YES]; + [window->ns.object setFrame:[getScreen(window->monitor->ns.displayID) frame] + display:YES]; return status; } @@ -864,7 +859,7 @@ static GLboolean createWindow(_GLFWwindow* window, NSRect contentRect; if (wndconfig->monitor) - contentRect = [wndconfig->monitor->ns.screen frame]; + contentRect = [getScreen(wndconfig->monitor->ns.displayID) frame]; else contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height);