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.
This commit is contained in:
Camilla Löwy 2016-12-05 01:19:48 +01:00
parent ecda05af29
commit 04f559e28d
21 changed files with 386 additions and 489 deletions

View File

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

View File

@ -209,6 +209,66 @@ static void endFadeReservation(CGDisplayFadeReservationToken token)
////// GLFW internal API ////// ////// 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 // Change the current video mode
// //
GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired) GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
@ -288,55 +348,6 @@ void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor)
////// GLFW platform API ////// ////// 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) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{ {
const CGRect bounds = CGDisplayBounds(monitor->ns.displayID); const CGRect bounds = CGDisplayBounds(monitor->ns.displayID);

View File

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

View File

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

View File

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

View File

@ -48,6 +48,9 @@
#define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_NONE
#include "../include/GLFW/glfw3.h" #include "../include/GLFW/glfw3.h"
#define _GLFW_INSERT_FIRST 0
#define _GLFW_INSERT_LAST 1
typedef int GLFWbool; typedef int GLFWbool;
typedef struct _GLFWwndconfig _GLFWwndconfig; typedef struct _GLFWwndconfig _GLFWwndconfig;
@ -563,21 +566,6 @@ const char* _glfwPlatformGetKeyName(int key, int scancode);
*/ */
int _glfwPlatformGetKeyScancode(int key); 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 /*! @copydoc glfwGetMonitorPos
* @ingroup platform * @ingroup platform
*/ */
@ -959,7 +947,7 @@ void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered);
/*! @ingroup event /*! @ingroup event
*/ */
void _glfwInputMonitorChange(void); void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int type);
/*! @ingroup event /*! @ingroup event
*/ */

View File

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

View File

@ -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; int i;
_GLFWmonitor** monitors = NULL;
MirDisplayConfiguration* displayConfig = MirDisplayConfiguration* displayConfig =
mir_connection_create_display_config(_glfw.mir.connection); mir_connection_create_display_config(_glfw.mir.connection);
*count = 0;
for (i = 0; i < displayConfig->num_outputs; i++) for (i = 0; i < displayConfig->num_outputs; i++)
{ {
const MirDisplayOutput* out = displayConfig->outputs + i; const MirDisplayOutput* out = displayConfig->outputs + i;
@ -51,32 +50,27 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
out->num_modes && out->num_modes &&
out->current_mode < out->num_modes) out->current_mode < out->num_modes)
{ {
found++; _GLFWmonitor* monitor = _glfwAllocMonitor("Unknown",
monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); out->physical_width_mm,
monitors[i] = _glfwAllocMonitor("Unknown", out->physical_height_mm);
out->physical_width_mm,
out->physical_height_mm);
monitors[i]->mir.x = out->position_x; monitor->mir.x = out->position_x;
monitors[i]->mir.y = out->position_y; monitor->mir.y = out->position_y;
monitors[i]->mir.outputId = out->output_id; monitor->mir.outputId = out->output_id;
monitors[i]->mir.curMode = out->current_mode; monitor->mir.curMode = out->current_mode;
monitor->modes = _glfwPlatformGetVideoModes(monitor, &monitor->modeCount);
monitors[i]->modes = _glfwPlatformGetVideoModes(monitors[i], _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
&monitors[i]->modeCount);
} }
} }
mir_display_config_destroy(displayConfig); 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) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{ {

View File

@ -86,80 +86,46 @@ static GLFWbool refreshVideoModes(_GLFWmonitor* monitor)
////// GLFW event API ////// ////// GLFW event API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void _glfwInputMonitorChange(void) void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int type)
{ {
int i, j, monitorCount = _glfw.monitorCount; if (action == GLFW_CONNECTED)
_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++) _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.monitorCount--;
_glfw.monitors[i] = monitors[j]; memmove(_glfw.monitors + i,
_glfw.monitors + i + 1,
(_glfw.monitorCount - i) * sizeof(_GLFWmonitor*));
break; 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++) if (action == GLFW_DISCONNECTED)
{ _glfwFreeMonitor(monitor);
_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);
} }
void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window) void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window)

View File

@ -32,18 +32,6 @@
////// GLFW platform API ////// ////// 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) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{ {
} }

View File

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

View File

@ -90,6 +90,122 @@ static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
////// GLFW internal API ////// ////// 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 // Change the current video mode
// //
GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired) GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
@ -146,91 +262,6 @@ void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
////// GLFW platform API ////// ////// 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) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{ {
DEVMODEW settings; DEVMODEW settings;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -95,6 +95,130 @@ static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi,
////// GLFW internal API ////// ////// 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 // Set the current video mode for the specified monitor
// //
GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired) GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
@ -198,119 +322,6 @@ void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
////// GLFW platform API ////// ////// 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) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{ {
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)

View File

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

View File

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