Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Rauch <Rauch.Christian@gmx.de>2020-07-25 17:58:29 +0300
committerChristian Rauch <Rauch.Christian@gmx.de>2021-06-03 20:18:27 +0300
commit870bcf6e1af5a493b2e2583d98b3b12b7ab3a05d (patch)
treea60676e598284a42c95714baa649441c3999f45b
parent8b78510fc47a6c89036d371dfb8693cb851c61ab (diff)
GHOST/wayland: adapt window and cursor surface scale to support HiDPI screens
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp228
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h14
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp99
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.h17
4 files changed, 288 insertions, 70 deletions
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index d6e46f27918..1e9a2940c32 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -53,15 +53,6 @@
#include <cstring>
-struct output_t {
- struct wl_output *output;
- int32_t width, height;
- int transform;
- int scale;
- std::string make;
- std::string model;
-};
-
struct buffer_t {
void *data;
size_t size;
@@ -73,6 +64,12 @@ struct cursor_t {
struct wl_buffer *buffer;
struct wl_cursor_image image;
struct buffer_t *file_buffer = nullptr;
+ struct wl_cursor_theme *theme = nullptr;
+ int size;
+ std::string theme_name;
+ // outputs on which the cursor is visible
+ std::unordered_set<const output_t *> outputs;
+ int scale = 1;
};
struct data_offer_t {
@@ -146,7 +143,10 @@ struct display_t {
struct wl_shm *shm = nullptr;
std::vector<output_t *> outputs;
std::vector<input_t *> inputs;
- struct wl_cursor_theme *cursor_theme = nullptr;
+ struct {
+ std::string theme;
+ int size;
+ } cursor;
struct wl_data_device_manager *data_device_manager = nullptr;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = nullptr;
struct zwp_pointer_constraints_v1 *pointer_constraints = nullptr;
@@ -155,6 +155,8 @@ struct display_t {
std::vector<struct wl_egl_window *> os_egl_windows;
};
+static GHOST_WindowManager *window_manager = nullptr;
+
static void display_destroy(display_t *d)
{
if (d->data_device_manager) {
@@ -189,6 +191,9 @@ static void display_destroy(display_t *d)
if (input->cursor.surface) {
wl_surface_destroy(input->cursor.surface);
}
+ if (input->cursor.theme) {
+ wl_cursor_theme_destroy(input->cursor.theme);
+ }
if (input->pointer) {
wl_pointer_destroy(input->pointer);
}
@@ -211,10 +216,6 @@ static void display_destroy(display_t *d)
delete input;
}
- if (d->cursor_theme) {
- wl_cursor_theme_destroy(d->cursor_theme);
- }
-
if (d->shm) {
wl_shm_destroy(d->shm);
}
@@ -801,6 +802,69 @@ const struct wl_buffer_listener cursor_buffer_listener = {
cursor_buffer_release,
};
+static GHOST_IWindow *get_window(struct wl_surface *surface)
+{
+ if (!surface) {
+ return nullptr;
+ }
+
+ for (GHOST_IWindow *win : window_manager->getWindows()) {
+ if (surface == static_cast<const GHOST_WindowWayland *>(win)->surface()) {
+ return win;
+ }
+ }
+ return nullptr;
+}
+
+static bool update_cursor_scale(cursor_t &cursor, wl_shm *shm)
+{
+ int scale = 0;
+ for (const output_t *output : cursor.outputs) {
+ if (output->scale > scale)
+ scale = output->scale;
+ }
+
+ if (scale > 0 && cursor.scale != scale) {
+ cursor.scale = scale;
+ wl_surface_set_buffer_scale(cursor.surface, scale);
+ wl_cursor_theme_destroy(cursor.theme);
+ cursor.theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm);
+ return true;
+ }
+ return false;
+}
+
+static void cursor_surface_enter(void *data,
+ struct wl_surface * /*wl_surface*/,
+ struct wl_output *output)
+{
+ input_t *input = static_cast<input_t *>(data);
+ for (const output_t *reg_output : input->system->outputs()) {
+ if (reg_output->output == output) {
+ input->cursor.outputs.insert(reg_output);
+ }
+ }
+ update_cursor_scale(input->cursor, input->system->shm());
+}
+
+static void cursor_surface_leave(void *data,
+ struct wl_surface * /*wl_surface*/,
+ struct wl_output *output)
+{
+ input_t *input = static_cast<input_t *>(data);
+ for (const output_t *reg_output : input->system->outputs()) {
+ if (reg_output->output == output) {
+ input->cursor.outputs.erase(reg_output);
+ }
+ }
+ update_cursor_scale(input->cursor, input->system->shm());
+}
+
+struct wl_surface_listener cursor_surface_listener = {
+ cursor_surface_enter,
+ cursor_surface_leave,
+};
+
static void pointer_enter(void *data,
struct wl_pointer * /*wl_pointer*/,
uint32_t serial,
@@ -808,22 +872,28 @@ static void pointer_enter(void *data,
wl_fixed_t surface_x,
wl_fixed_t surface_y)
{
- if (!surface) {
+ GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(surface));
+
+ if (!win) {
return;
}
+
+ win->activate();
+
input_t *input = static_cast<input_t *>(data);
input->pointer_serial = serial;
- input->x = wl_fixed_to_int(surface_x);
- input->y = wl_fixed_to_int(surface_y);
+ input->x = win->scale() * wl_fixed_to_int(surface_x);
+ input->y = win->scale() * wl_fixed_to_int(surface_y);
input->focus_pointer = surface;
- input->system->pushEvent(
- new GHOST_EventCursor(input->system->getMilliSeconds(),
- GHOST_kEventCursorMove,
- static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface)),
- input->x,
- input->y,
- GHOST_TABLET_DATA_NONE));
+ win->setCursorShape(win->getCursorShape());
+
+ input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ static_cast<GHOST_WindowWayland *>(win),
+ input->x,
+ input->y,
+ GHOST_TABLET_DATA_NONE));
}
static void pointer_leave(void *data,
@@ -831,9 +901,14 @@ static void pointer_leave(void *data,
uint32_t /*serial*/,
struct wl_surface *surface)
{
- if (surface != nullptr) {
- static_cast<input_t *>(data)->focus_pointer = nullptr;
+ GHOST_IWindow *win = get_window(surface);
+
+ if (!win) {
+ return;
}
+
+ static_cast<input_t *>(data)->focus_pointer = nullptr;
+ static_cast<GHOST_WindowWayland *>(win)->deactivate();
}
static void pointer_motion(void *data,
@@ -844,21 +919,20 @@ static void pointer_motion(void *data,
{
input_t *input = static_cast<input_t *>(data);
- GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
- wl_surface_get_user_data(input->focus_pointer));
+ GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_pointer));
if (!win) {
return;
}
- input->x = wl_fixed_to_int(surface_x);
- input->y = wl_fixed_to_int(surface_y);
+ input->x = win->scale() * wl_fixed_to_int(surface_x);
+ input->y = win->scale() * wl_fixed_to_int(surface_y);
input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
GHOST_kEventCursorMove,
win,
- wl_fixed_to_int(surface_x),
- wl_fixed_to_int(surface_y),
+ input->x,
+ input->y,
GHOST_TABLET_DATA_NONE));
}
@@ -869,6 +943,14 @@ static void pointer_button(void *data,
uint32_t button,
uint32_t state)
{
+ input_t *input = static_cast<input_t *>(data);
+
+ GHOST_IWindow *win = get_window(input->focus_pointer);
+
+ if (!win) {
+ return;
+ }
+
GHOST_TEventType etype = GHOST_kEventUnknown;
switch (state) {
case WL_POINTER_BUTTON_STATE_RELEASED:
@@ -892,9 +974,6 @@ static void pointer_button(void *data,
break;
}
- input_t *input = static_cast<input_t *>(data);
- GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
- wl_surface_get_user_data(input->focus_pointer));
input->data_source->source_serial = serial;
input->buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED);
input->system->pushEvent(new GHOST_EventButton(
@@ -907,12 +986,18 @@ static void pointer_axis(void *data,
uint32_t axis,
wl_fixed_t value)
{
+ input_t *input = static_cast<input_t *>(data);
+
+ GHOST_IWindow *win = get_window(input->focus_pointer);
+
+ if (!win) {
+ return;
+ }
+
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) {
return;
}
- input_t *input = static_cast<input_t *>(data);
- GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
- wl_surface_get_user_data(input->focus_pointer));
+
input->system->pushEvent(
new GHOST_EventWheel(input->system->getMilliSeconds(), win, std::signbit(value) ? +1 : -1));
}
@@ -1142,7 +1227,12 @@ static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capa
input->cursor.visible = true;
input->cursor.buffer = nullptr;
input->cursor.file_buffer = new buffer_t;
+ if (!get_cursor_settings(input->cursor.theme_name, input->cursor.size)) {
+ input->cursor.theme_name = std::string();
+ input->cursor.size = default_cursor_size;
+ }
wl_pointer_add_listener(input->pointer, &pointer_listener, data);
+ wl_surface_add_listener(input->cursor.surface, &cursor_surface_listener, data);
}
if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
@@ -1165,8 +1255,8 @@ static void output_geometry(void *data,
struct wl_output * /*wl_output*/,
int32_t /*x*/,
int32_t /*y*/,
- int32_t /*physical_width*/,
- int32_t /*physical_height*/,
+ int32_t physical_width,
+ int32_t physical_height,
int32_t /*subpixel*/,
const char *make,
const char *model,
@@ -1176,6 +1266,8 @@ static void output_geometry(void *data,
output->transform = transform;
output->make = std::string(make);
output->model = std::string(model);
+ output->width_mm = physical_width;
+ output->height_mm = physical_height;
}
static void output_mode(void *data,
@@ -1186,8 +1278,8 @@ static void output_mode(void *data,
int32_t /*refresh*/)
{
output_t *output = static_cast<output_t *>(data);
- output->width = width;
- output->height = height;
+ output->width_pxl = width;
+ output->height_pxl = height;
}
/**
@@ -1232,7 +1324,7 @@ static void global_add(void *data,
struct display_t *display = static_cast<struct display_t *>(data);
if (!strcmp(interface, wl_compositor_interface.name)) {
display->compositor = static_cast<wl_compositor *>(
- wl_registry_bind(wl_registry, name, &wl_compositor_interface, 1));
+ wl_registry_bind(wl_registry, name, &wl_compositor_interface, 3));
}
else if (!strcmp(interface, xdg_wm_base_interface.name)) {
display->xdg_shell = static_cast<xdg_wm_base *>(
@@ -1340,19 +1432,6 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t)
wl_data_device_add_listener(input->data_device, &data_device_listener, input);
}
}
-
- std::string theme;
- int size;
- if (!get_cursor_settings(theme, size)) {
- theme = std::string();
- size = default_cursor_size;
- }
-
- d->cursor_theme = wl_cursor_theme_load(theme.c_str(), size, d->shm);
- if (!d->cursor_theme) {
- display_destroy(d);
- throw std::runtime_error("Wayland: unable to access cursor themes!");
- }
}
GHOST_SystemWayland::~GHOST_SystemWayland()
@@ -1479,8 +1558,8 @@ void GHOST_SystemWayland::getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TU
{
if (getNumDisplays() > 0) {
/* We assume first output as main. */
- width = uint32_t(d->outputs[0]->width);
- height = uint32_t(d->outputs[0]->height);
+ width = uint32_t(d->outputs[0]->width_pxl) / d->outputs[0]->scale;
+ height = uint32_t(d->outputs[0]->height_pxl) / d->outputs[0]->scale;
}
}
@@ -1538,6 +1617,11 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
const bool is_dialog,
const GHOST_IWindow *parentWindow)
{
+ /* globally store pointer to window manager */
+ if (!window_manager) {
+ window_manager = getWindowManager();
+ }
+
GHOST_WindowWayland *window = new GHOST_WindowWayland(
this,
title,
@@ -1582,6 +1666,16 @@ xdg_wm_base *GHOST_SystemWayland::shell()
return d->xdg_shell;
}
+const std::vector<output_t *> &GHOST_SystemWayland::outputs() const
+{
+ return d->outputs;
+}
+
+wl_shm *GHOST_SystemWayland::shm() const
+{
+ return d->shm;
+}
+
void GHOST_SystemWayland::setSelection(const std::string &selection)
{
this->selection = selection;
@@ -1603,8 +1697,8 @@ static void set_cursor_buffer(input_t *input, wl_buffer *buffer)
wl_pointer_set_cursor(input->pointer,
input->pointer_serial,
input->cursor.surface,
- int32_t(input->cursor.image.hotspot_x),
- int32_t(input->cursor.image.hotspot_y));
+ int32_t(input->cursor.image.hotspot_x) / input->cursor.scale,
+ int32_t(input->cursor.image.hotspot_y) / input->cursor.scale);
}
}
@@ -1616,7 +1710,15 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
const std::string cursor_name = cursors.count(shape) ? cursors.at(shape) :
cursors.at(GHOST_kStandardCursorDefault);
- wl_cursor *cursor = wl_cursor_theme_get_cursor(d->cursor_theme, cursor_name.c_str());
+ input_t *input = d->inputs[0];
+ cursor_t *c = &input->cursor;
+
+ if (!c->theme) {
+ /* The cursor surface hasn't entered an output yet. Initialise theme with scale 1. */
+ c->theme = wl_cursor_theme_load(c->theme_name.c_str(), c->size, d->inputs[0]->system->shm());
+ }
+
+ wl_cursor *cursor = wl_cursor_theme_get_cursor(c->theme, cursor_name.c_str());
if (!cursor) {
GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
@@ -1628,11 +1730,11 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
if (!buffer) {
return GHOST_kFailure;
}
- cursor_t *c = &d->inputs[0]->cursor;
+
c->buffer = buffer;
c->image = *image;
- set_cursor_buffer(d->inputs[0], buffer);
+ set_cursor_buffer(input, buffer);
return GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index 10b9ef6bd62..2457bed5def 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.h
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -34,6 +34,16 @@ class GHOST_WindowWayland;
struct display_t;
+struct output_t {
+ struct wl_output *output;
+ int32_t width_pxl, height_pxl; // dimensions in pixel
+ int32_t width_mm, height_mm; // dimensions in millimeter
+ int transform;
+ int scale;
+ std::string make;
+ std::string model;
+};
+
class GHOST_SystemWayland : public GHOST_System {
public:
GHOST_SystemWayland();
@@ -84,6 +94,10 @@ class GHOST_SystemWayland : public GHOST_System {
xdg_wm_base *shell();
+ const std::vector<output_t *> &outputs() const;
+
+ wl_shm *shm() const;
+
void setSelection(const std::string &selection);
GHOST_TSuccess setCursorShape(GHOST_TStandardCursor shape);
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index 1412c496512..70cfe35d628 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -29,9 +29,15 @@
#include <wayland-egl.h>
+static constexpr size_t base_dpi = 96;
+
struct window_t {
GHOST_WindowWayland *w;
wl_surface *surface;
+ // outputs on which the window is currently shown on
+ std::unordered_set<const output_t *> outputs;
+ GHOST_TUns16 dpi = 0;
+ int scale = 1;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
wl_egl_window *egl_window;
@@ -97,13 +103,14 @@ static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t ser
{
window_t *win = static_cast<window_t *>(data);
- int w, h;
- wl_egl_window_get_attached_size(win->egl_window, &w, &h);
- if (win->pending_width != 0 && win->pending_height != 0 && win->pending_width != w &&
- win->pending_height != h) {
- win->width = win->pending_width;
- win->height = win->pending_height;
- wl_egl_window_resize(win->egl_window, win->pending_width, win->pending_height, 0, 0);
+ if (win->xdg_surface != xdg_surface) {
+ return;
+ }
+
+ if (win->pending_width != 0 && win->pending_height != 0) {
+ win->width = win->scale * win->pending_width;
+ win->height = win->scale * win->pending_height;
+ wl_egl_window_resize(win->egl_window, win->width, win->height, 0, 0);
win->pending_width = 0;
win->pending_height = 0;
win->w->notify_size();
@@ -123,6 +130,52 @@ static const xdg_surface_listener surface_listener = {
surface_configure,
};
+static bool update_scale(GHOST_WindowWayland *window)
+{
+ int scale = 0;
+ for (const output_t *output : window->outputs_active()) {
+ if (output->scale > scale)
+ scale = output->scale;
+ }
+
+ if (scale > 0 && window->scale() != scale) {
+ window->scale() = scale;
+ // using the real DPI will cause wrong scaling of the UI
+ // use a multiplier for the default DPI as workaround
+ window->dpi() = scale * base_dpi;
+ wl_surface_set_buffer_scale(window->surface(), scale);
+ return true;
+ }
+ return false;
+}
+
+static void surface_enter(void *data, struct wl_surface * /*wl_surface*/, struct wl_output *output)
+{
+ GHOST_WindowWayland *w = static_cast<GHOST_WindowWayland *>(data);
+ for (const output_t *reg_output : w->outputs()) {
+ if (reg_output->output == output) {
+ w->outputs_active().insert(reg_output);
+ }
+ }
+ update_scale(w);
+}
+
+static void surface_leave(void *data, struct wl_surface * /*wl_surface*/, struct wl_output *output)
+{
+ GHOST_WindowWayland *w = static_cast<GHOST_WindowWayland *>(data);
+ for (const output_t *reg_output : w->outputs()) {
+ if (reg_output->output == output) {
+ w->outputs_active().erase(reg_output);
+ }
+ }
+ update_scale(w);
+}
+
+struct wl_surface_listener wl_surface_listener = {
+ surface_enter,
+ surface_leave,
+};
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -161,6 +214,8 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
/* Window surfaces. */
w->surface = wl_compositor_create_surface(m_system->compositor());
+ wl_surface_add_listener(w->surface, &wl_surface_listener, this);
+
w->egl_window = wl_egl_window_create(w->surface, int(width), int(height));
w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->shell(), w->surface);
@@ -229,6 +284,31 @@ GHOST_TSuccess GHOST_WindowWayland::notify_size()
new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowSize, this));
}
+wl_surface *GHOST_WindowWayland::surface() const
+{
+ return w->surface;
+}
+
+const std::vector<output_t *> &GHOST_WindowWayland::outputs() const
+{
+ return m_system->outputs();
+}
+
+std::unordered_set<const output_t *> &GHOST_WindowWayland::outputs_active()
+{
+ return w->outputs;
+}
+
+uint16_t &GHOST_WindowWayland::dpi()
+{
+ return w->dpi;
+}
+
+int &GHOST_WindowWayland::scale()
+{
+ return w->scale;
+}
+
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
{
return m_system->setCursorGrab(mode, w->surface);
@@ -320,6 +400,11 @@ GHOST_WindowWayland::~GHOST_WindowWayland()
delete w;
}
+GHOST_TUns16 GHOST_WindowWayland::getDPIHint()
+{
+ return w->dpi;
+}
+
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorVisibility(bool visible)
{
return m_system->setCursorVisibility(visible);
diff --git a/intern/ghost/intern/GHOST_WindowWayland.h b/intern/ghost/intern/GHOST_WindowWayland.h
index b62b5c24d60..dbddc7c469e 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.h
+++ b/intern/ghost/intern/GHOST_WindowWayland.h
@@ -24,9 +24,14 @@
#include "GHOST_Window.h"
+#include <unordered_set>
+#include <vector>
+
class GHOST_SystemWayland;
struct window_t;
+struct wl_surface;
+struct output_t;
class GHOST_WindowWayland : public GHOST_Window {
public:
@@ -47,6 +52,8 @@ class GHOST_WindowWayland : public GHOST_Window {
~GHOST_WindowWayland() override;
+ GHOST_TUns16 getDPIHint() override;
+
GHOST_TSuccess close();
GHOST_TSuccess activate();
@@ -55,6 +62,16 @@ class GHOST_WindowWayland : public GHOST_Window {
GHOST_TSuccess notify_size();
+ wl_surface *surface() const;
+
+ const std::vector<output_t *> &outputs() const;
+
+ std::unordered_set<const output_t *> &outputs_active();
+
+ uint16_t &dpi();
+
+ int &scale();
+
protected:
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override;