浏览代码

Restructure monitor enumeration

This way is both kinder on event-based enumeration and less work to
unwind allocations for when properly implementing GLFW_OUT_OF_MEMORY.
Camilla Löwy 8 年之前
父节点
当前提交
04f559e28d
共有 21 个文件被更改,包括 377 次插入480 次删除
  1. 1 0
      src/cocoa_init.m
  2. 60 49
      src/cocoa_monitor.m
  3. 1 0
      src/cocoa_platform.h
  4. 1 1
      src/cocoa_window.m
  5. 0 1
      src/init.c
  6. 4 16
      src/internal.h
  7. 1 0
      src/mir_init.c
  8. 20 26
      src/mir_monitor.c
  9. 26 60
      src/monitor.c
  10. 0 12
      src/osmesa_monitor.c
  11. 1 0
      src/win32_init.c
  12. 106 75
      src/win32_monitor.c
  13. 1 0
      src/win32_platform.h
  14. 1 1
      src/win32_window.c
  15. 0 3
      src/wl_init.c
  16. 25 109
      src/wl_monitor.c
  17. 2 13
      src/wl_platform.h
  18. 1 0
      src/x11_init.c
  19. 124 113
      src/x11_monitor.c
  20. 1 0
      src/x11_platform.h
  21. 1 1
      src/x11_window.c

+ 1 - 0
src/cocoa_init.m

@@ -322,6 +322,7 @@ int _glfwPlatformInit(void)
     _glfwInitTimerNS();
     _glfwInitJoysticksNS();
 
+    _glfwPollMonitorsNS();
     return GLFW_TRUE;
 }
 

+ 60 - 49
src/cocoa_monitor.m

@@ -209,6 +209,66 @@ static void endFadeReservation(CGDisplayFadeReservationToken token)
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
+// Poll for changes in the set of connected monitors
+//
+void _glfwPollMonitorsNS(void)
+{
+    uint32_t i, j, displayCount, disconnectedCount;
+    CGDirectDisplayID* displays;
+    _GLFWmonitor** disconnected;
+
+    CGGetOnlineDisplayList(0, NULL, &displayCount);
+    displays = calloc(displayCount, sizeof(CGDirectDisplayID));
+    CGGetOnlineDisplayList(displayCount, displays, &displayCount);
+
+    disconnectedCount = _glfw.monitorCount;
+    disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
+    memcpy(disconnected, _glfw.monitors, _glfw.monitorCount * sizeof(_GLFWmonitor*));
+
+    for (i = 0;  i < displayCount;  i++)
+    {
+        _GLFWmonitor* monitor;
+        const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);
+
+        if (CGDisplayIsAsleep(displays[i]))
+            continue;
+
+        for (j = 0;  j < disconnectedCount;  j++)
+        {
+            // HACK: Compare unit numbers instead of display IDs to work around
+            //       display replacement on machines with automatic graphics
+            //       switching
+            if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber)
+            {
+                disconnected[j] = NULL;
+                break;
+            }
+        }
+
+        const CGSize size = CGDisplayScreenSize(displays[i]);
+        char* name = getDisplayName(displays[i]);
+        if (!name)
+            name = strdup("Unknown");
+
+        monitor = _glfwAllocMonitor(name, size.width, size.height);
+        monitor->ns.displayID  = displays[i];
+        monitor->ns.unitNumber = unitNumber;
+
+        free(name);
+
+        _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
+    }
+
+    for (i = 0;  i < disconnectedCount;  i++)
+    {
+        if (disconnected[i])
+            _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
+    }
+
+    free(disconnected);
+    free(displays);
+}
+
 // Change the current video mode
 //
 GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
