Various fixes for monitor work area retrieval from upstream

This commit is contained in:
Kovid Goyal 2019-03-06 09:08:08 +05:30
parent 2e0d39b512
commit 4c4c6ab0e6
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
9 changed files with 168 additions and 70 deletions

View File

@ -213,6 +213,30 @@ static void endFadeReservation(CGDisplayFadeReservationToken token)
}
}
// Finds and caches the NSScreen corresponding to the specified monitor
//
GLFWbool refreshMonitorScreen(_GLFWmonitor* monitor)
{
if (monitor->ns.screen)
return GLFW_TRUE;
for (NSScreen* screen in [NSScreen screens])
{
NSNumber* displayID = [screen deviceDescription][@"NSScreenNumber"];
// HACK: Compare unit numbers instead of display IDs to work around
// display replacement on machines with automatic graphics
// switching
if (monitor->ns.unitNumber == CGDisplayUnitNumber([displayID unsignedIntValue]))
{
monitor->ns.screen = screen;
return GLFW_TRUE;
}
}
_glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to find a screen for monitor");
return GLFW_FALSE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
@ -429,35 +453,8 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
float* xscale, float* yscale)
{
if (!monitor->ns.screen)
{
NSUInteger i;
NSArray* screens = [NSScreen screens];
for (i = 0; i < [screens count]; i++)
{
NSScreen* screen = [screens objectAtIndex:i];
NSNumber* displayID =
[[screen deviceDescription] objectForKey:@"NSScreenNumber"];
// HACK: Compare unit numbers instead of display IDs to work around
// display replacement on machines with automatic graphics
// switching
if (monitor->ns.unitNumber ==
CGDisplayUnitNumber([displayID unsignedIntValue]))
{
monitor->ns.screen = screen;
break;
}
}
if (i == [screens count])
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to find a screen for monitor");
if (!refreshMonitorScreen(monitor))
return;
}
}
const NSRect points = [monitor->ns.screen frame];
const NSRect pixels = [monitor->ns.screen convertRectToBacking:points];
@ -470,20 +467,20 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
{
NSScreen *resultScreen;
for (NSScreen *screen in [NSScreen screens]) {
if ([[[screen deviceDescription] valueForKey:@"NSScreenNumber"] intValue] == monitor->ns.displayID) {
resultScreen = screen;
break;
}
}
if (!refreshMonitorScreen(monitor))
return;
NSRect frameRect = [[NSScreen resultScreen] visibleFrame];
const NSRect frameRect = [monitor->ns.screen visibleFrame];
if (xpos)
*xpos = frameRect.origin.x;
if (ypos)
*ypos = _glfwTransformYNS(frameRect.origin.y + frameRect.size.height);
if (width)
*width = frameRect.size.width;
if (height)
*height = frameRect.size.height;
*xpos = NSMinX(frameRect);
*ypos = NSMinY(frameRect);
*width = NSMaxX(frameRect);
*height = NSMaxY(frameRect);
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)

View File

@ -202,6 +202,7 @@ void _glfwInitTimerNS(void);
void _glfwPollMonitorsNS(void);
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
float _glfwTransformYNS(float y);
void _glfwClearDisplayLinks();
void _glfwCocoaPostEmptyEvent(short subtype, long data1, bool at_start);
void _glfwDispatchTickCallback();

View File

