Added SDL_GetDisplayUsableBounds().
authorRyan C. Gordon <icculus@icculus.org>
Mon, 04 Jan 2016 23:52:40 -0500
changeset 10019 36f7e8084508
parent 10018 3c1384edf9fa
child 10020 08b9e569e1ce
Added SDL_GetDisplayUsableBounds().
.hgignore
include/SDL_video.h
src/dynapi/SDL_dynapi_overrides.h
src/dynapi/SDL_dynapi_procs.h
src/video/SDL_sysvideo.h
src/video/SDL_video.c
src/video/cocoa/SDL_cocoamodes.h
src/video/cocoa/SDL_cocoamodes.m
src/video/cocoa/SDL_cocoavideo.m
src/video/uikit/SDL_uikitmodes.h
src/video/uikit/SDL_uikitmodes.m
src/video/uikit/SDL_uikitvideo.m
src/video/windows/SDL_windowsmodes.c
src/video/windows/SDL_windowsmodes.h
src/video/windows/SDL_windowsvideo.c
src/video/x11/SDL_x11modes.c
src/video/x11/SDL_x11modes.h
src/video/x11/SDL_x11video.c
test/Makefile.in
test/testbounds.c
--- a/.hgignore	Wed Apr 22 16:50:48 2015 -0400
+++ b/.hgignore	Mon Jan 04 23:52:40 2016 -0500
@@ -116,6 +116,7 @@
 test/testver
 test/testviewport
 test/testwm2
+test/testbounds
 test/torturethread
 test/testdisplayinfo
 test/*.exe
--- a/include/SDL_video.h	Wed Apr 22 16:50:48 2015 -0400
+++ b/include/SDL_video.h	Mon Jan 04 23:52:40 2016 -0500
@@ -312,6 +312,25 @@
 extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
 
 /**
+ *  \brief Get the usable desktop area represented by a display, with the
+ *         primary display located at 0,0
+ *
+ *  This is the same area as SDL_GetDisplayBounds() reports, but with portions
+ *  reserved by the system removed. For example, on Mac OS X, this subtracts
+ *  the area occupied by the menu bar and dock.
+ *
+ *  Setting a window to be fullscreen generally bypasses these unusable areas,
+ *  so these are good guidelines for the maximum space available to a
+ *  non-fullscreen window.
+ *
+ *  \return 0 on success, or -1 if the index is out of range.
+ *
+ *  \sa SDL_GetDisplayBounds()
+ *  \sa SDL_GetNumVideoDisplays()
+ */
+extern DECLSPEC int SDLCALL SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect * rect);
+
+/**
  *  \brief Returns the number of available display modes.
  *
  *  \sa SDL_GetDisplayMode()
--- a/src/dynapi/SDL_dynapi_overrides.h	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/dynapi/SDL_dynapi_overrides.h	Mon Jan 04 23:52:40 2016 -0500
@@ -597,3 +597,4 @@
 #define SDL_JoystickCurrentPowerLevel SDL_JoystickCurrentPowerLevel_REAL
 #define SDL_GameControllerFromInstanceID SDL_GameControllerFromInstanceID_REAL
 #define SDL_JoystickFromInstanceID SDL_JoystickFromInstanceID_REAL
+#define SDL_GetDisplayUsableBounds SDL_GetDisplayUsableBounds_REAL
--- a/src/dynapi/SDL_dynapi_procs.h	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/dynapi/SDL_dynapi_procs.h	Mon Jan 04 23:52:40 2016 -0500
@@ -631,3 +631,4 @@
 SDL_DYNAPI_PROC(SDL_JoystickPowerLevel,SDL_JoystickCurrentPowerLevel,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(SDL_GameController*,SDL_GameControllerFromInstanceID,(SDL_JoystickID a),(a),return)
 SDL_DYNAPI_PROC(SDL_Joystick*,SDL_JoystickFromInstanceID,(SDL_JoystickID a),(a),return)
+SDL_DYNAPI_PROC(int,SDL_GetDisplayUsableBounds,(int a, SDL_Rect *b),(a,b),return)
--- a/src/video/SDL_sysvideo.h	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/SDL_sysvideo.h	Mon Jan 04 23:52:40 2016 -0500
@@ -176,6 +176,11 @@
     int (*GetDisplayDPI) (_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi);
 
     /*
+     * Get the usable bounds of a display (bounds minus menubar or whatever)
+     */
+    int (*GetDisplayUsableBounds) (_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
+
+    /*
      * Get a list of the available display modes for a display.
      */
     void (*GetDisplayModes) (_THIS, SDL_VideoDisplay * display);
--- a/src/video/SDL_video.c	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/SDL_video.c	Mon Jan 04 23:52:40 2016 -0500
@@ -684,7 +684,26 @@
         rect->w = display->current_mode.w;
         rect->h = display->current_mode.h;
     }