@@ -288,55 +348,6 @@ void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor)
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
-{
-    uint32_t i, found = 0, displayCount;
-    _GLFWmonitor** monitors;
-    CGDirectDisplayID* displays;
-
-    *count = 0;
-
-    CGGetOnlineDisplayList(0, NULL, &displayCount);
-    displays = calloc(displayCount, sizeof(CGDirectDisplayID));
-    monitors = calloc(displayCount, sizeof(_GLFWmonitor*));
-
-    CGGetOnlineDisplayList(displayCount, displays, &displayCount);
-
-    for (i = 0;  i < displayCount;  i++)
-    {
-        _GLFWmonitor* monitor;
-
-        if (CGDisplayIsAsleep(displays[i]))
-            continue;
-
-        const CGSize size = CGDisplayScreenSize(displays[i]);
-        char* name = getDisplayName(displays[i]);
-        if (!name)
-            name = strdup("Unknown");
-
-        monitor = _glfwAllocMonitor(name, size.width, size.height);
-        monitor->ns.displayID  = displays[i];
-        monitor->ns.unitNumber = CGDisplayUnitNumber(displays[i]);
-
-        free(name);
-
-        found++;
-        monitors[found - 1] = monitor;
-    }
-
-    free(displays);
-
-    *count = found;
-    return monitors;
-}
-
-GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
-{
-    // HACK: Compare unit numbers instead of display IDs to work around display
-    //       replacement on machines with automatic graphics switching
-    return first->ns.unitNumber == second->ns.unitNumber;
-}
-
 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
 {
     const CGRect bounds = CGDisplayBounds(monitor->ns.displayID);

+ 1 - 0
src/cocoa_platform.h

@@ -158,6 +158,7 @@ typedef struct _GLFWtimeNS
 
 void _glfwInitTimerNS(void);
 
+void _glfwPollMonitorsNS(void);
 GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
 void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
 

+ 1 - 1
src/cocoa_window.m

@@ -340,7 +340,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 
 - (void)applicationDidChangeScreenParameters:(NSNotification *) notification
 {
-    _glfwInputMonitorChange();
+    _glfwPollMonitorsNS();
 }
 
 - (void)applicationDidFinishLaunching:(NSNotification *)notification

+ 0 - 1
src/init.c

@@ -130,7 +130,6 @@ GLFWAPI int glfwInit(void)
         return GLFW_FALSE;
     }
 
-    _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount);
     _glfwInitialized = GLFW_TRUE;
 
     _glfw.timerOffset = _glfwPlatformGetTimerValue();

+ 4 - 16
src/internal.h

@@ -48,6 +48,9 @@
 #define GLFW_INCLUDE_NONE
 #include "../include/GLFW/glfw3.h"
 
+#define _GLFW_INSERT_FIRST      0
+#define _GLFW_INSERT_LAST       1
+
 typedef int GLFWbool;
 
 typedef struct _GLFWwndconfig   _GLFWwndconfig;
@@ -563,21 +566,6 @@ const char* _glfwPlatformGetKeyName(int key, int scancode);
  */
 int _glfwPlatformGetKeyScancode(int key);
 
-/*! @copydoc glfwGetMonitors
- *  @ingroup platform
- */
-_GLFWmonitor** _glfwPlatformGetMonitors(int* count);
-
-/*! @brief Checks whether two monitor objects represent the same monitor.
- *
- *  @param[in] first The first monitor.
- *  @param[in] second The second monitor.
- *  @return @c GLFW_TRUE if the monitor objects represent the same monitor, or
- *  @c GLFW_FALSE otherwise.
- *  @ingroup platform
- */
-GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second);
-
 /*! @copydoc glfwGetMonitorPos
  *  @ingroup platform
  */
@@ -959,7 +947,7 @@ void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered);
 
 /*! @ingroup event
  */
-void _glfwInputMonitorChange(void);
+void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int type);
 
 /*! @ingroup event
  */

+ 1 - 0
src/mir_init.c

@@ -213,6 +213,7 @@ int _glfwPlatformInit(void)
         return GLFW_FALSE;
     }
 
+    _glfwPollMonitorsMir();
     return GLFW_TRUE;
 }
 

+ 20 - 26
src/mir_monitor.c

@@ -30,18 +30,17 @@
 
 
 //////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
+//////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
+// Poll for changes in the set of connected monitors
+//
+void _glfwPollMonitorsMir(void)
 {
-    int i, found = 0;
-    _GLFWmonitor** monitors = NULL;
+    int i;
     MirDisplayConfiguration* displayConfig =
         mir_connection_create_display_config(_glfw.mir.connection);
 
-    *count = 0;
-
     for (i = 0;  i < displayConfig->num_outputs;  i++)
     {
         const MirDisplayOutput* out = displayConfig->outputs + i;
@@ -51,32 +50,27 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
             out->num_modes &&
             out->current_mode < out->num_modes)
         {
-            found++;
-            monitors        = realloc(monitors, sizeof(_GLFWmonitor*) * found);
-            monitors[i]     = _glfwAllocMonitor("Unknown",
-                                                out->physical_width_mm,
-                                                out->physical_height_mm);
-
-            monitors[i]->mir.x         = out->position_x;
-            monitors[i]->mir.y         = out->position_y;
-            monitors[i]->mir.outputId  = out->output_id;
-            monitors[i]->mir.curMode   = out->current_mode;
-
-            monitors[i]->modes = _glfwPlatformGetVideoModes(monitors[i],
-                                                            &monitors[i]->modeCount);
+            _GLFWmonitor* monitor = _glfwAllocMonitor("Unknown",
+                                                      out->physical_width_mm,
+                                                      out->physical_height_mm);
+
+            monitor->mir.x        = out->position_x;
+            monitor->mir.y        = out->position_y;
+            monitor->mir.outputId = out->output_id;
+            monitor->mir.curMode  = out->current_mode;
+            monitor->modes = _glfwPlatformGetVideoModes(monitor, &monitor->modeCount);
+
+            _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
         }
     }
 
     mir_display_config_destroy(displayConfig);
