Added an API function to query geometry of multiple monitors:
authorSam Lantinga <slouken@libsdl.org>
Sun, 06 Dec 2009 08:03:38 +0000
changeset 3528 59ff7a2beb57
parent 3527 444cb12cadb6
child 3529 09155ec3e291
Added an API function to query geometry of multiple monitors: SDL_GetDisplayBounds() Implemented multi-monitor window positions on Windows
include/SDL_video.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_cocoamouse.m
src/video/cocoa/SDL_cocoavideo.m
src/video/cocoa/SDL_cocoawindow.m
src/video/win32/SDL_win32modes.c
src/video/win32/SDL_win32modes.h
src/video/win32/SDL_win32video.c
src/video/win32/SDL_win32window.c
test/testvidinfo.c
--- a/include/SDL_video.h	Sun Dec 06 06:21:39 2009 +0000
+++ b/include/SDL_video.h	Sun Dec 06 08:03:38 2009 +0000
@@ -343,11 +343,22 @@
 /**
  *  \brief Returns the number of available video displays.
  *  
+ *  \sa SDL_GetDisplayBounds()
  *  \sa SDL_SelectVideoDisplay()
  */
 extern DECLSPEC int SDLCALL SDL_GetNumVideoDisplays(void);
 
 /**
+ *  \brief Get the desktop area represented by a display, with the primary
+ *         display located at 0,0
+ *  
+ *  \return 0 on success, or -1 if the index is out of range.
+ *  
+ *  \sa SDL_GetNumVideoDisplays()
+ */
+extern DECLSPEC int SDLCALL SDL_GetDisplayBounds(int index, SDL_Rect * rect);
+
+/**
  *  \brief Set the index of the currently selected display.
  *  
  *  \return 0 on success, or -1 if the index is out of range.
--- a/src/video/SDL_sysvideo.h	Sun Dec 06 06:21:39 2009 +0000
+++ b/src/video/SDL_sysvideo.h	Sun Dec 06 08:03:38 2009 +0000
@@ -213,6 +213,11 @@
      */
 
     /*
+     * Get the bounds of a display
+     */
+    int (*GetDisplayBounds) (_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
+
+    /*
      * Get a list of the available display modes. e.g.
      * SDL_AddDisplayMode(_this->current_display, mode)
      */
--- a/src/video/SDL_video.c	Sun Dec 06 06:21:39 2009 +0000
+++ b/src/video/SDL_video.c	Sun Dec 06 08:03:38 2009 +0000
@@ -335,6 +335,41 @@
 }
 
 int