-    return 0;
+    return 0;  /* !!! FIXME: should this be an error if (rect==NULL) ? */
+}
+
+int SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect * rect)
+{
+    CHECK_DISPLAY_INDEX(displayIndex, -1);
+
+    if (rect) {
+        SDL_VideoDisplay *display = &_this->displays[displayIndex];
+
+        if (_this->GetDisplayUsableBounds) {
+            if (_this->GetDisplayUsableBounds(_this, display, rect) == 0) {
+                return 0;
+            }
+        }
+
+        /* Oh well, just give the entire display bounds. */
+        return SDL_GetDisplayBounds(displayIndex, rect);
+    }
+    return 0;  /* !!! FIXME: should this be an error if (rect==NULL) ? */
 }
 
 int
--- a/src/video/cocoa/SDL_cocoamodes.h	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/cocoa/SDL_cocoamodes.h	Mon Jan 04 23:52:40 2016 -0500
@@ -35,6 +35,7 @@
 
 extern void Cocoa_InitModes(_THIS);
 extern int Cocoa_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
+extern int Cocoa_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
 extern void Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
 extern int Cocoa_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
 extern void Cocoa_QuitModes(_THIS);
--- a/src/video/cocoa/SDL_cocoamodes.m	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/cocoa/SDL_cocoamodes.m	Mon Jan 04 23:52:40 2016 -0500
@@ -19,6 +19,7 @@
   3. This notice may not be removed or altered from any source distribution.
 */
 #include "../../SDL_internal.h"
+#include "SDL_assert.h"
 
 #if SDL_VIDEO_DRIVER_COCOA
 
@@ -338,6 +339,41 @@
     return 0;
 }
 
