Merge branch 'master' into xdg-positioner

This commit is contained in:
Tony Crisci 2018-03-28 00:20:39 -04:00
commit 41e54ba632
62 changed files with 2927 additions and 1083 deletions

View file

@ -8,8 +8,10 @@ lib_wlr_types = static_library(
'wlr_gamma_control.c',
'wlr_idle_inhibit_v1.c',
'wlr_idle.c',
'wlr_idle_inhibit_v1.c',
'wlr_input_device.c',
'wlr_keyboard.c',
'wlr_layer_shell.c',
'wlr_linux_dmabuf.c',
'wlr_list.c',
'wlr_matrix.c',

415
types/wlr_layer_shell.c Normal file
View file

@ -0,0 +1,415 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-server.h>
#include <wlr/types/wlr_layer_shell.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/util/log.h>
#include "util/signal.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
static const char *zwlr_layer_surface_role = "zwlr_layer_surface";
static void resource_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static const struct zwlr_layer_shell_v1_interface layer_shell_implementation;
static const struct zwlr_layer_surface_v1_interface layer_surface_implementation;
static struct wlr_layer_shell *layer_shell_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &zwlr_layer_shell_v1_interface,
&layer_shell_implementation));
return wl_resource_get_user_data(resource);
}
static struct wlr_layer_surface *layer_surface_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &zwlr_layer_surface_v1_interface,
&layer_surface_implementation));
return wl_resource_get_user_data(resource);
}
static void layer_surface_configure_destroy(
struct wlr_layer_surface_configure *configure) {
if (configure == NULL) {
return;
}
wl_list_remove(&configure->link);
free(configure);
}
static void layer_surface_handle_ack_configure(struct wl_client *client,
struct wl_resource *resource, uint32_t serial) {
struct wlr_layer_surface *surface = layer_surface_from_resource(resource);
bool found = false;
struct wlr_layer_surface_configure *configure, *tmp;
wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) {
if (configure->serial < serial) {
layer_surface_configure_destroy(configure);
} else if (configure->serial == serial) {
found = true;
break;
} else {
break;
}
}
if (!found) {
wl_resource_post_error(resource,
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE,
"wrong configure serial: %u", serial);
return;
}
if (surface->acked_configure) {
layer_surface_configure_destroy(surface->acked_configure);
}
surface->acked_configure = configure;
wl_list_remove(&configure->link);
wl_list_init(&configure->link);
}
static void layer_surface_handle_set_size(struct wl_client *client,
struct wl_resource *resource, uint32_t width, uint32_t height) {
struct wlr_layer_surface *surface = layer_surface_from_resource(resource);
surface->client_pending.desired_width = width;
surface->client_pending.desired_height = height;
}
static void layer_surface_handle_set_anchor(struct wl_client *client,
struct wl_resource *resource, uint32_t anchor) {
const uint32_t max_anchor =
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
if (anchor > max_anchor) {
wl_resource_post_error(resource,
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR,
"invalid anchor %d", anchor);
}
struct wlr_layer_surface *surface = layer_surface_from_resource(resource);
surface->client_pending.anchor = anchor;
}
static void layer_surface_handle_set_exclusive_zone(struct wl_client *client,
struct wl_resource *resource, int32_t zone) {
struct wlr_layer_surface *surface = layer_surface_from_resource(resource);
surface->client_pending.exclusive_zone = zone;
}
static void layer_surface_handle_set_margin(
struct wl_client *client, struct wl_resource *resource,
int32_t top, int32_t right, int32_t bottom, int32_t left) {
struct wlr_layer_surface *surface = layer_surface_from_resource(resource);
surface->client_pending.margin.top = top;
surface->client_pending.margin.right = right;
surface->client_pending.margin.bottom = bottom;
surface->client_pending.margin.left = left;
}
static void layer_surface_handle_set_keyboard_interactivity(
struct wl_client *client, struct wl_resource *resource,
uint32_t interactive) {
struct wlr_layer_surface *surface = layer_surface_from_resource(resource);
surface->client_pending.keyboard_interactive = !!interactive;
}
static void layer_surface_handle_get_popup(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *popup) {
// TODO
}
static const struct zwlr_layer_surface_v1_interface layer_surface_implementation = {
.destroy = resource_handle_destroy,
.ack_configure = layer_surface_handle_ack_configure,
.set_size = layer_surface_handle_set_size,
.set_anchor = layer_surface_handle_set_anchor,
.set_exclusive_zone = layer_surface_handle_set_exclusive_zone,
.set_margin = layer_surface_handle_set_margin,
.set_keyboard_interactivity = layer_surface_handle_set_keyboard_interactivity,
.get_popup = layer_surface_handle_get_popup,
};
static void layer_surface_unmap(struct wlr_layer_surface *surface) {
// TODO: probably need to ungrab before this event
wlr_signal_emit_safe(&surface->events.unmap, surface);
struct wlr_layer_surface_configure *configure, *tmp;
wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) {
layer_surface_configure_destroy(configure);
}
surface->configured = surface->mapped = false;
surface->configure_serial = 0;
if (surface->configure_idle) {
wl_event_source_remove(surface->configure_idle);
surface->configure_idle = NULL;
}
surface->configure_next_serial = 0;
}
static void layer_surface_destroy(struct wlr_layer_surface *surface) {
layer_surface_unmap(surface);
wlr_signal_emit_safe(&surface->events.destroy, surface);
wl_resource_set_user_data(surface->resource, NULL);
wl_list_remove(&surface->surface_destroy_listener.link);
wlr_surface_set_role_committed(surface->surface, NULL, NULL);
free(surface);
}
static void layer_surface_resource_destroy(struct wl_resource *resource) {
struct wlr_layer_surface *surface =
layer_surface_from_resource(resource);
if (surface != NULL) {
layer_surface_destroy(surface);
}
}
static bool wlr_layer_surface_state_changed(struct wlr_layer_surface *surface) {
struct wlr_layer_surface_state *state;
if (wl_list_empty(&surface->configure_list)) {
if (surface->acked_configure) {
state = &surface->acked_configure->state;
} else if (!surface->configured) {
return true;
} else {
state = &surface->current;
}
} else {
struct wlr_layer_surface_configure *configure =
wl_container_of(surface->configure_list.prev, configure, link);
state = &configure->state;
}
bool changed = state->actual_width != surface->server_pending.actual_width
|| state->actual_height != surface->server_pending.actual_height;
return changed;
}
void wlr_layer_surface_configure(struct wlr_layer_surface *surface,
uint32_t width, uint32_t height) {
surface->server_pending.actual_width = width;
surface->server_pending.actual_height = height;
if (wlr_layer_surface_state_changed(surface)) {
struct wl_display *display =
wl_client_get_display(wl_resource_get_client(surface->resource));
struct wlr_layer_surface_configure *configure =
calloc(1, sizeof(struct wlr_layer_surface_configure));
if (configure == NULL) {
wl_client_post_no_memory(wl_resource_get_client(surface->resource));
return;
}
surface->configure_next_serial = wl_display_next_serial(display);
wl_list_insert(surface->configure_list.prev, &configure->link);
configure->state.actual_width = width;
configure->state.actual_height = height;
configure->serial = surface->configure_next_serial;
zwlr_layer_surface_v1_send_configure(surface->resource,
configure->serial, configure->state.actual_width,
configure->state.actual_height);
}
}
void wlr_layer_surface_close(struct wlr_layer_surface *surface) {
if (surface->closed) {
return;
}
surface->closed = true;
layer_surface_unmap(surface);
zwlr_layer_surface_v1_send_closed(surface->resource);
}
static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface,
void *role_data) {
struct wlr_layer_surface *surface = role_data;
if (surface->closed) {
// Ignore commits after the compositor has closed it
return;
}
if (surface->acked_configure) {
struct wlr_layer_surface_configure *configure =
surface->acked_configure;
surface->configured = true;
surface->configure_serial = configure->serial;
surface->current.actual_width = configure->state.actual_width;
surface->current.actual_height = configure->state.actual_height;
layer_surface_configure_destroy(configure);
surface->acked_configure = NULL;
}
if (wlr_surface_has_buffer(surface->surface) && !surface->configured) {
wl_resource_post_error(surface->resource,
ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED,
"layer_surface has never been configured");
return;
}
surface->current.anchor = surface->client_pending.anchor;
surface->current.exclusive_zone = surface->client_pending.exclusive_zone;
surface->current.margin = surface->client_pending.margin;
surface->current.keyboard_interactive =
surface->client_pending.keyboard_interactive;
surface->current.desired_width = surface->client_pending.desired_width;
surface->current.desired_height = surface->client_pending.desired_height;
if (!surface->added) {
surface->added = true;
wlr_signal_emit_safe(&surface->shell->events.new_surface,
surface);
}
if (surface->configured && wlr_surface_has_buffer(surface->surface) &&
!surface->mapped) {
surface->mapped = true;
wlr_signal_emit_safe(&surface->events.map, surface);
}
if (surface->configured && !wlr_surface_has_buffer(surface->surface) &&
surface->mapped) {
layer_surface_unmap(surface);
}
}
static void handle_wlr_surface_destroyed(struct wl_listener *listener,
void *data) {
struct wlr_layer_surface *layer_surface =
wl_container_of(listener, layer_surface, surface_destroy_listener);
layer_surface_destroy(layer_surface);
}
static void layer_shell_handle_get_layer_surface(struct wl_client *wl_client,
struct wl_resource *client_resource, uint32_t id,
struct wl_resource *surface_resource,
struct wl_resource *output_resource,
uint32_t layer, const char *namespace) {
struct wlr_layer_shell *shell =
layer_shell_from_resource(client_resource);
struct wlr_surface *wlr_surface =
wlr_surface_from_resource(surface_resource);
if (wlr_surface_set_role(wlr_surface, zwlr_layer_surface_role,
client_resource, ZWLR_LAYER_SHELL_V1_ERROR_ROLE)) {
return;
}
struct wlr_layer_surface *surface =
calloc(1, sizeof(struct wlr_layer_surface));
if (surface == NULL) {
wl_client_post_no_memory(wl_client);
return;
}
surface->shell = shell;
surface->surface = wlr_surface;
surface->output = wlr_output_from_resource(output_resource);
surface->resource = wl_resource_create(wl_client,
&zwlr_layer_surface_v1_interface,
wl_resource_get_version(client_resource),
id);
surface->namespace = strdup(namespace);
surface->layer = layer;
if (surface->resource == NULL || surface->namespace == NULL) {
free(surface);
wl_client_post_no_memory(wl_client);
return;
}
if (layer > ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) {
wl_resource_post_error(surface->resource,
ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER,
"Invalid layer %d", layer);
free(surface);
return;
}
wl_list_init(&surface->configure_list);
wl_signal_init(&surface->events.destroy);
wl_signal_add(&surface->surface->events.destroy,
&surface->surface_destroy_listener);
surface->surface_destroy_listener.notify = handle_wlr_surface_destroyed;
wl_signal_init(&surface->events.map);
wl_signal_init(&surface->events.unmap);
wlr_surface_set_role_committed(surface->surface,
handle_wlr_surface_committed, surface);
wlr_log(L_DEBUG, "new layer_surface %p (res %p)",
surface, surface->resource);
wl_resource_set_implementation(surface->resource,
&layer_surface_implementation, surface, layer_surface_resource_destroy);
}
static const struct zwlr_layer_shell_v1_interface layer_shell_implementation = {
.get_layer_surface = layer_shell_handle_get_layer_surface,
};
static void client_handle_destroy(struct wl_resource *resource) {
wl_list_remove(wl_resource_get_link(resource));
}
static void layer_shell_bind(struct wl_client *wl_client, void *data,
uint32_t version, uint32_t id) {
struct wlr_layer_shell *layer_shell = data;
assert(wl_client && layer_shell);
struct wl_resource *resource = wl_resource_create(
wl_client, &zwlr_layer_shell_v1_interface, version, id);
if (resource == NULL) {
wl_client_post_no_memory(wl_client);
return;
}
wl_resource_set_implementation(resource,
&layer_shell_implementation, layer_shell, client_handle_destroy);
wl_list_insert(&layer_shell->client_resources,
wl_resource_get_link(resource));
}
static void handle_display_destroy(struct wl_listener *listener, void *data) {
struct wlr_layer_shell *layer_shell =
wl_container_of(listener, layer_shell, display_destroy);
wlr_layer_shell_destroy(layer_shell);
}
struct wlr_layer_shell *wlr_layer_shell_create(struct wl_display *display) {
struct wlr_layer_shell *layer_shell =
calloc(1, sizeof(struct wlr_layer_shell));
if (!layer_shell) {
return NULL;
}
wl_list_init(&layer_shell->client_resources);
struct wl_global *wl_global = wl_global_create(display,
&zwlr_layer_shell_v1_interface, 1, layer_shell, layer_shell_bind);
if (!wl_global) {
free(layer_shell);
return NULL;
}
layer_shell->wl_global = wl_global;
wl_signal_init(&layer_shell->events.new_surface);
layer_shell->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &layer_shell->display_destroy);
return layer_shell;
}
void wlr_layer_shell_destroy(struct wlr_layer_shell *layer_shell) {
if (!layer_shell) {
return;
}
struct wl_resource *client, *tmp;
wl_resource_for_each_safe(client, tmp, &layer_shell->client_resources) {
wl_resource_destroy(client);
}
wl_list_remove(&layer_shell->display_destroy.link);
wl_global_destroy(layer_shell->wl_global);
free(layer_shell);
}