-
-    *count = found;
-    return monitors;
 }
 
-GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
-{
-    return first->mir.outputId == second->mir.outputId;
-}
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
 
 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
 {

+ 26 - 60
src/monitor.c

@@ -86,80 +86,46 @@ static GLFWbool refreshVideoModes(_GLFWmonitor* monitor)
 //////                         GLFW event API                       //////
 //////////////////////////////////////////////////////////////////////////
 
-void _glfwInputMonitorChange(void)
+void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int type)
 {
-    int i, j, monitorCount = _glfw.monitorCount;
-    _GLFWmonitor** monitors = _glfw.monitors;
-
-    _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount);
-
-    // Re-use still connected monitor objects
-
-    for (i = 0;  i < _glfw.monitorCount;  i++)
-    {
-        for (j = 0;  j < monitorCount;  j++)
-        {
-            if (_glfwPlatformIsSameMonitor(_glfw.monitors[i], monitors[j]))
-            {
-                _glfwFreeMonitor(_glfw.monitors[i]);
-                _glfw.monitors[i] = monitors[j];
-                break;
-            }
-        }
-    }
-
-    // Find and report disconnected monitors (not in the new list)
-
-    for (i = 0;  i < monitorCount;  i++)
+    if (action == GLFW_CONNECTED)
     {
-        _GLFWwindow* window;
+        _glfw.monitorCount++;
+        _glfw.monitors =
+            realloc(_glfw.monitors, sizeof(_GLFWmonitor*) * _glfw.monitorCount);
 
-        for (j = 0;  j < _glfw.monitorCount;  j++)
+        if (type == _GLFW_INSERT_FIRST)
         {
-            if (monitors[i] == _glfw.monitors[j])
-                break;
+            memmove(_glfw.monitors + 1,
+                    _glfw.monitors,
+                    (_glfw.monitorCount - 1) * sizeof(_GLFWmonitor*));
+            _glfw.monitors[0] = monitor;
         }
-
-        if (j < _glfw.monitorCount)
-            continue;
-
-        for (window = _glfw.windowListHead;  window;  window = window->next)
-        {
-            if (window->monitor == monitors[i])
-            {
-                int width, height;
-                _glfwPlatformGetWindowSize(window, &width, &height);
-                _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0);
-            }
-        }
-
-        if (_glfw.callbacks.monitor)
-            _glfw.callbacks.monitor((GLFWmonitor*) monitors[i], GLFW_DISCONNECTED);
+        else
+            _glfw.monitors[_glfw.monitorCount - 1] = monitor;
     }
-
-    // Find and report newly connected monitors (not in the old list)
-    // Re-used monitor objects are then removed from the old list to avoid
-    // having them destroyed at the end of this function
-
-    for (i = 0;  i < _glfw.monitorCount;  i++)
+    else if (action == GLFW_DISCONNECTED)
     {
-        for (j = 0;  j < monitorCount;  j++)
+        int i;
+
+        for (i = 0;  i < _glfw.monitorCount;  i++)
         {
-            if (_glfw.monitors[i] == monitors[j])
+            if (_glfw.monitors[i] == monitor)
             {
-                monitors[j] = NULL;
+                _glfw.monitorCount--;
+                memmove(_glfw.monitors + i,
+                        _glfw.monitors + i + 1,
+                        (_glfw.monitorCount - i) * sizeof(_GLFWmonitor*));
                 break;
             }
         }
-
-        if (j < monitorCount)
-            continue;
-
-        if (_glfw.callbacks.monitor)
-            _glfw.callbacks.monitor((GLFWmonitor*) _glfw.monitors[i], GLFW_CONNECTED);
     }
 
-    _glfwFreeMonitors(monitors, monitorCount);
+    if (_glfw.callbacks.monitor)
+        _glfw.callbacks.monitor((GLFWmonitor*) monitor, action);
+
+    if (action == GLFW_DISCONNECTED)
+        _glfwFreeMonitor(monitor);
 }
 
 void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window)

+ 0 - 12
src/osmesa_monitor.c

@@ -32,18 +32,6 @@
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
-{
-    // OSMesa is headless, so no monitors
-    *count = 0;
-    return NULL;
-}
-
-int _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
-{
-    return GLFW_FALSE;
-}
-
 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
 {
 }

