mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-18 06:47:31 -04:00
Merge branch 'master' into 'master'
backend/wayland: handle hidpi and subpixel Closes #854 and #1758 See merge request wlroots/wlroots!3418
This commit is contained in:
commit
fbbbbb2e5f
5 changed files with 278 additions and 41 deletions
|
|
@ -236,6 +236,43 @@ static const struct zwp_linux_dmabuf_feedback_v1_listener
|
|||
.tranche_flags = linux_dmabuf_feedback_v1_handle_tranche_flags,
|
||||
};
|
||||
|
||||
static void update_outputs(struct wlr_wl_backend *backend) {
|
||||
struct wlr_wl_output *output;
|
||||
wl_list_for_each(output, &backend->outputs, link) {
|
||||
surface_update(output);
|
||||
}
|
||||
}
|
||||
|
||||
static void wlr_output_handle_scale(void *data,
|
||||
struct wl_output *wl_output, int32_t factor) {
|
||||
struct wlr_wl_remote_output *output = data;
|
||||
output->scale = factor;
|
||||
}
|
||||
|
||||
static void wlr_output_handle_geometry(void *data, struct wl_output *wl_output,
|
||||
int32_t x, int32_t y, int32_t phys_width, int32_t phys_height,
|
||||
int32_t subpixel, const char *make, const char *model, int32_t transform) {
|
||||
struct wlr_wl_remote_output *output = data;
|
||||
output->subpixel = subpixel;
|
||||
}
|
||||
|
||||
static void wlr_output_handle_mode(void *data, struct wl_output *wl_output,
|
||||
uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
|
||||
// This is intentionally left blank
|
||||
}
|
||||
|
||||
static void wlr_output_handle_done(void *data, struct wl_output *wl_output) {
|
||||
struct wlr_wl_remote_output *output = data;
|
||||
update_outputs(output->backend);
|
||||
}
|
||||
|
||||
static const struct wl_output_listener output_listener = {
|
||||
.scale = wlr_output_handle_scale,
|
||||
.geometry = wlr_output_handle_geometry,
|
||||
.mode = wlr_output_handle_mode,
|
||||
.done = wlr_output_handle_done
|
||||
};
|
||||
|
||||
static bool device_has_name(const drmDevice *device, const char *name) {
|
||||
for (size_t i = 0; i < DRM_NODE_MAX; i++) {
|
||||
if (!(device->available_nodes & (1 << i))) {
|
||||
|
|
@ -396,6 +433,26 @@ static void registry_global(void *data, struct wl_registry *registry,
|
|||
} else if (strcmp(iface, wl_subcompositor_interface.name) == 0) {
|
||||
wl->subcompositor = wl_registry_bind(registry, name,
|
||||
&wl_subcompositor_interface, 1);
|
||||
} else if (strcmp(iface, wl_output_interface.name) == 0) {
|
||||
struct wlr_wl_remote_output *output = calloc(1, sizeof(*output));
|
||||
if (!output) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wl_output *wl_output = wl_registry_bind(registry, name, &wl_output_interface, 2);
|
||||
if (!wl_output) {
|
||||
free(output);
|
||||
return;
|
||||
}
|
||||
|
||||
output->output = wl_output;
|
||||
output->scale = 1;
|
||||
output->name = name;
|
||||
output->backend = wl;
|
||||
output->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
|
||||
|
||||
wl_list_insert(&wl->remote_outputs, &output->link);
|
||||
wl_output_add_listener(wl_output, &output_listener, output);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -410,6 +467,15 @@ static void registry_global_remove(void *data, struct wl_registry *registry,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct wlr_wl_remote_output *output;
|
||||
wl_list_for_each(output, &wl->remote_outputs, link) {
|
||||
if (output->name == name) {
|
||||
wl_list_remove(&output->link);
|
||||
free(output);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
|
|
@ -469,6 +535,13 @@ static void backend_destroy(struct wlr_backend *backend) {
|
|||
destroy_wl_buffer(buffer);
|
||||
}
|
||||
|
||||
struct wlr_wl_remote_output *remote_output, *tmp_remote_output;
|
||||
wl_list_for_each_safe(remote_output, tmp_remote_output,
|
||||
&wl->remote_outputs, link) {
|
||||
wl_output_release(remote_output->output);
|
||||
free(remote_output);
|
||||
}
|
||||
|
||||
wlr_backend_finish(backend);
|
||||
|
||||
wl_list_remove(&wl->local_display_destroy.link);
|
||||
|
|
@ -575,6 +648,7 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
|
|||
wl_list_init(&wl->outputs);
|
||||
wl_list_init(&wl->seats);
|
||||
wl_list_init(&wl->buffers);
|
||||
wl_list_init(&wl->remote_outputs);
|
||||
wl->presentation_clock = CLOCK_MONOTONIC;
|
||||
|
||||
wl->remote_display = wl_display_connect(remote);
|
||||
|
|
|
|||
|
|
@ -66,6 +66,12 @@ static void presentation_feedback_destroy(
|
|||
free(feedback);
|
||||
}
|
||||
|
||||
static void active_remote_output_destroy(
|
||||
struct wlr_wl_active_remote_output *output) {
|
||||
wl_list_remove(&output->link);
|
||||
free(output);
|
||||
}
|
||||
|
||||
static void presentation_feedback_handle_sync_output(void *data,
|
||||
struct wp_presentation_feedback *feedback, struct wl_output *output) {
|
||||
// This space is intentionally left blank
|
||||
|
|
@ -455,7 +461,19 @@ static bool output_commit(struct wlr_output *wlr_output,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool needs_commit = false;
|
||||
if (state->committed & WLR_OUTPUT_STATE_SCALE) {
|
||||
wl_surface_set_buffer_scale(output->surface, ceil(state->scale));
|
||||
needs_commit = true;
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
if (output->requested.needs_ack) {
|
||||
output->requested.needs_ack = false;
|
||||
xdg_surface_ack_configure(output->xdg_surface,
|
||||
output->requested.serial);
|
||||
}
|
||||
|
||||
const pixman_region32_t *damage = NULL;
|
||||
if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
|
||||
damage = &state->damage;
|
||||
|
|
@ -503,7 +521,7 @@ static bool output_commit(struct wlr_output *wlr_output,
|
|||
output->surface);
|
||||
}
|
||||
|
||||
wl_surface_commit(output->surface);
|
||||
needs_commit = true;
|
||||
|
||||
if (wp_feedback != NULL) {
|
||||
struct wlr_wl_presentation_feedback *feedback =
|
||||
|
|
@ -528,6 +546,10 @@ static bool output_commit(struct wlr_output *wlr_output,
|
|||
}
|
||||
}
|
||||
|
||||
if (needs_commit) {
|
||||
wl_surface_commit(output->surface);
|
||||
}
|
||||
|
||||
wl_display_flush(output->backend->remote_display);
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_MODE) {
|
||||
|
|
@ -541,34 +563,18 @@ static bool output_commit(struct wlr_output *wlr_output,
|
|||
static bool output_set_cursor(struct wlr_output *wlr_output,
|
||||
struct wlr_buffer *wlr_buffer, int hotspot_x, int hotspot_y) {
|
||||
struct wlr_wl_output *output = get_wl_output_from_output(wlr_output);
|
||||
struct wlr_wl_backend *backend = output->backend;
|
||||
|
||||
output->cursor.hotspot_x = hotspot_x;
|
||||
output->cursor.hotspot_y = hotspot_y;
|
||||
|
||||
if (output->cursor.surface == NULL) {
|
||||
output->cursor.surface =
|
||||
wl_compositor_create_surface(backend->compositor);
|
||||
}
|
||||
struct wl_surface *surface = output->cursor.surface;
|
||||
wlr_buffer_unlock(output->cursor.buffer);
|
||||
output->cursor.buffer = NULL;
|
||||
|
||||
if (wlr_buffer != NULL) {
|
||||
struct wlr_wl_buffer *buffer =
|
||||
get_or_create_wl_buffer(output->backend, wlr_buffer);
|
||||
if (buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wl_surface_attach(surface, buffer->wl_buffer, 0, 0);
|
||||
wl_surface_damage_buffer(surface, 0, 0, INT32_MAX, INT32_MAX);
|
||||
wl_surface_commit(surface);
|
||||
} else {
|
||||
wl_surface_attach(surface, NULL, 0, 0);
|
||||
wl_surface_commit(surface);
|
||||
if (wlr_buffer) {
|
||||
output->cursor.buffer = wlr_buffer_lock(wlr_buffer);
|
||||
}
|
||||
|
||||
update_wl_output_cursor(output);
|
||||
wl_display_flush(backend->remote_display);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -605,6 +611,12 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
|||
presentation_feedback_destroy(feedback);
|
||||
}
|
||||
|
||||
struct wlr_wl_active_remote_output *active, *active_tmp;
|
||||
wl_list_for_each_safe(active, active_tmp,
|
||||
&output->active_remote_outputs, link) {
|
||||
active_remote_output_destroy(active);
|
||||
}
|
||||
|
||||
if (output->zxdg_toplevel_decoration_v1) {
|
||||
zxdg_toplevel_decoration_v1_destroy(output->zxdg_toplevel_decoration_v1);
|
||||
}
|
||||
|
|
@ -617,15 +629,43 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
|||
|
||||
void update_wl_output_cursor(struct wlr_wl_output *output) {
|
||||
struct wlr_wl_pointer *pointer = output->cursor.pointer;
|
||||
if (pointer) {
|
||||
if (!pointer || !output->cursor.buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(pointer->output == output);
|
||||
assert(output->enter_serial);
|
||||
|
||||
struct wlr_wl_backend *backend = output->backend;
|
||||
|
||||
if (output->cursor.surface == NULL) {
|
||||
output->cursor.surface =
|
||||
wl_compositor_create_surface(backend->compositor);
|
||||
}
|
||||
|
||||
struct wl_surface *surface = output->cursor.surface;
|
||||
if (!surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_wl_buffer *buffer =
|
||||
get_or_create_wl_buffer(output->backend, output->cursor.buffer);
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
int scale = ceil(output->wlr_output.scale);
|
||||
wl_surface_attach(surface, buffer->wl_buffer, 0, 0);
|
||||
wl_surface_damage_buffer(surface, 0, 0, INT32_MAX, INT32_MAX);
|
||||
wl_surface_set_buffer_scale(surface, scale);
|
||||
wl_surface_commit(surface);
|
||||
|
||||
wl_display_flush(backend->remote_display);
|
||||
|
||||
struct wlr_wl_seat *seat = pointer->seat;
|
||||
wl_pointer_set_cursor(seat->wl_pointer, output->enter_serial,
|
||||
output->cursor.surface, output->cursor.hotspot_x,
|
||||
output->cursor.hotspot_y);
|
||||
}
|
||||
output->cursor.surface, output->cursor.hotspot_x / scale,
|
||||
output->cursor.hotspot_y / scale);
|
||||
}
|
||||
|
||||
static bool output_move_cursor(struct wlr_output *_output, int x, int y) {
|
||||
|
|
@ -647,14 +687,60 @@ bool wlr_output_is_wl(struct wlr_output *wlr_output) {
|
|||
return wlr_output->impl == &output_impl;
|
||||
}
|
||||
|
||||
void surface_update(struct wlr_wl_output *output) {
|
||||
if (wl_list_empty(&output->active_remote_outputs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t scale = 1;
|
||||
enum wl_output_subpixel subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
|
||||
|
||||
struct wlr_wl_active_remote_output *active;
|
||||
wl_list_for_each(active, &output->active_remote_outputs, link) {
|
||||
struct wlr_wl_remote_output *output = active->remote_output;
|
||||
if (scale < output->scale) {
|
||||
scale = output->scale;
|
||||
}
|
||||
|
||||
if (output->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) {
|
||||
subpixel = output->subpixel;
|
||||
}
|
||||
}
|
||||
|
||||
struct wlr_output_state state = {
|
||||
.committed = WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_SCALE |
|
||||
WLR_OUTPUT_STATE_SUBPIXEL,
|
||||
.mode_type = WLR_OUTPUT_STATE_MODE_CUSTOM,
|
||||
.scale = scale,
|
||||
.subpixel = subpixel,
|
||||
.custom_mode = {
|
||||
.width = output->requested.width * scale,
|
||||
.height = output->requested.height * scale
|
||||
},
|
||||
};
|
||||
|
||||
wlr_output_send_request_state(&output->wlr_output, &state);
|
||||
update_wl_output_cursor(output);
|
||||
}
|
||||
|
||||
static void xdg_surface_handle_configure(void *data,
|
||||
struct xdg_surface *xdg_surface, uint32_t serial) {
|
||||
struct wlr_wl_output *output = data;
|
||||
assert(output && output->xdg_surface == xdg_surface);
|
||||
|
||||
if (wl_list_empty(&output->active_remote_outputs)) {
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
wl_surface_commit(output->surface);
|
||||
return;
|
||||
}
|
||||
|
||||
// nothing else?
|
||||
output->requested.needs_ack = true;
|
||||
output->requested.serial = serial;
|
||||
surface_update(output);
|
||||
|
||||
// if the compositor did not commit a new buffer during the surface_update
|
||||
// above, assume that the compositor did not acknowledge the configure.
|
||||
output->requested.needs_ack = false;
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||
|
|
@ -671,12 +757,8 @@ static void xdg_toplevel_handle_configure(void *data,
|
|||
return;
|
||||
}
|
||||
|
||||
struct wlr_output_state state = {
|
||||
.committed = WLR_OUTPUT_STATE_MODE,
|
||||
.mode_type = WLR_OUTPUT_STATE_MODE_CUSTOM,
|
||||
.custom_mode = { .width = width, .height = height },
|
||||
};
|
||||
wlr_output_send_request_state(&output->wlr_output, &state);
|
||||
output->requested.width = width;
|
||||
output->requested.height = height;
|
||||
}
|
||||
|
||||
static void xdg_toplevel_handle_close(void *data,
|
||||
|
|
@ -692,6 +774,50 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
|||
.close = xdg_toplevel_handle_close,
|
||||
};
|
||||
|
||||
static void surface_enter(void *data, struct wl_surface *wl_surface,
|
||||
struct wl_output *wl_output) {
|
||||
struct wlr_wl_output *output = data;
|
||||
|
||||
struct wlr_wl_remote_output *remote_output;
|
||||
wl_list_for_each(remote_output, &output->backend->remote_outputs, link) {
|
||||
if (remote_output->output != wl_output) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct wlr_wl_active_remote_output *active = calloc(1, sizeof(*active));
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
|
||||
active->remote_output = remote_output;
|
||||
|
||||
wl_list_insert(&output->active_remote_outputs, &active->link);
|
||||
surface_update(output);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void surface_leave(void *data, struct wl_surface *wl_surface,
|
||||
struct wl_output *wl_output) {
|
||||
struct wlr_wl_output *output = data;
|
||||
|
||||
struct wlr_wl_active_remote_output *active;
|
||||
wl_list_for_each(active, &output->active_remote_outputs, link) {
|
||||
if (active->remote_output->output != wl_output) {
|
||||
continue;
|
||||
}
|
||||
|
||||
active_remote_output_destroy(active);
|
||||
surface_update(output);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_surface_listener surface_listener = {
|
||||
.enter = &surface_enter,
|
||||
.leave = &surface_leave,
|
||||
};
|
||||
|
||||
struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) {
|
||||
struct wlr_wl_backend *backend = get_wl_backend_from_backend(wlr_backend);
|
||||
if (!backend->started) {
|
||||
|
|
@ -724,6 +850,7 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) {
|
|||
|
||||
output->backend = backend;
|
||||
wl_list_init(&output->presentation_feedbacks);
|
||||
wl_list_init(&output->active_remote_outputs);
|
||||
|
||||
output->surface = wl_compositor_create_surface(backend->compositor);
|
||||
if (!output->surface) {
|
||||
|
|
@ -763,6 +890,7 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) {
|
|||
&xdg_surface_listener, output);
|
||||
xdg_toplevel_add_listener(output->xdg_toplevel,
|
||||
&xdg_toplevel_listener, output);
|
||||
wl_surface_add_listener(output->surface, &surface_listener, output);
|
||||
wl_surface_commit(output->surface);
|
||||
|
||||
wl_display_roundtrip(output->backend->remote_display);
|
||||
|
|
|
|||
|
|
@ -87,11 +87,12 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
|
|||
}
|
||||
|
||||
struct wlr_output *wlr_output = &pointer->output->wlr_output;
|
||||
int scale = ceil(wlr_output->scale);
|
||||
struct wlr_pointer_motion_absolute_event event = {
|
||||
.pointer = &pointer->wlr_pointer,
|
||||
.time_msec = time,
|
||||
.x = wl_fixed_to_double(sx) / wlr_output->width,
|
||||
.y = wl_fixed_to_double(sy) / wlr_output->height,
|
||||
.x = wl_fixed_to_double(sx) * scale / wlr_output->width,
|
||||
.y = wl_fixed_to_double(sy) * scale / wlr_output->height,
|
||||
};
|
||||
wl_signal_emit_mutable(&pointer->wlr_pointer.events.motion_absolute, &event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,8 +127,9 @@ static void touch_coordinates_to_absolute(struct wlr_wl_seat *seat,
|
|||
*/
|
||||
struct wlr_wl_output *output, *tmp;
|
||||
wl_list_for_each_safe(output, tmp, &seat->backend->outputs, link) {
|
||||
*sx = wl_fixed_to_double(x) / output->wlr_output.width;
|
||||
*sy = wl_fixed_to_double(y) / output->wlr_output.height;
|
||||
int scale = ceil(output->wlr_output.scale);
|
||||
*sx = wl_fixed_to_double(x) * scale / output->wlr_output.width;
|
||||
*sy = wl_fixed_to_double(y) * scale / output->wlr_output.height;
|
||||
return; // Choose the first output in the list
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,9 +48,28 @@ struct wlr_wl_backend {
|
|||
struct wl_drm *legacy_drm;
|
||||
struct xdg_activation_v1 *activation_v1;
|
||||
struct wl_subcompositor *subcompositor;
|
||||
struct wl_list remote_outputs; // wlr_wl_remote_output.link
|
||||
char *drm_render_name;
|
||||
};
|
||||
|
||||
struct wlr_wl_remote_output {
|
||||
struct wl_output *output;
|
||||
struct wlr_wl_backend *backend;
|
||||
uint32_t scale;
|
||||
enum wl_output_subpixel subpixel;
|
||||
|
||||
// we use this to identify the output in the
|
||||
// global registry so that we can remove it later
|
||||
uint32_t name;
|
||||
|
||||
struct wl_list link; // wlr_wl_backend.remote_outputs
|
||||
};
|
||||
|
||||
struct wlr_wl_active_remote_output {
|
||||
struct wlr_wl_remote_output *remote_output;
|
||||
struct wl_list link; // wlr_wl_output.active_remote_outputs
|
||||
};
|
||||
|
||||
struct wlr_wl_buffer {
|
||||
struct wlr_buffer *buffer;
|
||||
struct wl_buffer *wl_buffer;
|
||||
|
|
@ -86,12 +105,24 @@ struct wlr_wl_output {
|
|||
struct xdg_toplevel *xdg_toplevel;
|
||||
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1;
|
||||
struct wl_list presentation_feedbacks;
|
||||
struct wl_list active_remote_outputs; // wlr_wl_active_remote_output.link
|
||||
|
||||
uint32_t enter_serial;
|
||||
|
||||
// last requested output size. This is not the actual size that the
|
||||
// compositor has accepted.
|
||||
struct {
|
||||
bool needs_ack;
|
||||
uint32_t serial;
|
||||
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
} requested;
|
||||
|
||||
struct {
|
||||
struct wlr_wl_pointer *pointer;
|
||||
struct wl_surface *surface;
|
||||
struct wlr_buffer *buffer;
|
||||
int32_t hotspot_x, hotspot_y;
|
||||
} cursor;
|
||||
};
|
||||
|
|
@ -169,6 +200,8 @@ bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl,
|
|||
void destroy_wl_seat(struct wlr_wl_seat *seat);
|
||||
void destroy_wl_buffer(struct wlr_wl_buffer *buffer);
|
||||
|
||||
void surface_update(struct wlr_wl_output *output);
|
||||
|
||||
extern const struct wlr_pointer_impl wl_pointer_impl;
|
||||
extern const struct wlr_tablet_pad_impl wl_tablet_pad_impl;
|
||||
extern const struct wlr_tablet_impl wl_tablet_impl;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue