From 04f559e28d02f621187a0631490f26527cee8b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 5 Dec 2016 01:19:48 +0100 Subject: [PATCH] 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. --- src/cocoa_init.m | 1 + src/cocoa_monitor.m | 109 +++++++++++--------- src/cocoa_platform.h | 1 + src/cocoa_window.m | 2 +- src/init.c | 1 - src/internal.h | 20 +--- src/mir_init.c | 1 + src/mir_monitor.c | 42 ++++---- src/monitor.c | 94 ++++++----------- src/osmesa_monitor.c | 12 --- src/win32_init.c | 1 + src/win32_monitor.c | 201 ++++++++++++++++++++---------------- src/win32_platform.h | 1 + src/win32_window.c | 2 +- src/wl_init.c | 3 - src/wl_monitor.c | 128 ++++------------------- src/wl_platform.h | 15 +-- src/x11_init.c | 1 + src/x11_monitor.c | 237 ++++++++++++++++++++++--------------------- src/x11_platform.h | 1 + src/x11_window.c | 2 +- 21 files changed, 386 insertions(+), 489 deletions(-) diff --git a/src/cocoa_init.m b/src/cocoa_init.m index fb8b35b9..f029f50a 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -322,6 +322,7 @@ int _glfwPlatformInit(void) _glfwInitTimerNS(); _glfwInitJoysticksNS(); + _glfwPollMonitorsNS(); return GLFW_TRUE; } diff --git a/src/cocoa_monitor.m b/src/cocoa_monitor.m index e1ee682f..86929e2e 100644 --- a/src/cocoa_monitor.m +++ b/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); diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index fef2647b..f6e357a8 100644 --- a/src/cocoa_platform.h +++ b/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); diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 6ca9694a..ef46279b 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -340,7 +340,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)applicationDidChangeScreenParameters:(NSNotification *) notification { - _glfwInputMonitorChange(); + _glfwPollMonitorsNS(); } - (void)applicationDidFinishLaunching:(NSNotification *)notification diff --git a/src/init.c b/src/init.c index 9d82fb3c..abc2f1b5 100644 --- a/src/init.c +++ b/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(); diff --git a/src/internal.h b/src/internal.h index 3da9da2e..5c52cdf1 100644 --- a/src/internal.h +++ b/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 */ diff --git a/src/mir_init.c b/src/mir_init.c index 0d71f07e..29a7cfef 100644 --- a/src/mir_init.c +++ b/src/mir_init.c @@ -213,6 +213,7 @@ int _glfwPlatformInit(void) return GLFW_FALSE; } + _glfwPollMonitorsMir(); return GLFW_TRUE; } diff --git a/src/mir_monitor.c b/src/mir_monitor.c index 0cb4438a..9e2cdc96 100644 --- a/src/mir_monitor.c +++ b/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); + _GLFWmonitor* monitor = _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; + 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); - monitors[i]->modes = _glfwPlatformGetVideoModes(monitors[i], - &monitors[i]->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) { diff --git a/src/monitor.c b/src/monitor.c index 3de94bbe..eb19bb7c 100644 --- a/src/monitor.c +++ b/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++) + if (action == GLFW_CONNECTED) { - for (j = 0; j < monitorCount; j++) + _glfw.monitorCount++; + _glfw.monitors = + realloc(_glfw.monitors, sizeof(_GLFWmonitor*) * _glfw.monitorCount); + + if (type == _GLFW_INSERT_FIRST) { - if (_glfwPlatformIsSameMonitor(_glfw.monitors[i], monitors[j])) + memmove(_glfw.monitors + 1, + _glfw.monitors, + (_glfw.monitorCount - 1) * sizeof(_GLFWmonitor*)); + _glfw.monitors[0] = monitor; + } + else + _glfw.monitors[_glfw.monitorCount - 1] = monitor; + } + else if (action == GLFW_DISCONNECTED) + { + int i; + + for (i = 0; i < _glfw.monitorCount; i++) + { + if (_glfw.monitors[i] == monitor) { - _glfwFreeMonitor(_glfw.monitors[i]); - _glfw.monitors[i] = monitors[j]; + _glfw.monitorCount--; + memmove(_glfw.monitors + i, + _glfw.monitors + i + 1, + (_glfw.monitorCount - i) * sizeof(_GLFWmonitor*)); break; } } } - // Find and report disconnected monitors (not in the new list) + if (_glfw.callbacks.monitor) + _glfw.callbacks.monitor((GLFWmonitor*) monitor, action); - for (i = 0; i < monitorCount; i++) - { - _GLFWwindow* window; - - for (j = 0; j < _glfw.monitorCount; j++) - { - if (monitors[i] == _glfw.monitors[j]) - break; - } - - 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); - } - - // 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++) - { - for (j = 0; j < monitorCount; j++) - { - if (_glfw.monitors[i] == monitors[j]) - { - monitors[j] = NULL; - break; - } - } - - if (j < monitorCount) - continue; - - if (_glfw.callbacks.monitor) - _glfw.callbacks.monitor((GLFWmonitor*) _glfw.monitors[i], GLFW_CONNECTED); - } - - _glfwFreeMonitors(monitors, monitorCount); + if (action == GLFW_DISCONNECTED) + _glfwFreeMonitor(monitor); } void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window) diff --git a/src/osmesa_monitor.c b/src/osmesa_monitor.c index 13862b6d..d996a802 100644 --- a/src/osmesa_monitor.c +++ b/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) { } diff --git a/src/win32_init.c b/src/win32_init.c index adb87b60..6fb4caea 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -433,6 +433,7 @@ int _glfwPlatformInit(void) _glfwInitTimerWin32(); _glfwInitJoysticksWin32(); + _glfwPollMonitorsWin32(); return GLFW_TRUE; } diff --git a/src/win32_monitor.c b/src/win32_monitor.c index 935808c9..00c39fb8 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -90,6 +90,122 @@ static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// +// Poll for changes in the set of connected monitors +// +void _glfwPollMonitorsWin32(void) +{ + int i, disconnectedCount; + _GLFWmonitor** disconnected; + DWORD adapterIndex, displayIndex; + DISPLAY_DEVICEW adapter, display; + GLFWbool hasDisplays = GLFW_FALSE; + + 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 + + for (adapterIndex = 0; ; adapterIndex++) + { + ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW)); + adapter.cb = sizeof(DISPLAY_DEVICEW); + + if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0)) + break; + + if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); + display.cb = sizeof(DISPLAY_DEVICEW); + + if (EnumDisplayDevicesW(adapter.DeviceName, 0, &display, 0)) + { + hasDisplays = GLFW_TRUE; + break; + } + } + + for (adapterIndex = 0; ; adapterIndex++) + { + int type = _GLFW_INSERT_LAST; + + ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW)); + adapter.cb = sizeof(DISPLAY_DEVICEW); + + if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0)) + break; + + if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + type = _GLFW_INSERT_FIRST; + + if (hasDisplays) + { + for (displayIndex = 0; ; displayIndex++) + { + ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); + display.cb = sizeof(DISPLAY_DEVICEW); + + if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0)) + break; + + 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 + { + 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); + } + } + + for (i = 0; i < disconnectedCount; i++) + { + if (disconnected[i]) + _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); + } + + free(disconnected); +} + // Change the current video mode // GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired) @@ -146,91 +262,6 @@ void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -_GLFWmonitor** _glfwPlatformGetMonitors(int* count) -{ - int found = 0; - DWORD adapterIndex, displayIndex, primaryIndex = 0; - DISPLAY_DEVICEW adapter, display; - GLFWbool hasDisplays = GLFW_FALSE; - _GLFWmonitor** monitors = NULL; - - *count = 0; - - // HACK: Check if any active adapters have connected displays - // If not, this is a headless system or a VMware guest - - for (adapterIndex = 0; ; adapterIndex++) - { - ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW)); - adapter.cb = sizeof(DISPLAY_DEVICEW); - - if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0)) - break; - - if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) - continue; - - ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); - display.cb = sizeof(DISPLAY_DEVICEW); - - if (EnumDisplayDevicesW(adapter.DeviceName, 0, &display, 0)) - { - hasDisplays = GLFW_TRUE; - break; - } - } - - for (adapterIndex = 0; ; adapterIndex++) - { - ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW)); - adapter.cb = sizeof(DISPLAY_DEVICEW); - - if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0)) - break; - - if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) - continue; - - if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) - primaryIndex = found; - - if (hasDisplays) - { - for (displayIndex = 0; ; displayIndex++) - { - ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); - display.cb = sizeof(DISPLAY_DEVICEW); - - if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0)) - break; - - found++; - monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); - monitors[found - 1] = createMonitor(&adapter, &display); - } - } - else - { - found++; - monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); - monitors[found - 1] = createMonitor(&adapter, NULL); - } - } - - _GLFW_SWAP_POINTERS(monitors[0], monitors[primaryIndex]); - - *count = found; - return monitors; -} - -GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) -{ - if (wcslen(first->win32.displayName)) - return wcscmp(first->win32.displayName, second->win32.displayName) == 0; - else - return wcscmp(first->win32.adapterName, second->win32.adapterName) == 0; -} - void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { DEVMODEW settings; diff --git a/src/win32_platform.h b/src/win32_platform.h index 892ebee3..511621c1 100644 --- a/src/win32_platform.h +++ b/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); diff --git a/src/win32_window.c b/src/win32_window.c index 70cb09ad..04b8fae3 100644 --- a/src/win32_window.c +++ b/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) diff --git a/src/wl_init.c b/src/wl_init.c index e61f72f7..cbfca5d0 100644 --- a/src/wl_init.c +++ b/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, ®istryListener, NULL); - _glfw.wl.monitors = calloc(4, sizeof(_GLFWmonitor*)); - _glfw.wl.monitorsSize = 4; - createKeyTables(); _glfw.wl.xkb.context = xkb_context_new(0); diff --git a/src/wl_monitor.c b/src/wl_monitor.c index 73567a5b..24b0b39a 100644 --- a/src/wl_monitor.c +++ b/src/wl_monitor.c @@ -32,12 +32,6 @@ #include -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 }, }; + GLFWvidmode mode; - mode.base.width = width; - mode.base.height = height; - mode.base.refreshRate = refresh / 1000; - mode.flags = flags; + mode.width = width; + mode.height = height; + mode.redBits = 8; + mode.greenBits = 8; + mode.blueBits = 8; + mode.refreshRate = refresh / 1000; - 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->modeCount++; + monitor->modes = + realloc(monitor->modes, monitor->modeCount * sizeof(GLFWvidmode)); + monitor->modes[monitor->modeCount - 1] = mode; - monitor->wl.modes[monitor->wl.modesCount++] = 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; } @@ -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) diff --git a/src/wl_platform.h b/src/wl_platform.h index 209f7bca..f228d18a 100644 --- a/src/wl_platform.h +++ b/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 diff --git a/src/x11_init.c b/src/x11_init.c index 91cced2b..e930e58b 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -794,6 +794,7 @@ int _glfwPlatformInit(void) _glfwInitTimerPOSIX(); + _glfwPollMonitorsX11(); return GLFW_TRUE; } diff --git a/src/x11_monitor.c b/src/x11_monitor.c index ce13d4a1..e22c16d7 100644 --- a/src/x11_monitor.c +++ b/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) diff --git a/src/x11_platform.h b/src/x11_platform.h index b6035bbe..1db433d5 100644 --- a/src/x11_platform.h +++ b/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); diff --git a/src/x11_window.c b/src/x11_window.c index db34e9d9..5f22e7c1 100644 --- a/src/x11_window.c +++ b/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; } }