+ 1 - 0
src/win32_init.c

@@ -433,6 +433,7 @@ int _glfwPlatformInit(void)
     _glfwInitTimerWin32();
     _glfwInitJoysticksWin32();
 
+    _glfwPollMonitorsWin32();
     return GLFW_TRUE;
 }
 

+ 106 - 75
src/win32_monitor.c

@@ -90,71 +90,21 @@ static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-// Change the current video mode
+// Poll for changes in the set of connected monitors
 //
-GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
+void _glfwPollMonitorsWin32(void)
 {
-    GLFWvidmode current;
-    const GLFWvidmode* best;
-    DEVMODEW dm;
-
-    best = _glfwChooseVideoMode(monitor, desired);
-    _glfwPlatformGetVideoMode(monitor, &current);
-    if (_glfwCompareVideoModes(&current, best) == 0)
-        return GLFW_TRUE;
-
-    ZeroMemory(&dm, sizeof(dm));
-    dm.dmSize = sizeof(DEVMODEW);
-    dm.dmFields           = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
-                            DM_DISPLAYFREQUENCY;
-    dm.dmPelsWidth        = best->width;
-    dm.dmPelsHeight       = best->height;
-    dm.dmBitsPerPel       = best->redBits + best->greenBits + best->blueBits;
-    dm.dmDisplayFrequency = best->refreshRate;
-
-    if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
-        dm.dmBitsPerPel = 32;
-
-    if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
-                                 &dm,
-                                 NULL,
-                                 CDS_FULLSCREEN,
-                                 NULL) != DISP_CHANGE_SUCCESSFUL)
-    {
-        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode");
-        return GLFW_FALSE;
-    }
-
-    monitor->win32.modeChanged = GLFW_TRUE;
-    return GLFW_TRUE;
-}
-
-// Restore the previously saved (original) video mode
-//
-void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
-{
-    if (monitor->win32.modeChanged)
-    {
-        ChangeDisplaySettingsExW(monitor->win32.adapterName,
-                                 NULL, NULL, CDS_FULLSCREEN, NULL);
-        monitor->win32.modeChanged = GLFW_FALSE;
-    }
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-//////                       GLFW platform API                      //////
-//////////////////////////////////////////////////////////////////////////
-
-_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
-{
-    int found = 0;
-    DWORD adapterIndex, displayIndex, primaryIndex = 0;
+    int i, disconnectedCount;
+    _GLFWmonitor** disconnected;
+    DWORD adapterIndex, displayIndex;
     DISPLAY_DEVICEW adapter, display;
     GLFWbool hasDisplays = GLFW_FALSE;
-    _GLFWmonitor** monitors = NULL;
 
-    *count = 0;
+    disconnectedCount = _glfw.monitorCount;
+    disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
+    memcpy(disconnected,
+           _glfw.monitors,
+           _glfw.monitorCount * sizeof(_GLFWmonitor*));
 
     // HACK: Check if any active adapters have connected displays
     //       If not, this is a headless system or a VMware guest
@@ -182,6 +132,8 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
 
     for (adapterIndex = 0;  ;  adapterIndex++)
     {
+        int type = _GLFW_INSERT_LAST;
+
         ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW));
         adapter.cb = sizeof(DISPLAY_DEVICEW);
 
@@ -192,7 +144,7 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
             continue;
 
         if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
-            primaryIndex = found;
+            type = _GLFW_INSERT_FIRST;
 
         if (hasDisplays)
         {
@@ -204,33 +156,112 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
                 if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
                     break;
 
-                found++;
-                monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found);
-                monitors[found - 1] = createMonitor(&adapter, &display);
+                for (i = 0;  i < disconnectedCount;  i++)
+                {
+                    if (disconnected[i] &&
+                        wcscmp(disconnected[i]->win32.displayName,
+                               display.DeviceName) == 0)
+                    {
+                        disconnected[i] = NULL;
+                        break;
+                    }
+                }
+
+                if (i < disconnectedCount)
+                    continue;
+
+                _glfwInputMonitor(createMonitor(&adapter, &display),
+                                  GLFW_CONNECTED, type);
+
+                type = _GLFW_INSERT_LAST;
             }
         }
         else
         {
-            found++;
-            monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found);
-            monitors[found - 1] = createMonitor(&adapter, NULL);
+            for (i = 0;  i < disconnectedCount;  i++)
+            {
+                if (disconnected[i] &&
+                    wcscmp(disconnected[i]->win32.adapterName,
+                           adapter.DeviceName) == 0)
+                {
+                    disconnected[i] = NULL;
+                    break;
+                }
+            }
+
+            if (i < disconnectedCount)
+                continue;
+
+            _glfwInputMonitor(createMonitor(&adapter, NULL),
+                              GLFW_CONNECTED, type);
         }
     }
 