View file

@ -19,11 +19,6 @@ static const struct wl_buffer_interface wl_buffer_impl = {
wl_buffer_destroy,
};
bool wlr_dmabuf_buffer_has_inverted_y(struct wlr_dmabuf_buffer *dmabuf) {
return dmabuf->attributes.flags
& ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT;
}
bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource) {
if (!wl_resource_instance_of(buffer_resource, &wl_buffer_interface,
&wl_buffer_impl)) {
@ -139,19 +134,18 @@ static void params_create_common(struct wl_client *client,
goto err_out;
}
/* TODO: support more planes */
if (buffer->attributes.n_planes != 1) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
"only single plane buffers supported not %d",
buffer->attributes.n_planes);
goto err_out;
}
if (buffer->attributes.fd[0] == -1) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
"no dmabuf has been added for plane");
"no dmabuf has been added for plane 0");
goto err_out;
}
if ((buffer->attributes.fd[3] >= 0 || buffer->attributes.fd[2] >= 0) &&
(buffer->attributes.fd[2] == -1 || buffer->attributes.fd[1] == -1)) {
wl_resource_post_error (params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
"gap in dmabuf planes");
goto err_out;
}
@ -167,43 +161,48 @@ static void params_create_common(struct wl_client *client,
goto err_out;
}
if ((uint64_t)buffer->attributes.offset[0] + buffer->attributes.stride[0] > UINT32_MAX) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"size overflow for plane");
goto err_out;
}
if ((uint64_t)buffer->attributes.offset[0] +
(uint64_t)buffer->attributes.stride[0] * height > UINT32_MAX) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"size overflow for plane");
goto err_out;
}
off_t size = lseek(buffer->attributes.fd[0], 0, SEEK_END);
if (size != -1) { /* Skip checks if kernel does no support seek on buffer */
if (buffer->attributes.offset[0] >= size) {
for (int i = 0; i < buffer->attributes.n_planes; i++) {
if ((uint64_t)buffer->attributes.offset[i]
+ buffer->attributes.stride[i] > UINT32_MAX) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"invalid offset %i for plane",
buffer->attributes.offset[0]);
"size overflow for plane %d", i);
goto err_out;
}
if (buffer->attributes.offset[0] + buffer->attributes.stride[0] > size) {
if ((uint64_t)buffer->attributes.offset[i]
+ (uint64_t)buffer->attributes.stride[i] * height > UINT32_MAX) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"invalid stride %i for plane",
buffer->attributes.stride[0]);
"size overflow for plane %d", i);
goto err_out;
}
if (buffer->attributes.offset[0] + buffer->attributes.stride[0] * height > size) {
off_t size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
if (size == -1) { /* Skip checks if kernel does no support seek on buffer */
continue;
}
if (buffer->attributes.offset[i] >= size) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"invalid buffer stride or height for plane");
"invalid offset %i for plane %d",
buffer->attributes.offset[i], i);
goto err_out;
}
if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"invalid stride %i for plane %d",
buffer->attributes.stride[i], i);
goto err_out;
}
if (i == 0 && /* planes > 0 might be subsampled according to fourcc format */
buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"invalid buffer stride or height for plane %d", i);
goto err_out;
}
}

