diff --git a/include/GL/glfw3.h b/include/GL/glfw3.h index fd792e80..19759cb9 100644 --- a/include/GL/glfw3.h +++ b/include/GL/glfw3.h @@ -520,7 +520,7 @@ GLFWAPI const char* glfwErrorString(int error); GLFWAPI void glfwSetErrorCallback(GLFWerrorfun cbfun); /* Video mode functions */ -GLFWAPI int glfwGetVideoModes(GLFWvidmode* list, int maxcount); +GLFWAPI GLFWvidmode* glfwGetVideoModes(int* count); GLFWAPI void glfwGetDesktopMode(GLFWvidmode* mode); /* Gamma ramp functions */ diff --git a/readme.html b/readme.html index e5fa8c9d..ad62d559 100644 --- a/readme.html +++ b/readme.html @@ -294,6 +294,7 @@ version of GLFW.

  • Changed buffer bit depth parameters of glfwOpenWindow to window hints
  • Changed glfwOpenWindow and glfwSetWindowTitle to use UTF-8 encoded strings
  • Changed glfwGetProcAddress to return a (generic) function pointer
  • +
  • Changed glfwGetVideoModes to return a dynamic, unlimited number of video modes
  • Renamed glfw.h to glfw3.h to avoid conflicts with 2.x series
  • Renamed GLFW_WINDOW token to GLFW_WINDOWED
  • Renamed GLFW_WINDOW_NO_RESIZE to GLFW_WINDOW_RESIZABLE
  • diff --git a/src/cocoa_fullscreen.m b/src/cocoa_fullscreen.m index 147913fb..e02cb2f2 100644 --- a/src/cocoa_fullscreen.m +++ b/src/cocoa_fullscreen.m @@ -197,25 +197,31 @@ void _glfwRestoreVideoMode(void) // Get a list of available video modes //======================================================================== -int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount) +GLFWvidmode* _glfwPlatformGetVideoModes(int* found) { - CGDisplayModeRef mode; CFArrayRef modes; CFIndex count, i; - int stored = 0; + GLFWvidmode* result; modes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), NULL); count = CFArrayGetCount(modes); - for (i = 0; i < count && stored < maxcount; i++) + result = (GLFWvidmode*) malloc(sizeof(GLFWvidmode) * count); + + for (i = 0; i < count; i++) { + CGDisplayModeRef mode; + mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); if (modeIsGood(mode)) - list[stored++] = vidmodeFromCGDisplayMode(mode); + { + result[*found] vidmodeFromCGDisplayMode(mode); + (*found)++; + } } CFRelease(modes); - return stored; + return result; } diff --git a/src/fullscreen.c b/src/fullscreen.c index 631f6193..d613ab7e 100644 --- a/src/fullscreen.c +++ b/src/fullscreen.c @@ -68,6 +68,16 @@ static int compareVideoModes(const void* firstPtr, const void* secondPtr) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// +//======================================================================== +// Lexical comparison of GLFW video modes +//======================================================================== + +int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second) +{ + return compareVideoModes(first, second); +} + + //======================================================================== // Convert BPP to RGB bits based on "best guess" //======================================================================== @@ -100,36 +110,27 @@ void _glfwSplitBPP(int bpp, int* red, int* green, int* blue) // Get a list of available video modes //======================================================================== -GLFWAPI int glfwGetVideoModes(GLFWvidmode* list, int maxcount) +GLFWAPI GLFWvidmode* glfwGetVideoModes(int* count) { - int count; - if (!_glfwInitialized) { _glfwSetError(GLFW_NOT_INITIALIZED, NULL); - return 0; + return NULL; } - if (maxcount <= 0) + if (count == NULL) { - _glfwSetError(GLFW_INVALID_VALUE, - "glfwGetVideoModes: Parameter 'maxcount' must be " - "greater than zero"); - return 0; + _glfwSetError(GLFW_INVALID_VALUE, NULL); + return NULL; } - if (list == NULL) - { - _glfwSetError(GLFW_INVALID_VALUE, - "glfwGetVideoModes: Parameter 'list' cannot be NULL"); - return 0; - } + free(_glfwLibrary.modes); - count = _glfwPlatformGetVideoModes(list, maxcount); - if (count > 0) - qsort(list, count, sizeof(GLFWvidmode), compareVideoModes); + _glfwLibrary.modes = _glfwPlatformGetVideoModes(count); + if (_glfwLibrary.modes) + qsort(_glfwLibrary.modes, *count, sizeof(GLFWvidmode), compareVideoModes); - return count; + return _glfwLibrary.modes; } diff --git a/src/init.c b/src/init.c index 336cfe25..eab5869f 100644 --- a/src/init.c +++ b/src/init.c @@ -84,6 +84,9 @@ GLFWAPI void glfwTerminate(void) if (!_glfwPlatformTerminate()) return; + if (_glfwLibrary.modes) + free(_glfwLibrary.modes); + _glfwInitialized = GL_FALSE; } diff --git a/src/internal.h b/src/internal.h index 4e18c93c..99d74b86 100644 --- a/src/internal.h +++ b/src/internal.h @@ -251,6 +251,8 @@ struct _GLFWlibrary int originalRampSize; GLboolean rampChanged; + GLFWvidmode* modes; + // This is defined in the current port's platform.h _GLFW_PLATFORM_LIBRARY_WINDOW_STATE; _GLFW_PLATFORM_LIBRARY_OPENGL_STATE; @@ -287,7 +289,7 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, int x, int y); void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode); // Fullscreen -int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount); +GLFWvidmode* _glfwPlatformGetVideoModes(int* count); void _glfwPlatformGetDesktopMode(GLFWvidmode* mode); // Gamma ramp @@ -335,6 +337,7 @@ void _glfwPlatformCopyContext(_GLFWwindow* src, _GLFWwindow* dst, unsigned long //======================================================================== // Fullscren management (fullscreen.c) +int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second); void _glfwSplitBPP(int bpp, int* red, int* green, int* blue); // Error handling (error.c) diff --git a/src/win32_fullscreen.c b/src/win32_fullscreen.c index de3d898b..c04e5ff1 100644 --- a/src/win32_fullscreen.c +++ b/src/win32_fullscreen.c @@ -182,71 +182,78 @@ void _glfwRestoreVideoMode(void) // Get a list of available video modes //======================================================================== -int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount) +GLFWvidmode* _glfwPlatformGetVideoModes(int* found) { - int count, success, mode, i, j; - int m1, m2, bpp, r, g, b; - DEVMODE dm; + int dmIndex = 0, count = 0; + GLFWvidmode* result = NULL; - // Loop through all video modes and extract all the UNIQUE modes - count = 0; - mode = 0; + *found = 0; - do + for (;;) { - // Get video mode properties + int i; + GLFWvidmode mode; + DEVMODE dm; + + ZeroMemory(&dm, sizeof(DEVMODE)); dm.dmSize = sizeof(DEVMODE); - success = EnumDisplaySettings(NULL, mode, &dm); - // Is it a valid mode? (only list depths >= 15 bpp) - if (success && dm.dmBitsPerPel >= 15) + if (!EnumDisplaySettings(NULL, dmIndex, &dm)) + break; + + dmIndex++; + + if (dm.dmBitsPerPel < 15) { - // Convert to RGB, and back to bpp ("mask out" alpha bits etc) - _glfwSplitBPP(dm.dmBitsPerPel, &r, &g, &b); - bpp = r + g + b; - - // Mode "code" for this mode - m1 = (bpp << 25) | (dm.dmPelsWidth * dm.dmPelsHeight); - - // Insert mode in list (sorted), and avoid duplicates - for (i = 0; i < count; i++) - { - // Mode "code" for already listed mode - bpp = list[i].redBits + list[i].greenBits + list[i].blueBits; - m2 = (bpp << 25) | (list[i].width * list[i].height); - if (m1 <= m2) - break; - } - - // New entry at the end of the list? - if (i >= count) - { - list[count].width = dm.dmPelsWidth; - list[count].height = dm.dmPelsHeight; - list[count].redBits = r; - list[count].greenBits = g; - list[count].blueBits = b; - count ++; - } - // Insert new entry in the list? - else if (m1 < m2) - { - for (j = count; j > i; j--) - list[j] = list[j - 1]; - - list[i].width = dm.dmPelsWidth; - list[i].height = dm.dmPelsHeight; - list[i].redBits = r; - list[i].greenBits = g; - list[i].blueBits = b; - count++; - } + // Skip modes with less than 15 BPP + continue; } - mode++; - } - while (success && (count < maxcount)); - return count; + mode.width = dm.dmPelsWidth; + mode.height = dm.dmPelsHeight; + _glfwSplitBPP(dm.dmBitsPerPel, + &mode.redBits, + &mode.greenBits, + &mode.blueBits); + + for (i = 0; i < *found; i++) + { + if (_glfwCompareVideoModes(result + i, &mode) == 0) + break; + } + + if (i < *found) + { + // This is a duplicate, so skip it + continue; + } + + if (*found == count) + { + void* larger; + + if (count) + count *= 2; + else + count = 128; + + larger = realloc(result, count * sizeof(GLFWvidmode)); + if (!larger) + { + free(result); + + _glfwSetError(GLFW_OUT_OF_MEMORY, NULL); + return NULL; + } + + result = (GLFWvidmode*) larger; + } + + result[*found] = mode; + (*found)++; + } + + return result; } diff --git a/src/x11_fullscreen.c b/src/x11_fullscreen.c index 7ad11ec5..34beae6a 100644 --- a/src/x11_fullscreen.c +++ b/src/x11_fullscreen.c @@ -32,6 +32,7 @@ #include #include +#include ////////////////////////////////////////////////////////////////////////// @@ -325,92 +326,94 @@ void _glfwRestoreVideoMode(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -struct _glfwResolution +typedef struct { int width; int height; -}; +} _GLFWvidsize; + //======================================================================== // List available video modes //======================================================================== -int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount) +GLFWvidmode* _glfwPlatformGetVideoModes(int* found) { - int count, k, l, r, g, b, rgba, gl; - int depth; - XVisualInfo* vislist; + XVisualInfo* visuals; XVisualInfo dummy; - int viscount, rgbcount, rescount; - int* rgbarray; - struct _glfwResolution* resarray; + int i, j, visualCount, sizeCount, rgbCount; + int* rgbs; + _GLFWvidsize* sizes; + GLFWvidmode* result; - // Get list of visuals - vislist = XGetVisualInfo(_glfwLibrary.X11.display, 0, &dummy, &viscount); - if (vislist == NULL) + visuals = XGetVisualInfo(_glfwLibrary.X11.display, 0, &dummy, &visualCount); + if (visuals == NULL) { _glfwSetError(GLFW_PLATFORM_ERROR, "X11/GLX: Failed to retrieve the available visuals"); return 0; } - rgbarray = (int*) malloc(sizeof(int) * viscount); - rgbcount = 0; + // Build array of available RGB channel depths - // Build RGB array - for (k = 0; k < viscount; k++) + rgbs = (int*) malloc(sizeof(int) * visualCount); + rgbCount = 0; + + for (i = 0; i < visualCount; i++) { - // Does the visual support OpenGL & true color? - glXGetConfig(_glfwLibrary.X11.display, &vislist[k], GLX_USE_GL, &gl); - glXGetConfig(_glfwLibrary.X11.display, &vislist[k], GLX_RGBA, &rgba); - if (gl && rgba) + int gl, rgba, rgb, r, g, b; + + glXGetConfig(_glfwLibrary.X11.display, &visuals[i], GLX_USE_GL, &gl); + glXGetConfig(_glfwLibrary.X11.display, &visuals[i], GLX_RGBA, &rgba); + + if (!gl || !rgba) { - // Get color depth for this visual - depth = vislist[k].depth; - - // Convert to RGB - _glfwSplitBPP(depth, &r, &g, &b); - depth = (r << 16) | (g << 8) | b; - - // Is this mode unique? - for (l = 0; l < rgbcount; l++) - { - if (depth == rgbarray[l]) - break; - } - - if (l >= rgbcount) - { - rgbarray[rgbcount] = depth; - rgbcount++; - } + // The visual lacks OpenGL or true color, so skip it + continue; } + + // Convert to RGB channel depths and encode + _glfwSplitBPP(visuals[i].depth, &r, &g, &b); + rgb = (r << 16) | (g << 8) | b; + + for (j = 0; j < rgbCount; j++) + { + if (rgbs[j] == rgb) + break; + } + + if (j < rgbCount) + { + // This channel depth is a duplicate, so skip it + continue; + } + + rgbs[rgbCount] = rgb; + rgbCount++; } - XFree(vislist); + XFree(visuals); - rescount = 0; - resarray = NULL; + sizeCount = 0; + sizes = NULL; - // Build resolution array + // Build array of available resolutions if (_glfwLibrary.X11.RandR.available) { #if defined(_GLFW_HAS_XRANDR) XRRScreenConfiguration* sc; - XRRScreenSize* sizelist; - int sizecount; + XRRScreenSize* rrSizes; sc = XRRGetScreenInfo(_glfwLibrary.X11.display, _glfwLibrary.X11.root); - sizelist = XRRConfigSizes(sc, &sizecount); + rrSizes = XRRConfigSizes(sc, &sizeCount); - resarray = (struct _glfwResolution*) malloc(sizeof(struct _glfwResolution) * sizecount); + sizes = (_GLFWvidsize*) malloc(sizeof(_GLFWvidsize) * sizeCount); - for (k = 0; k < sizecount; k++) + for (i = 0; i < sizeCount; i++) { - resarray[rescount].width = sizelist[k].width; - resarray[rescount].height = sizelist[k].height; - rescount++; + sizes[i].width = rrSizes[i].width; + sizes[i].height = rrSizes[i].height; } XRRFreeScreenConfigInfo(sc); @@ -419,69 +422,75 @@ int _glfwPlatformGetVideoModes(GLFWvidmode* list, int maxcount) else if (_glfwLibrary.X11.VidMode.available) { #if defined(_GLFW_HAS_XF86VIDMODE) - XF86VidModeModeInfo** modelist; - int modecount, width, height; + XF86VidModeModeInfo** modes; + int modeCount; XF86VidModeGetAllModeLines(_glfwLibrary.X11.display, _glfwLibrary.X11.screen, - &modecount, &modelist); + &modeCount, &modes); - resarray = (struct _glfwResolution*) malloc(sizeof(struct _glfwResolution) * modecount); + sizes = (_GLFWvidsize*) malloc(sizeof(_GLFWvidsize) * modeCount); - for (k = 0; k < modecount; k++) + for (i = 0; i < modeCount; i++) { - width = modelist[k]->hdisplay; - height = modelist[k]->vdisplay; + _GLFWvidsize size; + size.width = modes[i]->hdisplay; + size.height = modes[i]->vdisplay; - // Is this mode unique? - for (l = 0; l < rescount; l++) + for (j = 0; j < sizeCount; j++) { - if (width == resarray[l].width && height == resarray[l].height) + if (memcmp(sizes + j, &size, sizeof(_GLFWvidsize)) == 0) break; } - if (l >= rescount) + if (j < sizeCount) { - resarray[rescount].width = width; - resarray[rescount].height = height; - rescount++; + // This size is a duplicate, so skip it + continue; } + + sizes[sizeCount] = size; + sizeCount++; } - XFree(modelist); + XFree(modes); #endif /*_GLFW_HAS_XF86VIDMODE*/ } - if (!resarray) + if (!sizeCount) { - rescount = 1; - resarray = (struct _glfwResolution*) malloc(sizeof(struct _glfwResolution) * rescount); + sizeCount = 1; + sizes = (_GLFWvidsize*) malloc(sizeof(_GLFWvidsize)); - resarray[0].width = DisplayWidth(_glfwLibrary.X11.display, - _glfwLibrary.X11.screen); - resarray[0].height = DisplayHeight(_glfwLibrary.X11.display, - _glfwLibrary.X11.screen); + sizes[0].width = DisplayWidth(_glfwLibrary.X11.display, + _glfwLibrary.X11.screen); + sizes[0].height = DisplayHeight(_glfwLibrary.X11.display, + _glfwLibrary.X11.screen); } - // Build permutations of colors and resolutions - count = 0; - for (k = 0; k < rgbcount && count < maxcount; k++) + // Build all permutations of channel depths and resolutions + + result = (GLFWvidmode*) malloc(sizeof(GLFWvidmode) * rgbCount * sizeCount); + *found = 0; + + for (i = 0; i < rgbCount; i++) { - for (l = 0; l < rescount && count < maxcount; l++) + for (j = 0; j < sizeCount; j++) { - list[count].width = resarray[l].width; - list[count].height = resarray[l].height; - list[count].redBits = (rgbarray[k] >> 16) & 255; - list[count].greenBits = (rgbarray[k] >> 8) & 255; - list[count].blueBits = rgbarray[k] & 255; - count++; + result[*found].width = sizes[j].width; + result[*found].height = sizes[j].height; + result[*found].redBits = (rgbs[i] >> 16) & 255; + result[*found].greenBits = (rgbs[i] >> 8) & 255; + result[*found].blueBits = rgbs[i] & 255; + + (*found)++; } } - free(resarray); - free(rgbarray); + free(sizes); + free(rgbs); - return count; + return result; } diff --git a/tests/modes.c b/tests/modes.c index 3a384003..0f2452c7 100644 --- a/tests/modes.c +++ b/tests/modes.c @@ -90,29 +90,11 @@ static void key_callback(GLFWwindow dummy, int key, int action) } } -static GLFWvidmode* get_video_modes(size_t* found) -{ - size_t count = 0; - GLFWvidmode* modes = NULL; - - for (;;) - { - count += 256; - modes = realloc(modes, sizeof(GLFWvidmode) * count); - - *found = glfwGetVideoModes(modes, count); - if (*found < count) - break; - } - - return modes; -} - static void list_modes(void) { size_t count, i; GLFWvidmode desktop_mode; - GLFWvidmode* modes = get_video_modes(&count); + GLFWvidmode* modes = glfwGetVideoModes(&count); glfwGetDesktopMode(&desktop_mode); printf("Desktop mode: %s\n", format_mode(&desktop_mode)); @@ -128,15 +110,13 @@ static void list_modes(void) putchar('\n'); } - - free(modes); } static void test_modes(void) { int width, height; size_t i, count; - GLFWvidmode* modes = get_video_modes(&count); + GLFWvidmode* modes = glfwGetVideoModes(&count); glfwSetWindowSizeCallback(window_size_callback); glfwSetWindowCloseCallback(window_close_callback); @@ -207,8 +187,6 @@ static void test_modes(void) glfwPollEvents(); window = NULL; } - - free(modes); } int main(int argc, char** argv)