-    _GLFW_SWAP_POINTERS(monitors[0], monitors[primaryIndex]);
+    for (i = 0;  i < disconnectedCount;  i++)
+    {
+        if (disconnected[i])
+            _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
+    }
 
-    *count = found;
-    return monitors;
+    free(disconnected);
 }
 
-GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
+// Change the current video mode
+//
+GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
 {
-    if (wcslen(first->win32.displayName))
-        return wcscmp(first->win32.displayName, second->win32.displayName) == 0;
-    else
-        return wcscmp(first->win32.adapterName, second->win32.adapterName) == 0;
+    GLFWvidmode current;
+    const GLFWvidmode* best;
+    DEVMODEW dm;
+
+    best = _glfwChooseVideoMode(monitor, desired);
+    _glfwPlatformGetVideoMode(monitor, &current);
+    if (_glfwCompareVideoModes(&current, best) == 0)
+        return GLFW_TRUE;
+
+    ZeroMemory(&dm, sizeof(dm));
+    dm.dmSize = sizeof(DEVMODEW);
+    dm.dmFields           = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
+                            DM_DISPLAYFREQUENCY;
+    dm.dmPelsWidth        = best->width;
+    dm.dmPelsHeight       = best->height;
+    dm.dmBitsPerPel       = best->redBits + best->greenBits + best->blueBits;
+    dm.dmDisplayFrequency = best->refreshRate;
+
+    if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
+        dm.dmBitsPerPel = 32;
+
+    if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
+                                 &dm,
+                                 NULL,
+                                 CDS_FULLSCREEN,
+                                 NULL) != DISP_CHANGE_SUCCESSFUL)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode");
+        return GLFW_FALSE;
+    }
+
+    monitor->win32.modeChanged = GLFW_TRUE;
+    return GLFW_TRUE;
+}
+
+// Restore the previously saved (original) video mode
+//
+void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
+{
+    if (monitor->win32.modeChanged)
+    {
+        ChangeDisplaySettingsExW(monitor->win32.adapterName,
+                                 NULL, NULL, CDS_FULLSCREEN, NULL);
+        monitor->win32.modeChanged = GLFW_FALSE;
+    }
 }
 
+
+//////////////////////////////////////////////////////////////////////////
+//////                       GLFW platform API                      //////
+//////////////////////////////////////////////////////////////////////////
+
 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
 {
     DEVMODEW settings;

+ 1 - 0
src/win32_platform.h

@@ -345,6 +345,7 @@ char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source);
 
 void _glfwInitTimerWin32(void);
 
+void _glfwPollMonitorsWin32(void);
 GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired);
 void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor);
 

+ 1 - 1
src/win32_window.c

@@ -458,7 +458,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
             {
                 if (wParam == DBT_DEVNODES_CHANGED)
                 {
-                    _glfwInputMonitorChange();
+                    _glfwPollMonitorsWin32();
                     return TRUE;
                 }
                 else if (wParam == DBT_DEVICEARRIVAL)

+ 0 - 3
src/wl_init.c

@@ -650,9 +650,6 @@ int _glfwPlatformInit(void)
     _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
     wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);
 
-    _glfw.wl.monitors = calloc(4, sizeof(_GLFWmonitor*));
-    _glfw.wl.monitorsSize = 4;
-
     createKeyTables();
 
     _glfw.wl.xkb.context = xkb_context_new(0);

+ 25 - 109
src/wl_monitor.c

@@ -32,12 +32,6 @@
 #include <errno.h>
 
 
