Compare commits

...

10 commits

Author SHA1 Message Date
Simon Ser 6859861998 build: bump version to 1.7-rc2 2022-01-09 11:53:35 +01:00
Simon Ser 297a0c9d35 Destroy sub-surfaces with parent layer-shell surface
Closes: https://github.com/swaywm/sway/issues/6337
(cherry picked from commit e2b4c573d6)
2022-01-09 11:49:53 +01:00
David96 3ab1c7f153 commands/move: Fix crash when pos_y is omitted
Fixes #6737

(cherry picked from commit 1bf1d84b75)
2022-01-09 11:49:53 +01:00
David Rosca 828a9a3cfb container: Fix crash when view unmaps + maps quickly
Followup on 4e4898e90f.

If a view quickly maps and unmaps repeatedly, there will be multiple
destroyed containers with same view in a single transaction. Each of
these containers will then try to destroy this view, resulting in use
after free.
The container should only destroy the view if the view still belongs
to the container.

Simple reproducer: couple XMapWindow + XUnmapWindow in a loop followed
by XDestroyWindow.

See #6605

(cherry picked from commit f92329701b)
2022-01-07 19:36:27 +01:00
Nathan Schulte 44bb0aa3ee swaybar: fix tray item icon scaling, positioning
(cherry picked from commit 107d15fafd)
2022-01-07 15:09:24 +01:00
Nathan Schulte ec9e4630e0 swaybar: fix tray_padding vs min-height re: scale
Co-authored-by: xdavidwu <xdavidwuph@gmail.com>
(cherry picked from commit bb60381c75)
2022-01-07 15:09:24 +01:00
Thomas Hebb a235794a96 input/seat: unset has_focus when focus_stack becomes empty
We currently track the focus of a seat in two ways: we use a list called
focus_stack to track the order in which nodes have been focused, with
the first node representing what's currently focused, and we use a
variable called has_focus to indicate whether anything has focus--i.e.
whether we should actually treat that first node as focused at any given
time.

In a number of places, we treat has_focus as implying that a focused
node exists. If it's true, we attempt to dereference the return value of
seat_get_focus(), our helper function for getting the first node in
focus_list, with no further checks. But this isn't quite correct with
the current implementation of seat_get_focus(): not only does it return
NULL when has_focus is false, it also returns NULL when focus_stack
contains no items.

In most cases, focus_stack never becomes empty and so this doesn't
matter at all. Since focus_stack stores a history of focused nodes, we
rarely remove nodes from it. The exception to this is when a node itself
goes away. In that case, we call seat_node_destroy() to remove it from
focus_stack and free it. But we don't unset has_focus if we've removed
the final node! This lets us get into a state where has_focus is true
but seat_get_focus() returns NULL, leading to a segfault when we try to
dereference it.

Fix the issue both by updating has_focus in seat_node_destroy() and by
adding an assertion in seat_get_focus() that ensures focus_stack and
has_focus are in sync, which will make it easier to track down similar
issues in the future.

Fixes #6395.

[1] There's some discussion in #1585 from when this was implemented
about whether has_focus is actually necessary; it's possible we could
remove it entirely, but for the moment this is the architecture we have.

(cherry picked from commit 921b0a8633)
2022-01-07 15:09:24 +01:00
Simon Ser 0e5dda3747 build: bump version to 1.7-rc1 2021-12-23 14:38:56 +01:00
Simon Ser d7867d41c2 Add cairo_image_surface_create error handling
cairo_image_surface_create can fail, e.g. when running out of
memory or when the size is too big. Avoid crashing in this case.

Closes: https://github.com/swaywm/sway/issues/6531
(cherry picked from commit 59aebaa5f9)
2021-12-23 12:16:37 +01:00
Simon Ser 5d16d15a95 swaybar: fix errno handling in status_handle_readable
If getline fails once, it was not reset before the next getline
call. errno is only overwritten by getline on error.

(cherry picked from commit 414950bbc8)
2021-12-23 12:16:37 +01:00
9 changed files with 71 additions and 23 deletions

View file

