Wayland: Implement HiDPI support

Windows now keep track of the monitors they are on, so we can calculate
the best scaling factor for them, by using the maximum of each of the
monitors.

The compositor scales down the buffer automatically when it is on a
lower density monitor, instead of the previous way where it was scaling
up the buffer on higher density monitors, which makes the application
look much better on those ones.
This commit is contained in:
Emmanuel Gil Peyrot 2015-10-10 16:35:06 +01:00 committed by Jonas Ådahl
parent ecd04539ec
commit 06479ba535
4 changed files with 111 additions and 3 deletions

View File

@ -36,6 +36,11 @@
#include <wayland-cursor.h>
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)
{

View File

@ -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);

View File

@ -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;

View File

@ -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,