-struct _GLFWvidmodeWayland
-{
-    GLFWvidmode         base;
-    uint32_t            flags;
-};
-
 static void geometry(void* data,
                      struct wl_output* output,
                      int32_t x,
@@ -50,21 +44,15 @@ static void geometry(void* data,
                      int32_t transform)
 {
     struct _GLFWmonitor *monitor = data;
-    char* name;
-    size_t nameLength;
+    char name[1024];
 
     monitor->wl.x = x;
     monitor->wl.y = y;
     monitor->widthMM = physicalWidth;
     monitor->heightMM = physicalHeight;
 
-    nameLength = strlen(make) + 1 + strlen(model) + 1;
-    name = realloc(monitor->name, nameLength);
-    if (name)
-    {
-        sprintf(name, "%s %s", make, model);
-        monitor->name = name;
-    }
+    snprintf(name, sizeof(name), "%s %s", make, model);
+    monitor->name = strdup(name);
 }
 
 static void mode(void* data,
@@ -75,32 +63,29 @@ static void mode(void* data,
                  int32_t refresh)
 {
     struct _GLFWmonitor *monitor = data;
-    _GLFWvidmodeWayland mode = { { 0 }, };
-
-    mode.base.width = width;
-    mode.base.height = height;
-    mode.base.refreshRate = refresh / 1000;
-    mode.flags = flags;
-
-    if (monitor->wl.modesCount + 1 >= monitor->wl.modesSize)
-    {
-        int size = monitor->wl.modesSize * 2;
-        _GLFWvidmodeWayland* modes =
-            realloc(monitor->wl.modes,
-                    size * sizeof(_GLFWvidmodeWayland));
-        monitor->wl.modes = modes;
-        monitor->wl.modesSize = size;
-    }
-
-    monitor->wl.modes[monitor->wl.modesCount++] = mode;
+    GLFWvidmode mode;
+
+    mode.width = width;
+    mode.height = height;
+    mode.redBits = 8;
+    mode.greenBits = 8;
+    mode.blueBits = 8;
+    mode.refreshRate = refresh / 1000;
+
+    monitor->modeCount++;
+    monitor->modes =
+        realloc(monitor->modes, monitor->modeCount * sizeof(GLFWvidmode));
+    monitor->modes[monitor->modeCount - 1] = mode;
+
+    if (flags & WL_OUTPUT_MODE_CURRENT)
+        monitor->wl.currentMode = monitor->modeCount - 1;
 }
 
-static void done(void* data,
-                 struct wl_output* output)
+static void done(void* data, struct wl_output* output)
 {
     struct _GLFWmonitor *monitor = data;
 
-    monitor->wl.done = GLFW_TRUE;
+    _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
 }
 
 static void scale(void* data,
@@ -149,26 +134,10 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version)
         return;
     }
 
-    monitor->wl.modes = calloc(4, sizeof(_GLFWvidmodeWayland));
-    monitor->wl.modesSize = 4;
-
     monitor->wl.scale = 1;
-
     monitor->wl.output = output;
-    wl_output_add_listener(output, &outputListener, monitor);
-
-    if (_glfw.wl.monitorsCount + 1 >= _glfw.wl.monitorsSize)
-    {
-        _GLFWmonitor** monitors = _glfw.wl.monitors;
-        int size = _glfw.wl.monitorsSize * 2;
 
-        monitors = realloc(monitors, size * sizeof(_GLFWmonitor*));
-
-        _glfw.wl.monitors = monitors;
-        _glfw.wl.monitorsSize = size;
-    }
-
-    _glfw.wl.monitors[_glfw.wl.monitorsCount++] = monitor;
+    wl_output_add_listener(output, &outputListener, monitor);
 }
 
 
@@ -176,42 +145,6 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version)
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
-{
-    _GLFWmonitor** monitors;
-    _GLFWmonitor* monitor;
-    int i, monitorsCount = _glfw.wl.monitorsCount;
-
-    if (_glfw.wl.monitorsCount == 0)
-        goto err;
-
-    monitors = calloc(monitorsCount, sizeof(_GLFWmonitor*));
-
-    for (i = 0; i < monitorsCount; i++)
-    {
-        _GLFWmonitor* origMonitor = _glfw.wl.monitors[i];
-        monitor = calloc(1, sizeof(_GLFWmonitor));
-
-        monitor->modes =
-            _glfwPlatformGetVideoModes(origMonitor,
-                                       &origMonitor->wl.modesCount);
-        *monitor = *_glfw.wl.monitors[i];
-        monitors[i] = monitor;
-    }
-
-    *count = monitorsCount;
-    return monitors;
-
-err:
-    *count = 0;
-    return NULL;
-}
-
-GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
-{
-    return first->wl.output == second->wl.output;
-}
-
 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
 {
     if (xpos)
@@ -222,30 +155,13 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
 
 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
 {
-    GLFWvidmode *modes;
-    int i, modesCount = monitor->wl.modesCount;
-
-    modes = calloc(modesCount, sizeof(GLFWvidmode));
-
-    for (i = 0;  i < modesCount;  i++)
-        modes[i] = monitor->wl.modes[i].base;
-
-    *found = modesCount;
-    return modes;
+    *found = monitor->modeCount;
+    return monitor->modes;
 }
 
 void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
 {
-    int i;
-
-    for (i = 0;  i < monitor->wl.modesCount;  i++)
-    {
-        if (monitor->wl.modes[i].flags & WL_OUTPUT_MODE_CURRENT)
-        {
-            *mode = monitor->wl.modes[i].base;
-            return;
-        }
-    }
+    *mode = monitor->modes[monitor->wl.currentMode];
 }
 
 void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)