View file

@ -731,15 +731,11 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,
return true;
}
if (cursor->texture == NULL) {
cursor->texture = wlr_render_texture_create(renderer);
if (cursor->texture == NULL) {
return false;
}
}
wlr_texture_destroy(cursor->texture);
return wlr_texture_upload_pixels(cursor->texture, WL_SHM_FORMAT_ARGB8888,
cursor->texture = wlr_texture_from_pixels(renderer, WL_SHM_FORMAT_ARGB8888,
stride, width, height, pixels);
return cursor->texture != NULL;
}
static void output_cursor_commit(struct wlr_output_cursor *cursor) {
@ -901,9 +897,7 @@ void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) {
}
cursor->output->hardware_cursor = NULL;
}
if (cursor->texture != NULL) {
wlr_texture_destroy(cursor->texture);
}
wlr_texture_destroy(cursor->texture);
wl_list_remove(&cursor->link);
free(cursor);
}

View file

@ -1257,8 +1257,9 @@ bool wlr_seat_touch_has_grab(struct wlr_seat *seat) {
}
bool wlr_seat_validate_grab_serial(struct wlr_seat *seat, uint32_t serial) {
return serial == seat->pointer_state.grab_serial ||
serial == seat->touch_state.grab_serial;
return true;
//return serial == seat->pointer_state.grab_serial ||
// serial == seat->touch_state.grab_serial;
}
struct wlr_seat_client *wlr_seat_client_from_resource(

View file

@ -155,8 +155,24 @@ static bool wlr_surface_update_size(struct wlr_surface *surface,
int scale = state->scale;
enum wl_output_transform transform = state->transform;
wlr_texture_get_buffer_size(surface->texture, state->buffer,
&state->buffer_width, &state->buffer_height);
struct wl_shm_buffer *buf = wl_shm_buffer_get(state->buffer);
if (buf != NULL) {
state->buffer_width = wl_shm_buffer_get_width(buf);
state->buffer_height = wl_shm_buffer_get_height(buf);
} else if (wlr_renderer_resource_is_wl_drm_buffer(surface->renderer,
state->buffer)) {
wlr_renderer_wl_drm_buffer_get_size(surface->renderer, state->buffer,
&state->buffer_width, &state->buffer_height);
} else if (wlr_dmabuf_resource_is_buffer(state->buffer)) {
struct wlr_dmabuf_buffer *dmabuf =
wlr_dmabuf_buffer_from_buffer_resource(state->buffer);
state->buffer_width = dmabuf->attributes.width;
state->buffer_height = dmabuf->attributes.height;
} else {
wlr_log(L_ERROR, "Unknown buffer handle attached");
state->buffer_width = 0;
state->buffer_height = 0;
}
int width = state->buffer_width / scale;
int height = state->buffer_height / scale;
@ -316,52 +332,65 @@ static void wlr_surface_damage_subsurfaces(struct wlr_subsurface *subsurface) {
static void wlr_surface_apply_damage(struct wlr_surface *surface,
bool reupload_buffer) {
if (!surface->current->buffer) {
struct wl_resource *resource = surface->current->buffer;
if (resource == NULL) {
return;
}
struct wl_shm_buffer *buffer = wl_shm_buffer_get(surface->current->buffer);
if (!buffer) {
if (wlr_renderer_buffer_is_drm(surface->renderer,
surface->current->buffer)) {
wlr_texture_upload_drm(surface->texture, surface->current->buffer);
goto release;
} else if (wlr_dmabuf_resource_is_buffer(
surface->current->buffer)) {
wlr_texture_upload_dmabuf(surface->texture, surface->current->buffer);
goto release;
struct wl_shm_buffer *buf = wl_shm_buffer_get(resource);
if (buf != NULL) {
wl_shm_buffer_begin_access(buf);
enum wl_shm_format fmt = wl_shm_buffer_get_format(buf);
int32_t stride = wl_shm_buffer_get_stride(buf);
int32_t width = wl_shm_buffer_get_width(buf);
int32_t height = wl_shm_buffer_get_height(buf);
void *data = wl_shm_buffer_get_data(buf);
if (surface->texture == NULL || reupload_buffer) {
wlr_texture_destroy(surface->texture);
surface->texture = wlr_texture_from_pixels(surface->renderer, fmt,
stride, width, height, data);
} else {
wlr_log(L_INFO, "Unknown buffer handle attached");
return;
}
}
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_copy(&damage, &surface->current->buffer_damage);
pixman_region32_intersect_rect(&damage, &damage, 0, 0,
surface->current->buffer_width,
surface->current->buffer_height);
uint32_t format = wl_shm_buffer_get_format(buffer);
if (reupload_buffer) {
wlr_texture_upload_shm(surface->texture, format, buffer);
} else {
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_copy(&damage, &surface->current->buffer_damage);
pixman_region32_intersect_rect(&damage, &damage, 0, 0,
surface->current->buffer_width, surface->current->buffer_height);
int n;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &n);
for (int i = 0; i < n; ++i) {
pixman_box32_t rect = rects[i];
if (!wlr_texture_update_shm(surface->texture, format,
rect.x1, rect.y1,
rect.x2 - rect.x1,
rect.y2 - rect.y1,
buffer)) {
break;
int n;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &n);
for (int i = 0; i < n; ++i) {
pixman_box32_t *r = &rects[i];
if (!wlr_texture_write_pixels(surface->texture, fmt, stride,
r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1,
r->x1, r->y1, data)) {
break;
}
}
pixman_region32_fini(&damage);
}
pixman_region32_fini(&damage);
wl_shm_buffer_end_access(buf);
} else if (!surface->texture || reupload_buffer) {
wlr_texture_destroy(surface->texture);
if (wlr_renderer_resource_is_wl_drm_buffer(surface->renderer, resource)) {
surface->texture =
wlr_texture_from_wl_drm(surface->renderer, resource);
} else if (wlr_dmabuf_resource_is_buffer(resource)) {
struct wlr_dmabuf_buffer *dmabuf =
wlr_dmabuf_buffer_from_buffer_resource(resource);
surface->texture =
wlr_texture_from_dmabuf(surface->renderer, &dmabuf->attributes);
} else {
surface->texture = NULL;
wlr_log(L_ERROR, "Unknown buffer handle attached");
}
}
release:
wlr_surface_state_release_buffer(surface->current);
}
@ -376,7 +405,8 @@ static void wlr_surface_commit_pending(struct wlr_surface *surface) {
wlr_surface_move_state(surface, surface->pending, surface->current);
if (null_buffer_commit) {
surface->texture->valid = false;
wlr_texture_destroy(surface->texture);
surface->texture = NULL;
}
bool reupload_buffer = oldw != surface->current->buffer_width ||
@ -612,7 +642,6 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res,
}
wlr_log(L_DEBUG, "New wlr_surface %p (res %p)", surface, res);
surface->renderer = renderer;
surface->texture = wlr_render_texture_create(renderer);
surface->resource = res;
surface->current = wlr_surface_state_create();
@ -629,7 +658,7 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res,
}
bool wlr_surface_has_buffer(struct wlr_surface *surface) {
return surface->texture && surface->texture->valid;
return surface->texture != NULL;
}
int wlr_surface_set_role(struct wlr_surface *surface, const char *role,

View file

@ -77,7 +77,7 @@ void wlr_xcursor_manager_set_cursor_image(struct wlr_xcursor_manager *manager,
}
struct wlr_xcursor_image *image = xcursor->images[0];
wlr_cursor_set_image(cursor, image->buffer, image->width,
wlr_cursor_set_image(cursor, image->buffer, image->width * 4,
image->width, image->height, image->hotspot_x, image->hotspot_y,
theme->scale);
}

View file

@ -194,18 +194,19 @@ static void xdg_surface_unmap(struct wlr_xdg_surface *surface) {
assert(surface->role != WLR_XDG_SURFACE_ROLE_NONE);
// TODO: probably need to ungrab before this event
wlr_signal_emit_safe(&surface->events.unmap, surface);
if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
wl_resource_set_user_data(surface->toplevel->resource, NULL);
free(surface->toplevel);
surface->toplevel = NULL;
if (surface->mapped) {
wlr_signal_emit_safe(&surface->events.unmap, surface);
}
if (surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
wl_resource_set_user_data(surface->popup->resource, NULL);
if (surface->popup->seat) {
switch (surface->role) {
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
free(surface->toplevel->title);
surface->toplevel->title = NULL;
free(surface->toplevel->app_id);
surface->toplevel->app_id = NULL;
break;
case WLR_XDG_SURFACE_ROLE_POPUP:
if (surface->popup->seat != NULL) {
struct wlr_xdg_popup_grab *grab =
xdg_shell_popup_grab_from_seat(surface->client->shell,
surface->popup->seat);
@ -220,11 +221,12 @@ static void xdg_surface_unmap(struct wlr_xdg_surface *surface) {
wlr_seat_keyboard_end_grab(grab->seat);
}
}
}
wl_list_remove(&surface->popup->link);
free(surface->popup);
surface->popup = NULL;
surface->popup->seat = NULL;
}
break;
case WLR_XDG_SURFACE_ROLE_NONE:
assert(false && "not reached");
}
struct wlr_xdg_surface_configure *configure, *tmp;
@ -232,13 +234,7 @@ static void xdg_surface_unmap(struct wlr_xdg_surface *surface) {
xdg_surface_configure_destroy(configure);
}
surface->role = WLR_XDG_SURFACE_ROLE_NONE;
free(surface->title);
surface->title = NULL;
free(surface->app_id);
surface->app_id = NULL;
surface->added = surface->configured = surface->mapped = false;
surface->configured = surface->mapped = false;
surface->configure_serial = 0;
if (surface->configure_idle) {
wl_event_source_remove(surface->configure_idle);
@ -251,6 +247,29 @@ static void xdg_surface_unmap(struct wlr_xdg_surface *surface) {
memset(&surface->next_geometry, 0, sizeof(struct wlr_box));
}
static void xdg_toplevel_destroy(struct wlr_xdg_surface *surface) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
xdg_surface_unmap(surface);
wl_resource_set_user_data(surface->toplevel->resource, NULL);
free(surface->toplevel);
surface->toplevel = NULL;
surface->role = WLR_XDG_SURFACE_ROLE_NONE;
}
static void xdg_popup_destroy(struct wlr_xdg_surface *surface) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP);
xdg_surface_unmap(surface);
wl_resource_set_user_data(surface->popup->resource, NULL);
wl_list_remove(&surface->popup->link);
free(surface->popup);
surface->popup = NULL;
surface->role = WLR_XDG_SURFACE_ROLE_NONE;
}
static void xdg_surface_destroy(struct wlr_xdg_surface *surface) {
if (surface->role != WLR_XDG_SURFACE_ROLE_NONE) {
xdg_surface_unmap(surface);
@ -258,6 +277,18 @@ static void xdg_surface_destroy(struct wlr_xdg_surface *surface) {
wlr_signal_emit_safe(&surface->events.destroy, surface);
switch (surface->role) {
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
xdg_toplevel_destroy(surface);
break;
case WLR_XDG_SURFACE_ROLE_POPUP:
xdg_popup_destroy(surface);
break;
case WLR_XDG_SURFACE_ROLE_NONE:
// This space is intentionally left blank
break;
}
wl_resource_set_user_data(surface->resource, NULL);
wl_list_remove(&surface->link);
wl_list_remove(&surface->surface_destroy_listener.link);
@ -572,7 +603,7 @@ static void xdg_popup_resource_destroy(struct wl_resource *resource) {
struct wlr_xdg_surface *surface =
xdg_surface_from_xdg_popup_resource(resource);
if (surface != NULL) {
xdg_surface_unmap(surface);
xdg_popup_destroy(surface);
}
}
@ -671,8 +702,8 @@ static void xdg_toplevel_handle_set_title(struct wl_client *client,
return;
}
free(surface->title);
surface->title = tmp;
free(surface->toplevel->title);
surface->toplevel->title = tmp;
}
static void xdg_toplevel_handle_set_app_id(struct wl_client *client,
@ -686,8 +717,8 @@ static void xdg_toplevel_handle_set_app_id(struct wl_client *client,
return;
}
free(surface->app_id);
surface->app_id = tmp;
free(surface->toplevel->app_id);
surface->toplevel->app_id = tmp;
}
static void xdg_toplevel_handle_show_window_menu(struct wl_client *client,
@ -718,7 +749,7 @@ static void xdg_toplevel_handle_show_window_menu(struct wl_client *client,
.y = y,
};
wlr_signal_emit_safe(&surface->events.request_show_window_menu, &event);
wlr_signal_emit_safe(&surface->toplevel->events.request_show_window_menu, &event);
}
static void xdg_toplevel_handle_move(struct wl_client *client,
@ -747,7 +778,7 @@ static void xdg_toplevel_handle_move(struct wl_client *client,
.serial = serial,
};
wlr_signal_emit_safe(&surface->events.request_move, &event);
wlr_signal_emit_safe(&surface->toplevel->events.request_move, &event);
}
static void xdg_toplevel_handle_resize(struct wl_client *client,
@ -777,39 +808,39 @@ static void xdg_toplevel_handle_resize(struct wl_client *client,
.edges = edges,
};
wlr_signal_emit_safe(&surface->events.request_resize, &event);
wlr_signal_emit_safe(&surface->toplevel->events.request_resize, &event);
}
static void xdg_toplevel_handle_set_max_size(struct wl_client *client,
struct wl_resource *resource, int32_t width, int32_t height) {
struct wlr_xdg_surface *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->next.max_width = width;
surface->toplevel->next.max_height = height;
surface->toplevel->client_pending.max_width = width;
surface->toplevel->client_pending.max_height = height;
}
static void xdg_toplevel_handle_set_min_size(struct wl_client *client,
struct wl_resource *resource, int32_t width, int32_t height) {
struct wlr_xdg_surface *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->next.min_width = width;
surface->toplevel->next.min_height = height;
surface->toplevel->client_pending.min_width = width;
surface->toplevel->client_pending.min_height = height;
}
static void xdg_toplevel_handle_set_maximized(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->next.maximized = true;
wlr_signal_emit_safe(&surface->events.request_maximize, surface);
surface->toplevel->client_pending.maximized = true;
wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface);
}
static void xdg_toplevel_handle_unset_maximized(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->next.maximized = false;
wlr_signal_emit_safe(&surface->events.request_maximize, surface);
surface->toplevel->client_pending.maximized = false;
wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface);
}
static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client,
@ -822,7 +853,7 @@ static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client,
output = wlr_output_from_resource(output_resource);
}
surface->toplevel->next.fullscreen = true;
surface->toplevel->client_pending.fullscreen = true;
struct wlr_xdg_toplevel_set_fullscreen_event event = {
.surface = surface,
@ -830,7 +861,7 @@ static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client,
.output = output,
};
wlr_signal_emit_safe(&surface->events.request_fullscreen, &event);
wlr_signal_emit_safe(&surface->toplevel->events.request_fullscreen, &event);
}
static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client,
@ -838,7 +869,7 @@ static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client,
struct wlr_xdg_surface *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->next.fullscreen = false;
surface->toplevel->client_pending.fullscreen = false;
struct wlr_xdg_toplevel_set_fullscreen_event event = {
.surface = surface,
@ -846,14 +877,14 @@ static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client,
.output = NULL,
};
wlr_signal_emit_safe(&surface->events.request_fullscreen, &event);
wlr_signal_emit_safe(&surface->toplevel->events.request_fullscreen, &event);
}
static void xdg_toplevel_handle_set_minimized(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
wlr_signal_emit_safe(&surface->events.request_minimize, surface);
wlr_signal_emit_safe(&surface->toplevel->events.request_minimize, surface);
}
static const struct xdg_toplevel_interface xdg_toplevel_implementation = {
@ -885,7 +916,7 @@ static void xdg_toplevel_resource_destroy(struct wl_resource *resource) {
struct wlr_xdg_surface *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
if (surface != NULL) {
xdg_surface_unmap(surface);
xdg_toplevel_destroy(surface);
}
}
@ -903,6 +934,12 @@ static void xdg_surface_handle_get_toplevel(struct wl_client *client,
wl_resource_post_no_memory(resource);
return;
}
wl_signal_init(&surface->toplevel->events.request_maximize);
wl_signal_init(&surface->toplevel->events.request_fullscreen);
wl_signal_init(&surface->toplevel->events.request_minimize);
wl_signal_init(&surface->toplevel->events.request_move);
wl_signal_init(&surface->toplevel->events.request_resize);
wl_signal_init(&surface->toplevel->events.request_show_window_menu);
surface->role = WLR_XDG_SURFACE_ROLE_TOPLEVEL;
surface->toplevel->base = surface;
@ -1050,25 +1087,25 @@ static bool wlr_xdg_surface_toplevel_state_compare(
configured.height = configure->toplevel_state->height;
}
if (state->pending.activated != configured.state.activated) {
if (state->server_pending.activated != configured.state.activated) {
return false;
}
if (state->pending.fullscreen != configured.state.fullscreen) {
if (state->server_pending.fullscreen != configured.state.fullscreen) {
return false;
}
if (state->pending.maximized != configured.state.maximized) {
if (state->server_pending.maximized != configured.state.maximized) {
return false;
}
if (state->pending.resizing != configured.state.resizing) {
if (state->server_pending.resizing != configured.state.resizing) {
return false;
}
if (state->pending.width == configured.width &&
state->pending.height == configured.height) {
if (state->server_pending.width == configured.width &&
state->server_pending.height == configured.height) {
return true;
}
if (state->pending.width == 0 && state->pending.height == 0) {
if (state->server_pending.width == 0 && state->server_pending.height == 0) {
return true;
}
@ -1086,12 +1123,12 @@ static void wlr_xdg_toplevel_send_configure(
wl_resource_post_no_memory(surface->toplevel->resource);
return;
}
*configure->toplevel_state = surface->toplevel->pending;
*configure->toplevel_state = surface->toplevel->server_pending;
uint32_t *s;
struct wl_array states;
wl_array_init(&states);
if (surface->toplevel->pending.maximized) {
if (surface->toplevel->server_pending.maximized) {
s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(L_ERROR, "Could not allocate state for maximized xdg_toplevel");
@ -1099,7 +1136,7 @@ static void wlr_xdg_toplevel_send_configure(
}
*s = XDG_TOPLEVEL_STATE_MAXIMIZED;
}
if (surface->toplevel->pending.fullscreen) {
if (surface->toplevel->server_pending.fullscreen) {
s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(L_ERROR, "Could not allocate state for fullscreen xdg_toplevel");
@ -1107,7 +1144,7 @@ static void wlr_xdg_toplevel_send_configure(
}
*s = XDG_TOPLEVEL_STATE_FULLSCREEN;
}
if (surface->toplevel->pending.resizing) {
if (surface->toplevel->server_pending.resizing) {
s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(L_ERROR, "Could not allocate state for resizing xdg_toplevel");
@ -1115,7 +1152,7 @@ static void wlr_xdg_toplevel_send_configure(
}
*s = XDG_TOPLEVEL_STATE_RESIZING;
}
if (surface->toplevel->pending.activated) {
if (surface->toplevel->server_pending.activated) {
s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(L_ERROR, "Could not allocate state for activated xdg_toplevel");
@ -1124,8 +1161,8 @@ static void wlr_xdg_toplevel_send_configure(
*s = XDG_TOPLEVEL_STATE_ACTIVATED;
}
uint32_t width = surface->toplevel->pending.width;
uint32_t height = surface->toplevel->pending.height;
uint32_t width = surface->toplevel->server_pending.width;
uint32_t height = surface->toplevel->server_pending.height;
xdg_toplevel_send_configure(surface->toplevel->resource, width, height,
&states);
@ -1233,13 +1270,13 @@ static void wlr_xdg_surface_toplevel_committed(
// update state that doesn't need compositor approval
surface->toplevel->current.max_width =
surface->toplevel->next.max_width;
surface->toplevel->client_pending.max_width;
surface->toplevel->current.min_width =
surface->toplevel->next.min_width;
surface->toplevel->client_pending.min_width;
surface->toplevel->current.max_height =
surface->toplevel->next.max_height;
surface->toplevel->client_pending.max_height;
surface->toplevel->current.min_height =
surface->toplevel->next.min_height;
surface->toplevel->client_pending.min_height;
}
static void wlr_xdg_surface_popup_committed(
@ -1347,12 +1384,6 @@ static void xdg_shell_handle_get_xdg_surface(struct wl_client *wl_client,
wl_list_init(&surface->configure_list);
wl_list_init(&surface->popups);
wl_signal_init(&surface->events.request_maximize);
wl_signal_init(&surface->events.request_fullscreen);
wl_signal_init(&surface->events.request_minimize);
wl_signal_init(&surface->events.request_move);
wl_signal_init(&surface->events.request_resize);
wl_signal_init(&surface->events.request_show_window_menu);
wl_signal_init(&surface->events.destroy);
wl_signal_init(&surface->events.ping_timeout);
wl_signal_init(&surface->events.new_popup);
@ -1530,8 +1561,8 @@ void wlr_xdg_surface_ping(struct wlr_xdg_surface *surface) {
uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface,
uint32_t width, uint32_t height) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
surface->toplevel->pending.width = width;
surface->toplevel->pending.height = height;
surface->toplevel->server_pending.width = width;
surface->toplevel->server_pending.height = height;
return wlr_xdg_surface_schedule_configure(surface);
}
@ -1539,7 +1570,7 @@ uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface,
uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface,
bool activated) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
surface->toplevel->pending.activated = activated;
surface->toplevel->server_pending.activated = activated;
return wlr_xdg_surface_schedule_configure(surface);
}
@ -1547,7 +1578,7 @@ uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface,
uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface,
bool maximized) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
surface->toplevel->pending.maximized = maximized;
surface->toplevel->server_pending.maximized = maximized;
return wlr_xdg_surface_schedule_configure(surface);
}
@ -1555,7 +1586,7 @@ uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface,
uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface,
bool fullscreen) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
surface->toplevel->pending.fullscreen = fullscreen;
surface->toplevel->server_pending.fullscreen = fullscreen;
return wlr_xdg_surface_schedule_configure(surface);
}
@ -1563,14 +1594,27 @@ uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface,
uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface,
bool resizing) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
surface->toplevel->pending.resizing = resizing;
surface->toplevel->server_pending.resizing = resizing;
return wlr_xdg_surface_schedule_configure(surface);
}
void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
xdg_toplevel_send_close(surface->toplevel->resource);
void wlr_xdg_surface_send_close(struct wlr_xdg_surface *surface) {
switch (surface->role) {
case WLR_XDG_SURFACE_ROLE_NONE:
assert(0 && "not reached");
break;
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
if (surface->toplevel) {
xdg_toplevel_send_close(surface->toplevel->resource);
}
break;
case WLR_XDG_SURFACE_ROLE_POPUP:
if (surface->popup) {
xdg_popup_send_popup_done(surface->popup->resource);
}
break;
}
}
void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface,

View file

@ -181,18 +181,19 @@ static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) {
assert(surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE);
// TODO: probably need to ungrab before this event
wlr_signal_emit_safe(&surface->events.unmap, surface);
if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) {
wl_resource_set_user_data(surface->toplevel->resource, NULL);
free(surface->toplevel);
surface->toplevel = NULL;
if (surface->mapped) {
wlr_signal_emit_safe(&surface->events.unmap, surface);
}
if (surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) {
wl_resource_set_user_data(surface->popup->resource, NULL);
if (surface->popup->seat) {
switch (surface->role) {
case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL:
free(surface->toplevel->title);
surface->toplevel->title = NULL;
free(surface->toplevel->app_id);
surface->toplevel->app_id = NULL;
break;
case WLR_XDG_SURFACE_V6_ROLE_POPUP:
if (surface->popup->seat != NULL) {
struct wlr_xdg_popup_grab_v6 *grab =
xdg_shell_popup_grab_from_seat(surface->client->shell,
surface->popup->seat);
@ -207,11 +208,12 @@ static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) {
wlr_seat_keyboard_end_grab(grab->seat);
}
}
}
wl_list_remove(&surface->popup->link);
free(surface->popup);
surface->popup = NULL;
surface->popup->seat = NULL;
}
break;
case WLR_XDG_SURFACE_V6_ROLE_NONE:
assert(false && "not reached");
}
struct wlr_xdg_surface_v6_configure *configure, *tmp;
@ -219,13 +221,7 @@ static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) {
xdg_surface_configure_destroy(configure);
}
surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE;
free(surface->title);
surface->title = NULL;
free(surface->app_id);
surface->app_id = NULL;
surface->added = surface->configured = surface->mapped = false;
surface->configured = surface->mapped = false;
surface->configure_serial = 0;
if (surface->configure_idle) {
wl_event_source_remove(surface->configure_idle);
@ -238,6 +234,29 @@ static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) {
memset(&surface->next_geometry, 0, sizeof(struct wlr_box));
}
static void xdg_toplevel_destroy(struct wlr_xdg_surface_v6 *surface) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
xdg_surface_unmap(surface);
wl_resource_set_user_data(surface->toplevel->resource, NULL);
free(surface->toplevel);
surface->toplevel = NULL;
surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE;
}
static void xdg_popup_destroy(struct wlr_xdg_surface_v6 *surface) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP);
xdg_surface_unmap(surface);
wl_resource_set_user_data(surface->popup->resource, NULL);
wl_list_remove(&surface->popup->link);
free(surface->popup);
surface->popup = NULL;
surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE;
}
static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) {
if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) {
xdg_surface_unmap(surface);
@ -245,6 +264,18 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) {
wlr_signal_emit_safe(&surface->events.destroy, surface);
switch (surface->role) {
case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL:
xdg_toplevel_destroy(surface);
break;
case WLR_XDG_SURFACE_V6_ROLE_POPUP:
xdg_popup_destroy(surface);
break;
case WLR_XDG_SURFACE_V6_ROLE_NONE:
// This space is intentionally left blank
break;
}
wl_resource_set_user_data(surface->resource, NULL);
wl_list_remove(&surface->link);
wl_list_remove(&surface->surface_destroy_listener.link);
@ -532,7 +563,7 @@ static void xdg_popup_resource_destroy(struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_popup_resource(resource);
if (surface != NULL) {
xdg_surface_unmap(surface);
xdg_popup_destroy(surface);
}
}
@ -634,8 +665,8 @@ static void xdg_toplevel_handle_set_title(struct wl_client *client,
return;
}
free(surface->title);
surface->title = tmp;
free(surface->toplevel->title);
surface->toplevel->title = tmp;
}
static void xdg_toplevel_handle_set_app_id(struct wl_client *client,
@ -648,8 +679,8 @@ static void xdg_toplevel_handle_set_app_id(struct wl_client *client,
return;
}
free(surface->app_id);
surface->app_id = tmp;
free(surface->toplevel->app_id);
surface->toplevel->app_id = tmp;
}
static void xdg_toplevel_handle_show_window_menu(struct wl_client *client,
@ -680,7 +711,8 @@ static void xdg_toplevel_handle_show_window_menu(struct wl_client *client,
.y = y,
};
wlr_signal_emit_safe(&surface->events.request_show_window_menu, &event);
wlr_signal_emit_safe(&surface->toplevel->events.request_show_window_menu,
&event);
}
static void xdg_toplevel_handle_move(struct wl_client *client,
@ -709,7 +741,7 @@ static void xdg_toplevel_handle_move(struct wl_client *client,
.serial = serial,
};
wlr_signal_emit_safe(&surface->events.request_move, &event);
wlr_signal_emit_safe(&surface->toplevel->events.request_move, &event);
}
static void xdg_toplevel_handle_resize(struct wl_client *client,
@ -739,39 +771,39 @@ static void xdg_toplevel_handle_resize(struct wl_client *client,
.edges = edges,
};
wlr_signal_emit_safe(&surface->events.request_resize, &event);
wlr_signal_emit_safe(&surface->toplevel->events.request_resize, &event);
}
static void xdg_toplevel_handle_set_max_size(struct wl_client *client,
struct wl_resource *resource, int32_t width, int32_t height) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->next.max_width = width;
surface->toplevel->next.max_height = height;
surface->toplevel->client_pending.max_width = width;
surface->toplevel->client_pending.max_height = height;
}
static void xdg_toplevel_handle_set_min_size(struct wl_client *client,
struct wl_resource *resource, int32_t width, int32_t height) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->next.min_width = width;
surface->toplevel->next.min_height = height;
surface->toplevel->client_pending.min_width = width;
surface->toplevel->client_pending.min_height = height;
}
static void xdg_toplevel_handle_set_maximized(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->next.maximized = true;
wlr_signal_emit_safe(&surface->events.request_maximize, surface);
surface->toplevel->client_pending.maximized = true;
wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface);
}
static void xdg_toplevel_handle_unset_maximized(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->next.maximized = false;
wlr_signal_emit_safe(&surface->events.request_maximize, surface);
surface->toplevel->client_pending.maximized = false;
wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface);
}
static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client,
@ -784,7 +816,7 @@ static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client,
output = wlr_output_from_resource(output_resource);
}
surface->toplevel->next.fullscreen = true;
surface->toplevel->client_pending.fullscreen = true;
struct wlr_xdg_toplevel_v6_set_fullscreen_event event = {
.surface = surface,
@ -792,7 +824,7 @@ static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client,
.output = output,
};
wlr_signal_emit_safe(&surface->events.request_fullscreen, &event);
wlr_signal_emit_safe(&surface->toplevel->events.request_fullscreen, &event);
}
static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client,
@ -800,7 +832,7 @@ static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client,
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->next.fullscreen = false;
surface->toplevel->client_pending.fullscreen = false;
struct wlr_xdg_toplevel_v6_set_fullscreen_event event = {
.surface = surface,
@ -808,14 +840,14 @@ static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client,
.output = NULL,
};
wlr_signal_emit_safe(&surface->events.request_fullscreen, &event);
wlr_signal_emit_safe(&surface->toplevel->events.request_fullscreen, &event);
}
static void xdg_toplevel_handle_set_minimized(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
wlr_signal_emit_safe(&surface->events.request_minimize, surface);
wlr_signal_emit_safe(&surface->toplevel->events.request_minimize, surface);
}
static const struct zxdg_toplevel_v6_interface
@ -847,7 +879,7 @@ static void xdg_toplevel_resource_destroy(struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
if (surface != NULL) {
xdg_surface_unmap(surface);
xdg_toplevel_destroy(surface);
}
}
@ -865,6 +897,12 @@ static void xdg_surface_handle_get_toplevel(struct wl_client *client,
wl_resource_post_no_memory(resource);
return;
}
wl_signal_init(&surface->toplevel->events.request_maximize);
wl_signal_init(&surface->toplevel->events.request_fullscreen);
wl_signal_init(&surface->toplevel->events.request_minimize);
wl_signal_init(&surface->toplevel->events.request_move);
wl_signal_init(&surface->toplevel->events.request_resize);
wl_signal_init(&surface->toplevel->events.request_show_window_menu);
surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL;
surface->toplevel->base = surface;
@ -1012,25 +1050,25 @@ static bool wlr_xdg_surface_v6_toplevel_state_compare(
configured.height = configure->toplevel_state->height;
}
if (state->pending.activated != configured.state.activated) {
if (state->server_pending.activated != configured.state.activated) {
return false;
}
if (state->pending.fullscreen != configured.state.fullscreen) {
if (state->server_pending.fullscreen != configured.state.fullscreen) {
return false;
}
if (state->pending.maximized != configured.state.maximized) {
if (state->server_pending.maximized != configured.state.maximized) {
return false;
}
if (state->pending.resizing != configured.state.resizing) {
if (state->server_pending.resizing != configured.state.resizing) {
return false;
}
if (state->pending.width == configured.width &&
state->pending.height == configured.height) {
if (state->server_pending.width == configured.width &&
state->server_pending.height == configured.height) {
return true;
}
if (state->pending.width == 0 && state->pending.height == 0) {
if (state->server_pending.width == 0 && state->server_pending.height == 0) {
return true;
}
@ -1048,12 +1086,12 @@ static void wlr_xdg_toplevel_v6_send_configure(
wl_resource_post_no_memory(surface->toplevel->resource);
return;
}
*configure->toplevel_state = surface->toplevel->pending;
*configure->toplevel_state = surface->toplevel->server_pending;
uint32_t *s;
struct wl_array states;
wl_array_init(&states);
if (surface->toplevel->pending.maximized) {
if (surface->toplevel->server_pending.maximized) {
s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(L_ERROR, "Could not allocate state for maximized xdg_toplevel");
@ -1061,7 +1099,7 @@ static void wlr_xdg_toplevel_v6_send_configure(
}
*s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED;
}
if (surface->toplevel->pending.fullscreen) {
if (surface->toplevel->server_pending.fullscreen) {
s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(L_ERROR, "Could not allocate state for fullscreen xdg_toplevel");
@ -1069,7 +1107,7 @@ static void wlr_xdg_toplevel_v6_send_configure(
}
*s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN;
}
if (surface->toplevel->pending.resizing) {
if (surface->toplevel->server_pending.resizing) {
s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(L_ERROR, "Could not allocate state for resizing xdg_toplevel");
@ -1077,7 +1115,7 @@ static void wlr_xdg_toplevel_v6_send_configure(
}
*s = ZXDG_TOPLEVEL_V6_STATE_RESIZING;
}
if (surface->toplevel->pending.activated) {
if (surface->toplevel->server_pending.activated) {
s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(L_ERROR, "Could not allocate state for activated xdg_toplevel");
@ -1086,8 +1124,8 @@ static void wlr_xdg_toplevel_v6_send_configure(
*s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED;
}
uint32_t width = surface->toplevel->pending.width;
uint32_t height = surface->toplevel->pending.height;
uint32_t width = surface->toplevel->server_pending.width;
uint32_t height = surface->toplevel->server_pending.height;
zxdg_toplevel_v6_send_configure(surface->toplevel->resource, width,
height, &states);
@ -1195,13 +1233,13 @@ static void wlr_xdg_surface_v6_toplevel_committed(
// update state that doesn't need compositor approval
surface->toplevel->current.max_width =
surface->toplevel->next.max_width;
surface->toplevel->client_pending.max_width;
surface->toplevel->current.min_width =
surface->toplevel->next.min_width;
surface->toplevel->client_pending.min_width;
surface->toplevel->current.max_height =
surface->toplevel->next.max_height;
surface->toplevel->client_pending.max_height;
surface->toplevel->current.min_height =
surface->toplevel->next.min_height;
surface->toplevel->client_pending.min_height;
}
static void wlr_xdg_surface_v6_popup_committed(
@ -1309,12 +1347,6 @@ static void xdg_shell_handle_get_xdg_surface(struct wl_client *wl_client,
wl_list_init(&surface->configure_list);
wl_list_init(&surface->popups);
wl_signal_init(&surface->events.request_maximize);
wl_signal_init(&surface->events.request_fullscreen);
wl_signal_init(&surface->events.request_minimize);
wl_signal_init(&surface->events.request_move);
wl_signal_init(&surface->events.request_resize);
wl_signal_init(&surface->events.request_show_window_menu);
wl_signal_init(&surface->events.destroy);
wl_signal_init(&surface->events.ping_timeout);
wl_signal_init(&surface->events.new_popup);
@ -1492,8 +1524,8 @@ void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface) {
uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface,
uint32_t width, uint32_t height) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
surface->toplevel->pending.width = width;
surface->toplevel->pending.height = height;
surface->toplevel->server_pending.width = width;
surface->toplevel->server_pending.height = height;
return wlr_xdg_surface_v6_schedule_configure(surface);
}
@ -1501,7 +1533,7 @@ uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface,
uint32_t wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface,
bool activated) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
surface->toplevel->pending.activated = activated;
surface->toplevel->server_pending.activated = activated;
return wlr_xdg_surface_v6_schedule_configure(surface);
}
@ -1509,7 +1541,7 @@ uint32_t wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface,
uint32_t wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface,
bool maximized) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
surface->toplevel->pending.maximized = maximized;
surface->toplevel->server_pending.maximized = maximized;
return wlr_xdg_surface_v6_schedule_configure(surface);
}
@ -1517,7 +1549,7 @@ uint32_t wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface,
uint32_t wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface,
bool fullscreen) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
surface->toplevel->pending.fullscreen = fullscreen;
surface->toplevel->server_pending.fullscreen = fullscreen;
return wlr_xdg_surface_v6_schedule_configure(surface);
}
@ -1525,14 +1557,27 @@ uint32_t wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface,
uint32_t wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface,
bool resizing) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
surface->toplevel->pending.resizing = resizing;
surface->toplevel->server_pending.resizing = resizing;
return wlr_xdg_surface_v6_schedule_configure(surface);
}
void wlr_xdg_toplevel_v6_send_close(struct wlr_xdg_surface_v6 *surface) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
zxdg_toplevel_v6_send_close(surface->toplevel->resource);
void wlr_xdg_surface_v6_send_close(struct wlr_xdg_surface_v6 *surface) {
switch (surface->role) {
case WLR_XDG_SURFACE_V6_ROLE_NONE:
assert(0 && "not reached");
break;
case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL:
if (surface->toplevel) {
zxdg_toplevel_v6_send_close(surface->toplevel->resource);
}
break;
case WLR_XDG_SURFACE_V6_ROLE_POPUP:
if (surface->popup) {
zxdg_popup_v6_send_popup_done(surface->popup->resource);
}
break;
}
}
void wlr_xdg_surface_v6_popup_get_position(struct wlr_xdg_surface_v6 *surface,