From 25eb8c8c898d842d157a064aa0d767353e6edf3a Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 6 Dec 2009 08:03:38 +0000 Subject: [PATCH] Added an API function to query geometry of multiple monitors: SDL_GetDisplayBounds() Implemented multi-monitor window positions on Windows --- include/SDL_video.h | 11 ++++++++++ src/video/SDL_sysvideo.h | 5 +++++ src/video/SDL_video.c | 35 +++++++++++++++++++++++++++++++ src/video/cocoa/SDL_cocoamodes.h | 2 +- src/video/cocoa/SDL_cocoamodes.m | 19 ++++++++--------- src/video/cocoa/SDL_cocoamouse.m | 8 +++---- src/video/cocoa/SDL_cocoavideo.m | 1 + src/video/cocoa/SDL_cocoawindow.m | 26 ++++++++++++++--------- src/video/win32/SDL_win32modes.c | 14 ++++++++++++- src/video/win32/SDL_win32modes.h | 1 + src/video/win32/SDL_win32video.c | 1 + src/video/win32/SDL_win32window.c | 28 ++++++++++++++++++------- test/testvidinfo.c | 7 ++++++- 13 files changed, 124 insertions(+), 34 deletions(-) diff --git a/include/SDL_video.h b/include/SDL_video.h index 3cd737102..6ae110d07 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -343,10 +343,21 @@ extern DECLSPEC const char *SDLCALL SDL_GetCurrentVideoDriver(void); /** * \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. * diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 2e55e5f2a..2cfac4948 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -212,6 +212,11 @@ struct SDL_VideoDevice * Display functions */ + /* + * 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) diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 91c8b5fdd..0e4e9140e 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -334,6 +334,41 @@ SDL_GetNumVideoDisplays(void) return _this->num_displays; } +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) { diff --git a/src/video/cocoa/SDL_cocoamodes.h b/src/video/cocoa/SDL_cocoamodes.h index b45c77e9b..e3249aed7 100644 --- a/src/video/cocoa/SDL_cocoamodes.h +++ b/src/video/cocoa/SDL_cocoamodes.h @@ -35,7 +35,7 @@ typedef struct } 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); diff --git a/src/video/cocoa/SDL_cocoamodes.m b/src/video/cocoa/SDL_cocoamodes.m index 746baab4e..b26905bc9 100644 --- a/src/video/cocoa/SDL_cocoamodes.m +++ b/src/video/cocoa/SDL_cocoamodes.m @@ -200,19 +200,18 @@ - (void) setFrame:(NSRect)frame; 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 diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m index b1f11b6c4..7cad1253c 100644 --- a/src/video/cocoa/SDL_cocoamouse.m +++ b/src/video/cocoa/SDL_cocoamouse.m @@ -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 */ diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m index b61fb29a3..0377c7d33 100644 --- a/src/video/cocoa/SDL_cocoavideo.m +++ b/src/video/cocoa/SDL_cocoavideo.m @@ -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; diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 4ad890f4e..80bceda08 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -378,23 +378,28 @@ - (BOOL)canBecomeMainWindow { 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 @@ - (BOOL)canBecomeMainWindow { 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; } diff --git a/src/video/win32/SDL_win32modes.c b/src/video/win32/SDL_win32modes.c index 60b2b07f5..f606af56a 100644 --- a/src/video/win32/SDL_win32modes.c +++ b/src/video/win32/SDL_win32modes.c @@ -54,7 +54,7 @@ WIN_GetDisplayMode(LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode) 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 @@ WIN_InitModes(_THIS) 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) { diff --git a/src/video/win32/SDL_win32modes.h b/src/video/win32/SDL_win32modes.h index 2f77a7e6d..43db1b11d 100644 --- a/src/video/win32/SDL_win32modes.h +++ b/src/video/win32/SDL_win32modes.h @@ -35,6 +35,7 @@ typedef struct } 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); diff --git a/src/video/win32/SDL_win32video.c b/src/video/win32/SDL_win32video.c index ece7ec475..295fef744 100644 --- a/src/video/win32/SDL_win32video.c +++ b/src/video/win32/SDL_win32video.c @@ -160,6 +160,7 @@ WIN_CreateDevice(int devindex) /* 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; diff --git a/src/video/win32/SDL_win32window.c b/src/video/win32/SDL_win32window.c index 4c706b68e..3a2be6f10 100644 --- a/src/video/win32/SDL_win32window.c +++ b/src/video/win32/SDL_win32window.c @@ -185,12 +185,14 @@ int 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 @@ WIN_CreateWindow(_THIS, SDL_Window * window) 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 @@ WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon) 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 @@ WIN_SetWindowPosition(_THIS, SDL_Window * window) #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; } diff --git a/test/testvidinfo.c b/test/testvidinfo.c index 29b8ad07f..a9e7964d6 100644 --- a/test/testvidinfo.c +++ b/test/testvidinfo.c @@ -449,7 +449,12 @@ main(int argc, char *argv[]) } 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);