+ 2 - 13
src/wl_platform.h

@@ -71,10 +71,6 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
 #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
 
 
-// Wayland-specific video mode data
-//
-typedef struct _GLFWvidmodeWayland _GLFWvidmodeWayland;
-
 // Wayland-specific per-window data
 //
 typedef struct _GLFWwindowWayland
@@ -126,10 +122,6 @@ typedef struct _GLFWlibraryWayland
     struct wl_surface*          cursorSurface;
     uint32_t                    pointerSerial;
 
-    _GLFWmonitor**              monitors;
-    int                         monitorsCount;
-    int                         monitorsSize;
-
     short int                   keycodes[256];
     short int                   scancodes[GLFW_KEY_LAST + 1];
 
@@ -155,15 +147,12 @@ typedef struct _GLFWlibraryWayland
 typedef struct _GLFWmonitorWayland
 {
     struct wl_output*           output;
-
-    _GLFWvidmodeWayland*        modes;
-    int                         modesCount;
-    int                         modesSize;
-    GLFWbool                    done;
+    int                         currentMode;
 
     int                         x;
     int                         y;
     int                         scale;
+
 } _GLFWmonitorWayland;
 
 // Wayland-specific per-cursor data

+ 1 - 0
src/x11_init.c

@@ -794,6 +794,7 @@ int _glfwPlatformInit(void)
 
     _glfwInitTimerPOSIX();
 
+    _glfwPollMonitorsX11();
     return GLFW_TRUE;
 }
 

+ 124 - 113
src/x11_monitor.c

@@ -95,6 +95,130 @@ static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi,
 //////                       GLFW internal API                      //////
 //////////////////////////////////////////////////////////////////////////
 
+// Poll for changes in the set of connected monitors
+//
+void _glfwPollMonitorsX11(void)
+{
+    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
+    {
+        int i, j, disconnectedCount, screenCount = 0;
+        _GLFWmonitor** disconnected;
+        XineramaScreenInfo* screens = NULL;
+        XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
+                                                              _glfw.x11.root);
+        RROutput primary = XRRGetOutputPrimary(_glfw.x11.display,
+                                               _glfw.x11.root);
+
+        if (_glfw.x11.xinerama.available)
+            screens = XineramaQueryScreens(_glfw.x11.display, &screenCount);
+
+        disconnectedCount = _glfw.monitorCount;
+        disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
+        memcpy(disconnected,
+               _glfw.monitors,
+               _glfw.monitorCount * sizeof(_GLFWmonitor*));
+
+        for (i = 0;  i < sr->noutput;  i++)
+        {
+            int type, widthMM, heightMM;
+            XRROutputInfo* oi;
+            XRRCrtcInfo* ci;
+            _GLFWmonitor* monitor;
+
+            oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]);
+            if (oi->connection != RR_Connected || oi->crtc == None)
+            {
+                XRRFreeOutputInfo(oi);
+                continue;
+            }
+
+            for (j = 0;  j < disconnectedCount;  j++)
+            {
+                if (disconnected[j] &&
+                    disconnected[j]->x11.output == sr->outputs[i])
+                {
+                    disconnected[j] = NULL;
+                    break;
+                }
+            }
+
+            if (j < disconnectedCount)
+            {
+                XRRFreeOutputInfo(oi);
+                continue;
+            }
+
+            ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
+            if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
+            {
+                widthMM  = oi->mm_height;
+                heightMM = oi->mm_width;
+            }
+            else
+            {
+                widthMM  = oi->mm_width;
+                heightMM = oi->mm_height;
+            }
+
+            monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
+            monitor->x11.output = sr->outputs[i];
+            monitor->x11.crtc   = oi->crtc;
+
+            for (j = 0;  j < screenCount;  j++)
+            {
+                if (screens[j].x_org == ci->x &&
+                    screens[j].y_org == ci->y &&
+                    screens[j].width == ci->width &&
+                    screens[j].height == ci->height)
+                {
+                    monitor->x11.index = j;
+                    break;
+                }
+            }
+
+            if (monitor->x11.output == primary)
+                type = _GLFW_INSERT_FIRST;
+            else
+                type = _GLFW_INSERT_LAST;
+
+            _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
+
+            XRRFreeOutputInfo(oi);
+            XRRFreeCrtcInfo(ci);
+        }
+
+        XRRFreeScreenResources(sr);
+
+        if (screens)
+            XFree(screens);
+
+        for (i = 0;  i < disconnectedCount;  i++)
+        {
+            if (disconnected[i])
+                _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
+        }
+
+        free(disconnected);
+
+        if (!_glfw.monitorCount)
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "X11: RandR monitor support seems broken");
+            _glfw.x11.randr.monitorBroken = GLFW_TRUE;
+        }
+    }
+
+    if (!_glfw.monitorCount)
+    {
+        const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen);
+        const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen);
+
+        _glfwInputMonitor(_glfwAllocMonitor("Display", widthMM, heightMM),
+                          GLFW_CONNECTED,
+                          _GLFW_INSERT_FIRST);
+    }
+}
+
 // Set the current video mode for the specified monitor
 //
 GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