+int
+Cocoa_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
+{
+    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
+    const CGDirectDisplayID cgdisplay = displaydata->display;
+    NSArray *screens = [NSScreen screens];
+    NSScreen *screen = nil;
+
+    /* !!! FIXME: maybe track the NSScreen in SDL_DisplayData? */
+    for (NSScreen *i in screens) {
+        const CGDirectDisplayID thisDisplay = (CGDirectDisplayID) [[[i deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
+        if (thisDisplay == cgdisplay) {
+            screen = i;
+            break;
+        }
+    }
+
+    SDL_assert(screen != nil);  /* didn't find it?! */
+    if (screen == nil) {
+        return -1;
+    }
+
+    const CGRect cgrect = CGDisplayBounds(cgdisplay);
+    const NSRect frame = [screen visibleFrame];
+
+    // !!! FIXME: I assume -[NSScreen visibleFrame] is relative to the origin of the screen in question and not the whole desktop.
+    // !!! FIXME: The math vs CGDisplayBounds might be incorrect if that's not the case, though. Check this.
+    rect->x = (int)(cgrect.origin.x + frame.origin.x);
+    rect->y = (int)(cgrect.origin.y + frame.origin.y);
+    rect->w = (int)frame.size.width;
+    rect->h = (int)frame.size.height;
+
+    return 0;
+}
+
 void
 Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
 {
--- a/src/video/cocoa/SDL_cocoavideo.m	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/cocoa/SDL_cocoavideo.m	Mon Jan 04 23:52:40 2016 -0500
@@ -73,6 +73,7 @@
     device->VideoInit = Cocoa_VideoInit;
     device->VideoQuit = Cocoa_VideoQuit;
     device->GetDisplayBounds = Cocoa_GetDisplayBounds;
+    device->GetDisplayUsableBounds = Cocoa_GetDisplayUsableBounds;
     device->GetDisplayModes = Cocoa_GetDisplayModes;
     device->SetDisplayMode = Cocoa_SetDisplayMode;
     device->PumpEvents = Cocoa_PumpEvents;
--- a/src/video/uikit/SDL_uikitmodes.h	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/uikit/SDL_uikitmodes.h	Mon Jan 04 23:52:40 2016 -0500
@@ -43,6 +43,7 @@
 extern void UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
 extern int UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
 extern void UIKit_QuitModes(_THIS);
+extern int UIKit_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
 
 #endif /* _SDL_uikitmodes_h */
 
--- a/src/video/uikit/SDL_uikitmodes.m	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/uikit/SDL_uikitmodes.m	Mon Jan 04 23:52:40 2016 -0500
@@ -242,6 +242,26 @@
     return 0;
 }
 
+int
+UIKit_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
+{
+    /* the default function iterates displays to make a fake offset,
+       as if all the displays were side-by-side, which is fine for iOS. */
+    const int displayIndex = (int) (display - _this->displays);
+    if (SDL_GetDisplayBounds(displayIndex, rect) < 0) {
+        return -1;
+    }
+
+    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
+    const CGRect frame = [data->uiscreen applicationFrame];
+    const float scale = (float) data->scale;
+    rect->x += (int) (frame.origin.x * scale);
+    rect->y += (int) (frame.origin.y * scale);
+    rect->w = (int) (frame.size.width * scale);
+    rect->h = (int) (frame.size.height * scale);
+    return 0;
+}
+
 void
 UIKit_QuitModes(_THIS)
 {
--- a/src/video/uikit/SDL_uikitvideo.m	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/uikit/SDL_uikitvideo.m	Mon Jan 04 23:52:40 2016 -0500
@@ -85,6 +85,7 @@
     device->SetWindowFullscreen = UIKit_SetWindowFullscreen;
     device->DestroyWindow = UIKit_DestroyWindow;
     device->GetWindowWMInfo = UIKit_GetWindowWMInfo;
+    device->GetDisplayUsableBounds = UIKit_GetDisplayUsableBounds;
 
 #if SDL_IPHONE_KEYBOARD
     device->HasScreenKeyboardSupport = UIKit_HasScreenKeyboardSupport;
--- a/src/video/windows/SDL_windowsmodes.c	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/windows/SDL_windowsmodes.c	Mon Jan 04 23:52:40 2016 -0500
@@ -332,6 +332,43 @@
     return data->DiagDPI != 0.0f ? 0 : -1;
 }
 
+int
+WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
+{
+    const SDL_DisplayModeData *data = (const SDL_DisplayModeData *) display->current_mode.driverdata;
+    const DEVMODE *pDevMode = &data->DeviceMode;
+    POINT pt = {
+        /* !!! FIXME: no scale, right? */
+        (LONG) (pDevMode->dmPosition.x + (pDevMode->dmPelsWidth / 2)),
+        (LONG) (pDevMode->dmPosition.y + (pDevMode->dmPelsHeight / 2))
+    };
+    HMONITOR hmon = MonitorFromPoint(&pt, MONITOR_DEFAULTTONULL);
+    MONITORINFO minfo;
+    const RECT *work;
+    BOOL rc = FALSE;
+
+    SDL_assert(hmon != NULL);
+
+    if (hmon != NULL) {
+        SDL_zero(minfo);
+        minfo.cbSize = sizeof (MONITORINFO);
+        rc = GetMonitorInfo(hmon, &minfo);
+        SDL_assert(rc);
+    }
+
+    if (!rc) {
+        return SDL_SetError("Couldn't find monitor data");
+    }
+
+    work = &minfo->rcWork;
+    rect->x = (int)SDL_ceil(work->left * data->ScaleX);
+    rect->y = (int)SDL_ceil(work->top * data->ScaleY);
+    rect->w = (int)SDL_ceil((work->right - work->left) * data->ScaleX);
+    rect->h = (int)SDL_ceil((work->bottom - work->top) * data->ScaleY);
+
+    return 0;
+}
+
 void
 WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
 {
--- a/src/video/windows/SDL_windowsmodes.h	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/windows/SDL_windowsmodes.h	Mon Jan 04 23:52:40 2016 -0500
@@ -40,6 +40,7 @@
 
 extern int WIN_InitModes(_THIS);
 extern int WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
+extern int WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
 extern int WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi);
 extern void WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
 extern int WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
--- a/src/video/windows/SDL_windowsvideo.c	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/windows/SDL_windowsvideo.c	Mon Jan 04 23:52:40 2016 -0500
@@ -124,6 +124,7 @@
     device->VideoInit = WIN_VideoInit;
     device->VideoQuit = WIN_VideoQuit;
     device->GetDisplayBounds = WIN_GetDisplayBounds;
+    device->GetDisplayUsableBounds = WIN_GetDisplayUsableBounds;
     device->GetDisplayDPI = WIN_GetDisplayDPI;
     device->GetDisplayModes = WIN_GetDisplayModes;
     device->SetDisplayMode = WIN_SetDisplayMode;
--- a/src/video/x11/SDL_x11modes.c	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/x11/SDL_x11modes.c	Mon Jan 04 23:52:40 2016 -0500
@@ -1073,6 +1073,43 @@
     return data->ddpi != 0.0f ? 0 : -1;
 }
 
+int
+X11_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
+{
+    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
+    Display *display = data->display;
+    Atom _NET_WORKAREA;
+    int status, real_format;
+    int retval = -1;
+    Atom real_type;
+    unsigned long items_read = 0, items_left = 0;
+    unsigned char *propdata = NULL;
+
+    if (X11_GetDisplayBounds(_this, sdl_display, rect) < 0) {
+        return -1;
+    }
+
+    _NET_WORKAREA = X11_XInternAtom(display, "_NET_WORKAREA", False);
+    status = X11_XGetWindowProperty(display, DefaultRootWindow(display),
+                                    _NET_WORKAREA, 0L, 4L, False, XA_CARDINAL,
+                                    &real_type, &real_format, &items_read,
+                                    &items_left, &propdata);
+    if ((status == Success) && (items_read >= 4)) {
+        retval = 0;
+        const long *p = (long*) propdata;
+        const SDL_Rect usable = { (int)p[0], (int)p[1], (int)p[2], (int)p[3] };
+        if (!SDL_IntersectRect(rect, &usable, rect)) {
+            SDL_zerop(rect);
+        }
+    }
+
+    if (propdata) {
+        X11_XFree(propdata);
+    }
+
+    return retval;
+}
+
 #endif /* SDL_VIDEO_DRIVER_X11 */
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/x11/SDL_x11modes.h	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/x11/SDL_x11modes.h	Mon Jan 04 23:52:40 2016 -0500
@@ -77,6 +77,7 @@
 extern Uint32 X11_GetPixelFormatFromVisualInfo(Display * display,
                                                XVisualInfo * vinfo);
 extern int X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect);
+extern int X11_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect);
 extern int X11_GetDisplayDPI(_THIS, SDL_VideoDisplay * sdl_display, float * ddpi, float * hdpi, float * vdpi);
 
 #endif /* _SDL_x11modes_h */
