diff --git a/src/wl_init.c b/src/wl_init.c index a27bf6fc..cceef16b 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -36,6 +36,11 @@ #include +static inline int min(int n1, int n2) +{ + return n1 < n2 ? n1 : n2; +} + static void pointerHandleEnter(void* data, struct wl_pointer* pointer, uint32_t serial, @@ -381,7 +386,8 @@ static void registryHandleGlobal(void* data, if (strcmp(interface, "wl_compositor") == 0) { _glfw.wl.compositor = - wl_registry_bind(registry, name, &wl_compositor_interface, 1); + wl_registry_bind(registry, name, &wl_compositor_interface, + min(3, version)); } else if (strcmp(interface, "wl_shm") == 0) { diff --git a/src/wl_monitor.c b/src/wl_monitor.c index 967f05e9..7c58c8f8 100644 --- a/src/wl_monitor.c +++ b/src/wl_monitor.c @@ -97,6 +97,9 @@ static void scale(void* data, struct wl_output* output, int32_t factor) { + struct _GLFWmonitor *monitor = data; + + monitor->wl.scale = factor; } static const struct wl_output_listener output_listener = { @@ -142,6 +145,8 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version) monitor->wl.modes = calloc(4, sizeof(_GLFWvidmodeWayland)); monitor->wl.modesSize = 4; + monitor->wl.scale = 1; + monitor->wl.output = output; wl_output_add_listener(output, &output_listener, monitor); diff --git a/src/wl_platform.h b/src/wl_platform.h index 5b8c25d8..a734ec1e 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -65,8 +65,16 @@ typedef struct _GLFWwindowWayland struct wl_egl_window* native; struct wl_shell_surface* shell_surface; struct wl_callback* callback; + _GLFWcursor* currentCursor; double cursorPosX, cursorPosY; + + // We need to track the monitors the window spans on to calculate the + // optimal scaling factor. + int scale; + _GLFWmonitor** monitors; + int monitorsCount; + int monitorsSize; } _GLFWwindowWayland; @@ -123,7 +131,7 @@ typedef struct _GLFWmonitorWayland int x; int y; - + int scale; } _GLFWmonitorWayland; diff --git a/src/wl_window.c b/src/wl_window.c index 713cda29..00ce7135 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -72,6 +72,79 @@ static const struct wl_shell_surface_listener shellSurfaceListener = { handlePopupDone }; +static void checkScaleChange(_GLFWwindow* window) +{ + int scaledWidth, scaledHeight; + int scale = 1; + int i; + int monitorScale; + + // Get the scale factor from the highest scale monitor. + for (i = 0; i < window->wl.monitorsCount; ++i) + { + monitorScale = window->wl.monitors[i]->wl.scale; + if (scale < monitorScale) + scale = monitorScale; + } + + // Only change the framebuffer size if the scale changed. + if (scale != window->wl.scale) + { + window->wl.scale = scale; + scaledWidth = window->wl.width * scale; + scaledHeight = window->wl.height * scale; + wl_surface_set_buffer_scale(window->wl.surface, scale); + wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0); + _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); + } +} + +static void handleEnter(void *data, + struct wl_surface *surface, + struct wl_output *output) +{ + _GLFWwindow* window = data; + _GLFWmonitor* monitor = wl_output_get_user_data(output); + + if (window->wl.monitorsCount + 1 > window->wl.monitorsSize) + { + ++window->wl.monitorsSize; + window->wl.monitors = + realloc(window->wl.monitors, + window->wl.monitorsSize * sizeof(_GLFWmonitor*)); + } + + window->wl.monitors[window->wl.monitorsCount++] = monitor; + + checkScaleChange(window); +} + +static void handleLeave(void *data, + struct wl_surface *surface, + struct wl_output *output) +{ + _GLFWwindow* window = data; + _GLFWmonitor* monitor = wl_output_get_user_data(output); + GLFWbool found; + int i; + + for (i = 0, found = GLFW_FALSE; i < window->wl.monitorsCount - 1; ++i) + { + if (monitor == window->wl.monitors[i]) + found = GLFW_TRUE; + if (found) + window->wl.monitors[i] = window->wl.monitors[i + 1]; + } + window->wl.monitors[--window->wl.monitorsCount] = NULL; + + checkScaleChange(window); +} + +static const struct wl_surface_listener surfaceListener = { + handleEnter, + handleLeave +}; + static GLFWbool createSurface(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) { @@ -79,6 +152,10 @@ static GLFWbool createSurface(_GLFWwindow* window, if (!window->wl.surface) return GLFW_FALSE; + wl_surface_add_listener(window->wl.surface, + &surfaceListener, + window); + wl_surface_set_user_data(window->wl.surface, window); window->wl.native = wl_egl_window_create(window->wl.surface, @@ -98,6 +175,7 @@ static GLFWbool createSurface(_GLFWwindow* window, window->wl.width = wndconfig->width; window->wl.height = wndconfig->height; + window->wl.scale = 1; return GLFW_TRUE; } @@ -262,6 +340,10 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, window->wl.currentCursor = NULL; + window->wl.monitors = calloc(1, sizeof(_GLFWmonitor*)); + window->wl.monitorsCount = 0; + window->wl.monitorsSize = 1; + return GLFW_TRUE; } @@ -288,6 +370,8 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (window->wl.surface) wl_surface_destroy(window->wl.surface); + + free(window->wl.monitors); } void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) @@ -322,9 +406,12 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { - wl_egl_window_resize(window->wl.native, width, height, 0, 0); + int scaledWidth = width * window->wl.scale; + int scaledHeight = height * window->wl.scale; window->wl.width = width; window->wl.height = height; + wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0); + _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); } void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, @@ -344,6 +431,8 @@ void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { _glfwPlatformGetWindowSize(window, width, height); + *width *= window->wl.scale; + *height *= window->wl.scale; } void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,