@@ -198,119 +322,6 @@ void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
 //////                       GLFW platform API                      //////
 //////////////////////////////////////////////////////////////////////////
 
-_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
-{
-    int i, j, k, found = 0;
-    _GLFWmonitor** monitors = NULL;
-
-    *count = 0;
-
-    if (_glfw.x11.randr.available)
-    {
-        int screenCount = 0;
-        XineramaScreenInfo* screens = NULL;
-        XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
-                                                              _glfw.x11.root);
-        RROutput primary = XRRGetOutputPrimary(_glfw.x11.display,
-                                               _glfw.x11.root);
-
-        monitors = calloc(sr->noutput, sizeof(_GLFWmonitor*));
-
-        if (_glfw.x11.xinerama.available)
-            screens = XineramaQueryScreens(_glfw.x11.display, &screenCount);
-
-        for (i = 0;  i < sr->ncrtc;  i++)
-        {
-            XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display,
-                                             sr, sr->crtcs[i]);
-
-            for (j = 0;  j < ci->noutput;  j++)
-            {
-                int widthMM, heightMM;
-                _GLFWmonitor* monitor;
-                XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display,
-                                                     sr, ci->outputs[j]);
-                if (oi->connection != RR_Connected)
-                {
-                    XRRFreeOutputInfo(oi);
-                    continue;
-                }
-
-                if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
-                {
-                    widthMM  = oi->mm_height;
-                    heightMM = oi->mm_width;
-                }
-                else
-                {
-                    widthMM  = oi->mm_width;
-                    heightMM = oi->mm_height;
-                }
-
-                monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
-                monitor->x11.output = ci->outputs[j];
-                monitor->x11.crtc   = oi->crtc;
-
-                for (k = 0;  k < screenCount;  k++)
-                {
-                    if (screens[k].x_org == ci->x &&
-                        screens[k].y_org == ci->y &&
-                        screens[k].width == ci->width &&
-                        screens[k].height == ci->height)
-                    {
-                        monitor->x11.index = k;
-                        break;
-                    }
-                }
-
-                XRRFreeOutputInfo(oi);
-
-                found++;
-                monitors[found - 1] = monitor;
-
-                if (ci->outputs[j] == primary)
-                    _GLFW_SWAP_POINTERS(monitors[0], monitors[found - 1]);
-            }
-
-            XRRFreeCrtcInfo(ci);
-        }
-
-        XRRFreeScreenResources(sr);
-
-        if (screens)
-            XFree(screens);
-
-        if (found == 0)
-        {
-            _glfwInputError(GLFW_PLATFORM_ERROR,
-                            "X11: RandR monitor support seems broken");
-
-            _glfw.x11.randr.monitorBroken = GLFW_TRUE;
-            free(monitors);
-            monitors = NULL;
-        }
-    }
-
-    if (!monitors)
-    {
-        monitors = calloc(1, sizeof(_GLFWmonitor*));
-        monitors[0] = _glfwAllocMonitor("Display",
-                                        DisplayWidthMM(_glfw.x11.display,
-                                                       _glfw.x11.screen),
-                                        DisplayHeightMM(_glfw.x11.display,
-                                                        _glfw.x11.screen));
-        found = 1;
-    }
-
-    *count = found;
-    return monitors;
-}
-
-GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
-{
-    return first->x11.crtc == second->x11.crtc;
-}
-
 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
 {
     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)

+ 1 - 0
src/x11_platform.h

@@ -290,6 +290,7 @@ typedef struct _GLFWcursorX11
 } _GLFWcursorX11;
 
 
+void _glfwPollMonitorsX11(void);
 GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired);
 void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor);
 

+ 1 - 1
src/x11_window.c

@@ -910,7 +910,7 @@ static void processEvent(XEvent *event)
         if (event->type == _glfw.x11.randr.eventBase + RRNotify)
         {
             XRRUpdateConfiguration(event);
-            _glfwInputMonitorChange();
+            _glfwPollMonitorsX11();
             return;
         }
     }