@ -149,14 +149,6 @@ static void updateCursorMode(_GLFWwindow* window)
updateCursorImage(window);
}
// Transforms the specified y-coordinate between the CG display and NS screen
// coordinate systems
//
static float transformY(float y)
{
return CGDisplayBounds(CGMainDisplayID()).size.height - y;
}
// Make the specified window and its video mode active on its monitor
//
static void acquireMonitor(_GLFWwindow* window)
@ -164,7 +156,7 @@ static void acquireMonitor(_GLFWwindow* window)
_glfwSetVideoModeNS(window->monitor, &window->videoMode);
const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID);
const NSRect frame = NSMakeRect(bounds.origin.x,
transformY(bounds.origin.y + bounds.size.height),
_glfwTransformYNS(bounds.origin.y + bounds.size.height),
bounds.size.width,
bounds.size.height);
@ -1039,7 +1031,7 @@ is_ascii_control_char(char x) {
int xpos, ypos;
_glfwPlatformGetWindowPos(window, &xpos, &ypos);
const NSRect contentRect = [window->ns.view frame];
return NSMakeRect(xpos, transformY(ypos + contentRect.size.height), 0.0, 0.0);
return NSMakeRect(xpos, _glfwTransformYNS(ypos + contentRect.size.height), 0.0, 0.0);
}
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
@ -1437,13 +1429,13 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
if (xpos)
*xpos = contentRect.origin.x;
if (ypos)
*ypos = transformY(contentRect.origin.y + contentRect.size.height);
*ypos = _glfwTransformYNS(contentRect.origin.y + contentRect.size.height);
}
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int x, int y)
{
const NSRect contentRect = [window->ns.view frame];
const NSRect dummyRect = NSMakeRect(x, transformY(y + contentRect.size.height), 0, 0);
const NSRect dummyRect = NSMakeRect(x, _glfwTransformYNS(y + contentRect.size.height), 0, 0);
const NSRect frameRect = [window->ns.object frameRectForContentRect:dummyRect];
[window->ns.object setFrameOrigin:frameRect.origin];
}
@ -1606,7 +1598,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
else
{
const NSRect contentRect =
NSMakeRect(xpos, transformY(ypos + height), width, height);
NSMakeRect(xpos, _glfwTransformYNS(ypos + height), width, height);
const NSRect frameRect =
[window->ns.object frameRectForContentRect:contentRect
styleMask:getStyleMask(window)];
@ -1636,7 +1628,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
}
else
{
NSRect contentRect = NSMakeRect(xpos, transformY(ypos + height),
NSRect contentRect = NSMakeRect(xpos, _glfwTransformYNS(ypos + height),
width, height);
NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect
styleMask:styleMask];
@ -1864,7 +1856,7 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
const NSPoint globalPoint = globalRect.origin;
CGWarpMouseCursorPosition(CGPointMake(globalPoint.x,
transformY(globalPoint.y)));
_glfwTransformYNS(globalPoint.y)));
}
}
@ -2225,3 +2217,14 @@ GLFWAPI void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, unsigned sho
#undef K
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Transforms a y-coordinate between the CG display and NS screen spaces
//
float _glfwTransformYNS(float y)
{
return CGDisplayBounds(CGMainDisplayID()).size.height - y;
}

14
glfw/glfw3.h vendored
View File

@ -1940,23 +1940,27 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos);
/*! @brief Returns the work area of the monitor.
*
* This function returns the position, in screen coordinates, of the upper-left
* corner of the specified monitor.
* corner of the specified monitor alongwith the work area size in screen co-ordinates.
* The work area is defined as the area of the monitor not occluded by the operating
* system chrome (task bar, global menubar, etc.).
*
* Any or all of the position arguments may be `NULL`. If an error occurs, all
* non-`NULL` position arguments will be set to zero.
* Any or all of the position and size arguments may be `NULL`. If an error occurs, all
* non-`NULL` position and size arguments will be set to zero.
*
* @param[in] monitor The monitor to query.
* @param[out] xpos Where to store the monitor x-coordinate, or `NULL`.
* @param[out] ypos Where to store the monitor y-coordinate, or `NULL`.
* @param[out] width Where to store the monitor width, or `NULL`.
* @param[out] height Where to store the monitor height, or `NULL`.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref monitor_properties
* @sa @ref monitor_workarea
*
* @since Added in version 3.0.
* @since Added in version 3.3.
*
* @ingroup monitor
*/

4
glfw/monitor.c vendored
View File