+SDL_GetDisplayBounds(int index, SDL_Rect * rect)
+{
+    if (!_this) {
+        SDL_UninitializedVideo();
+        return -1;
+    }
+    if (index < 0 || index >= _this->num_displays) {
+        SDL_SetError("index must be in the range 0 - %d",
+                     _this->num_displays - 1);
+        return -1;
+    }
+    if (rect) {
+        SDL_VideoDisplay *display = &_this->displays[index];
+
+        if (_this->GetDisplayBounds) {
+            if (_this->GetDisplayBounds(_this, display, rect) < 0) {
+                return -1;
+            }
+        } else {
+            /* Assume that the displays are left to right */
+            if (index == 0) {
+                rect->x = 0;
+                rect->y = 0;
+            } else {
+                SDL_GetDisplayBounds(index-1, rect);
+                rect->x += rect->w;
+            }
+            rect->w = display->desktop_mode.w;
+            rect->h = display->desktop_mode.h;
+        }
+    }
+    return 0;
+}
+
+int
 SDL_SelectVideoDisplay(int index)
 {
     if (!_this) {
--- a/src/video/cocoa/SDL_cocoamodes.h	Sun Dec 06 06:21:39 2009 +0000
+++ b/src/video/cocoa/SDL_cocoamodes.h	Sun Dec 06 08:03:38 2009 +0000
@@ -35,7 +35,7 @@
 } SDL_DisplayModeData;
 
 extern void Cocoa_InitModes(_THIS);
-extern NSRect Cocoa_DisplayBounds(CGDirectDisplayID display);
+extern int Cocoa_GetDisplayBounds(_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	Sun Dec 06 06:21:39 2009 +0000
+++ b/src/video/cocoa/SDL_cocoamodes.m	Sun Dec 06 08:03:38 2009 +0000
@@ -200,19 +200,18 @@
     SDL_stack_free(displays);
 }
 
-/* This is needed on 10.4, where NSRect and CGRect are different */
-NSRect
-Cocoa_DisplayBounds(CGDirectDisplayID display)
+int
+Cocoa_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
 {
-    NSRect nsrect;
+    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
     CGRect cgrect;
 
-    cgrect = CGDisplayBounds(display);
-    nsrect.origin.x = cgrect.origin.x;
-    nsrect.origin.y = cgrect.origin.y;
-    nsrect.size.width = cgrect.size.width;
-    nsrect.size.height = cgrect.size.height;
-    return nsrect;
+    cgrect = CGDisplayBounds(displaydata->display);
+    rect->x = (int)cgrect.origin.x;
+    rect->y = (int)cgrect.origin.y;
+    rect->w = (int)cgrect.size.width;
+    rect->h = (int)cgrect.size.height;
+    return 0;
 }
 
 static void
--- a/src/video/cocoa/SDL_cocoamouse.m	Sun Dec 06 06:21:39 2009 +0000
+++ b/src/video/cocoa/SDL_cocoamouse.m	Sun Dec 06 08:03:38 2009 +0000
@@ -67,12 +67,12 @@
         SDL_Window *candidate = display->fullscreen_window;
 
         if (candidate) {
-            SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
-            NSRect rect = Cocoa_DisplayBounds(displaydata->display);
+            SDL_Rect bounds;
 
+            Cocoa_GetDisplayBounds(_this, display, &bounds);
             point = [NSEvent mouseLocation];
-            point.x = point.x - rect.origin.x;
-            point.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - point.y - rect.origin.y;
+            point.x = point.x - bounds.x;
+            point.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - point.y - bounds.y;
             if (point.x < 0 || point.x >= candidate->w ||
                 point.y < 0 || point.y >= candidate->h) {
                 /* The mouse is out of this fullscreen display */
--- a/src/video/cocoa/SDL_cocoavideo.m	Sun Dec 06 06:21:39 2009 +0000
+++ b/src/video/cocoa/SDL_cocoavideo.m	Sun Dec 06 08:03:38 2009 +0000
@@ -72,6 +72,7 @@
     /* Set the function pointers */
     device->VideoInit = Cocoa_VideoInit;
     device->VideoQuit = Cocoa_VideoQuit;
+    device->GetDisplayBounds = Cocoa_GetDisplayBounds;
     device->GetDisplayModes = Cocoa_GetDisplayModes;
     device->SetDisplayMode = Cocoa_SetDisplayMode;
     device->PumpEvents = Cocoa_PumpEvents;
--- a/src/video/cocoa/SDL_cocoawindow.m	Sun Dec 06 06:21:39 2009 +0000
+++ b/src/video/cocoa/SDL_cocoawindow.m	Sun Dec 06 08:03:38 2009 +0000
@@ -378,23 +378,28 @@
 {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
     NSWindow *nswindow;
-    SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayFromWindow(window)->driverdata;
+    SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
     NSRect rect;
+    SDL_Rect bounds;
     unsigned int style;
     NSString *title;
     int status;
 
-    rect = Cocoa_DisplayBounds(displaydata->display);
+    Cocoa_GetDisplayBounds(_this, display, &bounds);
     if ((window->flags & SDL_WINDOW_FULLSCREEN)
         || window->x == SDL_WINDOWPOS_CENTERED) {
-        rect.origin.x += (rect.size.width - window->w) / 2;
-    } else if (window->x != SDL_WINDOWPOS_UNDEFINED) {
+        rect.origin.x = bounds.x + (bounds.w - window->w) / 2;
+    } else if (window->x == SDL_WINDOWPOS_UNDEFINED) {
+        rect.origin.x = bounds.x;
+    } else {
         rect.origin.x = window->x;
     }
     if ((window->flags & SDL_WINDOW_FULLSCREEN)
         || window->y == SDL_WINDOWPOS_CENTERED) {
-        rect.origin.y += (rect.size.height - window->h) / 2;
-    } else if (window->x != SDL_WINDOWPOS_UNDEFINED) {
+        rect.origin.y = bounds.y + (bounds.h - window->h) / 2;
+    } else if (window->x == SDL_WINDOWPOS_UNDEFINED) {
+        rect.origin.y = bounds.y;
+    } else {
         rect.origin.y = window->y;
     }
     rect.size.width = window->w;
@@ -482,19 +487,20 @@
 {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
-    SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayFromWindow(window)->driverdata;
+    SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
     NSRect rect;
+    SDL_Rect bounds;
 
-    rect = Cocoa_DisplayBounds(displaydata->display);
+    Cocoa_GetDisplayBounds(_this, display, &bounds);
     if ((window->flags & SDL_WINDOW_FULLSCREEN)
         || window->x == SDL_WINDOWPOS_CENTERED) {
-        rect.origin.x += (rect.size.width - window->w) / 2;
+        rect.origin.x = bounds.x + (bounds.w - window->w) / 2;
     } else {
         rect.origin.x = window->x;
     }
     if ((window->flags & SDL_WINDOW_FULLSCREEN)
         || window->y == SDL_WINDOWPOS_CENTERED) {
-        rect.origin.y += (rect.size.height - window->h) / 2;
+        rect.origin.y = bounds.y + (bounds.h - window->h) / 2;
     } else {
         rect.origin.y = window->y;
     }
--- a/src/video/win32/SDL_win32modes.c	Sun Dec 06 06:21:39 2009 +0000
+++ b/src/video/win32/SDL_win32modes.c	Sun Dec 06 08:03:38 2009 +0000
@@ -54,7 +54,7 @@
     mode->driverdata = data;
 #ifdef _WIN32_WCE
     /* In WinCE EnumDisplaySettings(ENUM_CURRENT_SETTINGS) doesn't take the user defined orientation
-       into account but GetSystemMetrixs does. */
+       into account but GetSystemMetrics does. */
     if (index == ENUM_CURRENT_SETTINGS) {
         mode->w = GetSystemMetrics(SM_CXSCREEN);
         mode->h = GetSystemMetrics(SM_CYSCREEN);
@@ -199,6 +199,18 @@
     return 0;
 }
 
+int
+WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
+{
+    SDL_DisplayModeData *data = (SDL_DisplayModeData *) display->desktop_mode.driverdata;
+
+    rect->x = (int)data->DeviceMode.dmPosition.x;
+    rect->y = (int)data->DeviceMode.dmPosition.y;
+    rect->w = data->DeviceMode.dmPelsWidth;
+    rect->h = data->DeviceMode.dmPelsHeight;
+    return 0;
+}
+
 void
 WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
 {
--- a/src/video/win32/SDL_win32modes.h	Sun Dec 06 06:21:39 2009 +0000
+++ b/src/video/win32/SDL_win32modes.h	Sun Dec 06 08:03:38 2009 +0000
@@ -35,6 +35,7 @@
 } SDL_DisplayModeData;
 
 extern int WIN_InitModes(_THIS);
+extern int WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
 extern void WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
 extern int WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
 extern void WIN_QuitModes(_THIS);
--- a/src/video/win32/SDL_win32video.c	Sun Dec 06 06:21:39 2009 +0000
+++ b/src/video/win32/SDL_win32video.c	Sun Dec 06 08:03:38 2009 +0000
@@ -160,6 +160,7 @@
     /* Set the function pointers */
     device->VideoInit = WIN_VideoInit;
     device->VideoQuit = WIN_VideoQuit;
+    device->GetDisplayBounds = WIN_GetDisplayBounds;
     device->GetDisplayModes = WIN_GetDisplayModes;
     device->SetDisplayMode = WIN_SetDisplayMode;
     device->SetDisplayGammaRamp = WIN_SetDisplayGammaRamp;
--- a/src/video/win32/SDL_win32window.c	Sun Dec 06 06:21:39 2009 +0000
+++ b/src/video/win32/SDL_win32window.c	Sun Dec 06 08:03:38 2009 +0000
@@ -185,12 +185,14 @@
 WIN_CreateWindow(_THIS, SDL_Window * window)
 {
     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
+    SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
     RAWINPUTDEVICE Rid;
     AXIS TabX, TabY;
     LOGCONTEXTA lc;
     HWND hwnd;
     HWND top;
     RECT rect;
+    SDL_Rect bounds;
     DWORD style = (WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
     int x, y;
     int w, h;
@@ -219,19 +221,28 @@
     w = (rect.right - rect.left);
     h = (rect.bottom - rect.top);
 
+    WIN_GetDisplayBounds(_this, display, &bounds);
     if ((window->flags & SDL_WINDOW_FULLSCREEN)
         || window->x == SDL_WINDOWPOS_CENTERED) {
-        x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
+        x = bounds.x + (bounds.w - window->w) / 2;
     } else if (window->x == SDL_WINDOWPOS_UNDEFINED) {
-        x = CW_USEDEFAULT;
+        if (bounds.x == 0) {
+            x = CW_USEDEFAULT;
+        } else {
+            x = bounds.x;
+        }
     } else {
         x = window->x + rect.left;
     }
     if ((window->flags & SDL_WINDOW_FULLSCREEN)
         || window->y == SDL_WINDOWPOS_CENTERED) {
-        y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
-    } else if (window->y == SDL_WINDOWPOS_UNDEFINED) {
-        y = CW_USEDEFAULT;
+        y = bounds.y + (bounds.h - window->h) / 2;
+    } else if (window->x == SDL_WINDOWPOS_UNDEFINED) {
+        if (bounds.x == 0) {
+            y = CW_USEDEFAULT;
+        } else {
+            y = bounds.y;
+        }
     } else {
         y = window->y + rect.top;
     }
@@ -416,8 +427,10 @@
 void
 WIN_SetWindowPosition(_THIS, SDL_Window * window)
 {
+    SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
     RECT rect;
+    SDL_Rect bounds;
     DWORD style;
     HWND top;
     BOOL menu;
@@ -441,15 +454,16 @@
 #endif
     AdjustWindowRectEx(&rect, style, menu, 0);
 
+    WIN_GetDisplayBounds(_this, display, &bounds);
     if ((window->flags & SDL_WINDOW_FULLSCREEN)
         || window->x == SDL_WINDOWPOS_CENTERED) {
-        x = (GetSystemMetrics(SM_CXSCREEN) - window->w) / 2;
+        x = bounds.x + (bounds.w - window->w) / 2;
     } else {
         x = window->x + rect.left;
     }
     if ((window->flags & SDL_WINDOW_FULLSCREEN)
         || window->y == SDL_WINDOWPOS_CENTERED) {
-        y = (GetSystemMetrics(SM_CYSCREEN) - window->h) / 2;
+        y = bounds.y + (bounds.h - window->h) / 2;
     } else {
         y = window->y + rect.top;
     }
--- a/test/testvidinfo.c	Sun Dec 06 06:21:39 2009 +0000
+++ b/test/testvidinfo.c	Sun Dec 06 08:03:38 2009 +0000
@@ -449,7 +449,12 @@
     }
     printf("Number of displays: %d\n", SDL_GetNumVideoDisplays());
     for (d = 0; d < SDL_GetNumVideoDisplays(); ++d) {
-        printf("Display %d:\n", d);
+        SDL_Rect bounds;
+
+        SDL_GetDisplayBounds(d, &bounds);
+        printf("Display %d: %dx%d at %d,%d\n", d,
+               bounds.w, bounds.h, bounds.x, bounds.y);
+
         SDL_SelectVideoDisplay(d);
 
         SDL_GetDesktopDisplayMode(&mode);