--- a/src/video/x11/SDL_x11video.c	Wed Apr 22 16:50:48 2015 -0400
+++ b/src/video/x11/SDL_x11video.c	Mon Jan 04 23:52:40 2016 -0500
@@ -218,6 +218,7 @@
     device->VideoQuit = X11_VideoQuit;
     device->GetDisplayModes = X11_GetDisplayModes;
     device->GetDisplayBounds = X11_GetDisplayBounds;
+    device->GetDisplayUsableBounds = X11_GetDisplayUsableBounds;
     device->GetDisplayDPI = X11_GetDisplayDPI;
     device->SetDisplayMode = X11_SetDisplayMode;
     device->SuspendScreenSaver = X11_SuspendScreenSaver;
--- a/test/Makefile.in	Wed Apr 22 16:50:48 2015 -0400
+++ b/test/Makefile.in	Mon Jan 04 23:52:40 2016 -0500
@@ -14,6 +14,7 @@
 	testatomic$(EXE) \
 	testaudioinfo$(EXE) \
 	testautomation$(EXE) \
+	testbounds$(EXE) \
 	testdraw2$(EXE) \
 	testdrawchessboard$(EXE) \
 	testdropfile$(EXE) \
@@ -270,6 +271,9 @@
 testdisplayinfo$(EXE): $(srcdir)/testdisplayinfo.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
 
+testbounds$(EXE): $(srcdir)/testbounds.c
+	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
+
 controllermap$(EXE): $(srcdir)/controllermap.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testbounds.c	Mon Jan 04 23:52:40 2016 -0500
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely.
+*/
+
+#include "SDL.h"
+
+int main(int argc, char **argv)
+{
+    int total, i;
+
+    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+        SDL_Log("SDL_Init(SDL_INIT_VIDEO) failed: %s", SDL_GetError());
+    }
+
+    total = SDL_GetNumVideoDisplays();
+    for (i = 0; i < total; i++) {
+        SDL_Rect bounds = { -1,-1,-1,-1 }, usable = { -1,-1,-1,-1 };
+        SDL_GetDisplayBounds(i, &bounds);
+        SDL_GetDisplayUsableBounds(i, &usable);
+        SDL_Log("Display #%d ('%s'): bounds={(%d,%d),%dx%d}, usable={(%d,%d),%dx%d}",
+                i, SDL_GetDisplayName(i),
+                bounds.x, bounds.y, bounds.w, bounds.h,
+                usable.x, usable.y, usable.w, usable.h);
+    }
+
+    SDL_Quit();
+    return 0;
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
+