@ -341,8 +341,8 @@ GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* handle, int* xpos, int* ypos, i
*ypos = 0;
if (width)
*width = 0;
if (width)
*width = 0;
if (height)
*height = 0;
_GLFW_REQUIRE_INIT();

12
glfw/wl_monitor.c vendored
View File

@ -170,6 +170,18 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
*yscale = (float) monitor->wl.scale;
}
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
{
if (xpos)
*xpos = monitor->wl.x;
if (ypos)
*ypos = monitor->wl.y;
if (width)
*width = monitor->modes[monitor->wl.currentMode].width;
if (height)
*height = monitor->modes[monitor->wl.currentMode].height;
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
{
*found = monitor->modeCount;

2
glfw/x11_init.c vendored
View File

@ -139,6 +139,8 @@ static void detectEWMH(void)
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL");
_glfw.x11.NET_WORKAREA =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WORKAREA");
_glfw.x11.NET_CURRENT_DESKTOP =
getSupportedAtom(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP");
_glfw.x11.NET_ACTIVE_WINDOW =
getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");
_glfw.x11.NET_FRAME_EXTENTS =

92
glfw/x11_monitor.c vendored
View File

@ -351,18 +351,96 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
{
int areaX = 0, areaY = 0, areaWidth = 0, areaHeight = 0;
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
Atom* extents = NULL;
XRRScreenResources* sr;
XRRCrtcInfo* ci;
_glfwGetWindowPropertyX11(_glfw.x11.root, _glfw.x11.NET_WORKAREA, XA_CARDINAL, (unsigned char**) &extents);
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
*xpos = extents[0];
*ypos = extents[1];
*width = extents[2];
*height = extents[3];
XFree(extents);
areaX = ci->x;
areaY = ci->y;
const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
{
areaWidth = mi->height;
areaHeight = mi->width;
}
else
{
areaWidth = mi->width;
areaHeight = mi->height;
}
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr);
}
else
{
areaWidth = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
areaHeight = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
}
if (_glfw.x11.NET_WORKAREA && _glfw.x11.NET_CURRENT_DESKTOP)
{
Atom* extents = NULL;
Atom* desktop = NULL;
const unsigned long extentCount =
_glfwGetWindowPropertyX11(_glfw.x11.root,
_glfw.x11.NET_WORKAREA,
XA_CARDINAL,
(unsigned char**) &extents);
if (_glfwGetWindowPropertyX11(_glfw.x11.root,
_glfw.x11.NET_CURRENT_DESKTOP,
XA_CARDINAL,
(unsigned char**) &desktop) > 0)
{
if (extentCount >= 4 && *desktop < extentCount / 4)
{
const int globalX = extents[*desktop * 4 + 0];
const int globalY = extents[*desktop * 4 + 1];
const int globalWidth = extents[*desktop * 4 + 2];
const int globalHeight = extents[*desktop * 4 + 3];
if (areaX < globalX)
{
areaWidth -= globalX - areaX;
areaX = globalX;
}
if (areaY < globalY)
{
areaHeight -= globalY - areaY;
areaY = globalY;
}
if (areaX + areaWidth > globalX + globalWidth)
areaWidth = globalX - areaX + globalWidth;
if (areaY + areaHeight > globalY + globalHeight)
areaHeight = globalY - areaY + globalHeight;
}
}
if (extents)
XFree(extents);
if (desktop)
XFree(desktop);
}
if (xpos)
*xpos = areaX;
if (ypos)
*ypos = areaY;
if (width)
*width = areaWidth;
if (height)
*height = areaHeight;
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)

1
glfw/x11_platform.h vendored
View File

@ -249,6 +249,7 @@ typedef struct _GLFWlibraryX11
Atom NET_WM_WINDOW_OPACITY;
Atom NET_WM_CM_Sx;
Atom NET_WORKAREA;
Atom NET_CURRENT_DESKTOP;
Atom NET_ACTIVE_WINDOW;
Atom NET_FRAME_EXTENTS;
Atom NET_REQUEST_FRAME_EXTENTS;