@ -25,6 +25,8 @@ struct sway_layer_surface {
bool mapped; bool mapped;
struct wlr_box extent; struct wlr_box extent;
enum zwlr_layer_shell_v1_layer layer; enum zwlr_layer_shell_v1_layer layer;
struct wl_list subsurfaces;
}; };
struct sway_layer_popup { struct sway_layer_popup {
@ -44,6 +46,7 @@ struct sway_layer_popup {
struct sway_layer_subsurface { struct sway_layer_subsurface {
struct wlr_subsurface *wlr_subsurface; struct wlr_subsurface *wlr_subsurface;
struct sway_layer_surface *layer_surface; struct sway_layer_surface *layer_surface;
struct wl_list link;
struct wl_listener map; struct wl_listener map;
struct wl_listener unmap; struct wl_listener unmap;

View file

@ -1,7 +1,7 @@
project( project(
'sway', 'sway',
'c', 'c',
version: '1.6', version: '1.7-rc2',
license: 'MIT', license: 'MIT',
meson_version: '>=0.60.0', meson_version: '>=0.60.0',
default_options: [ default_options: [

View file

@ -874,6 +874,10 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
return cmd_results_new(CMD_INVALID, "Invalid x position specified"); return cmd_results_new(CMD_INVALID, "Invalid x position specified");
} }
if (argc < 1) {
return cmd_results_new(CMD_FAILURE, expected_position_syntax);
}
struct movement_amount ly = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID }; struct movement_amount ly = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID };
// Y direction // Y direction
num_consumed_args = parse_movement_amount(argc, argv, &ly); num_consumed_args = parse_movement_amount(argc, argv, &ly);

View file

@ -352,6 +352,8 @@ static void unmap(struct sway_layer_surface *sway_layer) {
sway_layer->layer_surface->surface, true); sway_layer->layer_surface->surface, true);
} }
static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface);
static void handle_destroy(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_layer_surface *sway_layer = struct sway_layer_surface *sway_layer =
wl_container_of(listener, sway_layer, destroy); wl_container_of(listener, sway_layer, destroy);
@ -360,6 +362,12 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
if (sway_layer->layer_surface->mapped) { if (sway_layer->layer_surface->mapped) {
unmap(sway_layer); unmap(sway_layer);
} }
struct sway_layer_subsurface *subsurface, *subsurface_tmp;
wl_list_for_each_safe(subsurface, subsurface_tmp, &sway_layer->subsurfaces, link) {
layer_subsurface_destroy(subsurface);
}
wl_list_remove(&sway_layer->link); wl_list_remove(&sway_layer->link);
wl_list_remove(&sway_layer->destroy.link); wl_list_remove(&sway_layer->destroy.link);
wl_list_remove(&sway_layer->map.link); wl_list_remove(&sway_layer->map.link);
@ -428,11 +436,8 @@ static void subsurface_handle_commit(struct wl_listener *listener, void *data) {
subsurface_damage(subsurface, false); subsurface_damage(subsurface, false);
} }
static void subsurface_handle_destroy(struct wl_listener *listener, static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface) {
void *data) { wl_list_remove(&subsurface->link);
struct sway_layer_subsurface *subsurface =
wl_container_of(listener, subsurface, destroy);
wl_list_remove(&subsurface->map.link); wl_list_remove(&subsurface->map.link);
wl_list_remove(&subsurface->unmap.link); wl_list_remove(&subsurface->unmap.link);
wl_list_remove(&subsurface->destroy.link); wl_list_remove(&subsurface->destroy.link);
@ -440,6 +445,13 @@ static void subsurface_handle_destroy(struct wl_listener *listener,
free(subsurface); free(subsurface);
} }
static void subsurface_handle_destroy(struct wl_listener *listener,
void *data) {
struct sway_layer_subsurface *subsurface =
wl_container_of(listener, subsurface, destroy);
layer_subsurface_destroy(subsurface);
}
static struct sway_layer_subsurface *create_subsurface( static struct sway_layer_subsurface *create_subsurface(
struct wlr_subsurface *wlr_subsurface, struct wlr_subsurface *wlr_subsurface,
struct sway_layer_surface *layer_surface) { struct sway_layer_surface *layer_surface) {
@ -451,6 +463,7 @@ static struct sway_layer_subsurface *create_subsurface(
subsurface->wlr_subsurface = wlr_subsurface; subsurface->wlr_subsurface = wlr_subsurface;
subsurface->layer_surface = layer_surface; subsurface->layer_surface = layer_surface;
wl_list_insert(&layer_surface->subsurfaces, &subsurface->link);
subsurface->map.notify = subsurface_handle_map; subsurface->map.notify = subsurface_handle_map;
wl_signal_add(&wlr_subsurface->events.map, &subsurface->map); wl_signal_add(&wlr_subsurface->events.map, &subsurface->map);
@ -643,6 +656,8 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
return; return;
} }
wl_list_init(&sway_layer->subsurfaces);
sway_layer->surface_commit.notify = handle_surface_commit; sway_layer->surface_commit.notify = handle_surface_commit;
wl_signal_add(&layer_surface->surface->events.commit, wl_signal_add(&layer_surface->surface->events.commit,
&sway_layer->surface_commit); &sway_layer->surface_commit);

View file

@ -51,6 +51,16 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) {
static void seat_node_destroy(struct sway_seat_node *seat_node) { static void seat_node_destroy(struct sway_seat_node *seat_node) {
wl_list_remove(&seat_node->destroy.link); wl_list_remove(&seat_node->destroy.link);
wl_list_remove(&seat_node->link); wl_list_remove(&seat_node->link);
/*
* This is the only time we remove items from the focus stack without
* immediately re-adding them. If we just removed the last thing,
* mark that nothing has focus anymore.
*/
if (wl_list_empty(&seat_node->seat->focus_stack)) {
seat_node->seat->has_focus = false;
}
free(seat_node); free(seat_node);
} }
@ -1415,9 +1425,8 @@ struct sway_node *seat_get_focus(struct sway_seat *seat) {
if (!seat->has_focus) { if (!seat->has_focus) {
return NULL; return NULL;
} }
if (wl_list_empty(&seat->focus_stack)) { sway_assert(!wl_list_empty(&seat->focus_stack),
return NULL; "focus_stack is empty, but has_focus is true");
}
struct sway_seat_node *current = struct sway_seat_node *current =
wl_container_of(seat->focus_stack.next, current, link); wl_container_of(seat->focus_stack.next, current, link);
return current->node; return current->node;

View file

@ -80,10 +80,8 @@ void container_destroy(struct sway_container *con) {
wlr_texture_destroy(con->marks_urgent); wlr_texture_destroy(con->marks_urgent);
wlr_texture_destroy(con->marks_focused_tab_title); wlr_texture_destroy(con->marks_focused_tab_title);
if (con->view) { if (con->view && con->view->container == con) {
if (con->view->container == con) {
con->view->container = NULL; con->view->container = NULL;
}
if (con->view->destroying) { if (con->view->destroying) {
view_destroy(con->view); view_destroy(con->view);
} }
@ -536,6 +534,13 @@ static void render_titlebar_text_texture(struct sway_output *output,
cairo_surface_t *surface = cairo_image_surface_create( cairo_surface_t *surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, width, height); CAIRO_FORMAT_ARGB32, width, height);
cairo_status_t status = cairo_surface_status(surface);
if (status != CAIRO_STATUS_SUCCESS) {
sway_log(SWAY_ERROR, "cairo_image_surface_create failed: %s",
cairo_status_to_string(status));
return;
}
cairo_t *cairo = cairo_create(surface); cairo_t *cairo = cairo_create(surface);
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
cairo_set_font_options(cairo, fo); cairo_set_font_options(cairo, fo);

View file

@ -117,11 +117,11 @@ bool status_handle_readable(struct status_line *status) {
status->text = status->buffer; status->text = status->buffer;
// intentional fall-through // intentional fall-through
case PROTOCOL_TEXT: case PROTOCOL_TEXT:
errno = 0;
while (true) { while (true) {
if (status->buffer[read_bytes - 1] == '\n') { if (status->buffer[read_bytes - 1] == '\n') {
status->buffer[read_bytes - 1] = '\0'; status->buffer[read_bytes - 1] = '\0';
} }
errno = 0;
read_bytes = getline(&status->buffer, read_bytes = getline(&status->buffer,
&status->buffer_size, status->read); &status->buffer_size, status->read);
if (errno == EAGAIN) { if (errno == EAGAIN) {

View file

@ -493,24 +493,36 @@ uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x,
cairo_destroy(cairo_icon); cairo_destroy(cairo_icon);
} }
int padded_size = icon_size + 2*padding; double descaled_padding = (double)padding / output->scale;
*x -= padded_size; double descaled_icon_size = (double)icon_size / output->scale;
int y = floor((height - padded_size) / 2.0);
int size = descaled_icon_size + 2 * descaled_padding;
*x -= size;
int icon_y = floor((output->height - size) / 2.0);
cairo_operator_t op = cairo_get_operator(cairo); cairo_operator_t op = cairo_get_operator(cairo);
cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
cairo_set_source_surface(cairo, icon, *x + padding, y + padding);
cairo_rectangle(cairo, *x, y, padded_size, padded_size); cairo_matrix_t scale_matrix;
cairo_pattern_t *icon_pattern = cairo_pattern_create_for_surface(icon);
// TODO: check cairo_pattern_status for "ENOMEM"
cairo_matrix_init_scale(&scale_matrix, output->scale, output->scale);
cairo_matrix_translate(&scale_matrix, -(*x + descaled_padding), -(icon_y + descaled_padding));
cairo_pattern_set_matrix(icon_pattern, &scale_matrix);
cairo_set_source(cairo, icon_pattern);
cairo_rectangle(cairo, *x, icon_y, size, size);
cairo_fill(cairo); cairo_fill(cairo);
cairo_set_operator(cairo, op); cairo_set_operator(cairo, op);
cairo_pattern_destroy(icon_pattern);
cairo_surface_destroy(icon); cairo_surface_destroy(icon);
struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
hotspot->x = *x; hotspot->x = *x;
hotspot->y = 0; hotspot->y = 0;
hotspot->width = height; hotspot->width = size;
hotspot->height = height; hotspot->height = output->height;
hotspot->callback = icon_hotspot_callback; hotspot->callback = icon_hotspot_callback;
hotspot->destroy = free; hotspot->destroy = free;
hotspot->data = strdup(sni->watcher_id); hotspot->data = strdup(sni->watcher_id);

View file

@ -116,8 +116,8 @@ uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x) {
} }
} // else display on all } // else display on all
if ((int) output->height*output->scale <= 2*config->tray_padding) { if ((int)(output->height * output->scale) <= 2 * config->tray_padding) {
return 2*config->tray_padding + 1; return (2 * config->tray_padding + 1) / output->scale;
} }
uint32_t max_height = 0; uint32_t max_height = 0;