Compare commits

...
Sign in to create a new pull request.

41 commits

Author SHA1 Message Date
William McKinnon
6293a2370e Merge remote-tracking branch 'origin/master' into fade-animations 2024-05-09 17:45:37 -04:00
William McKinnon
ae12a9cb13 Merge remote-tracking branch 'origin/master' into fade-animations 2024-05-08 00:30:28 -04:00
William McKinnon
1d1b4fbb2f improved animation timing 2024-04-21 23:50:11 -04:00
William McKinnon
ad0b9171b2 minor perf improvements, fixed render saved view race con 2024-04-21 23:03:35 -04:00
William McKinnon
e8f7a90104 Merge remote-tracking branch 'origin/master' into fade-animations 2024-04-20 18:04:33 -04:00
William McKinnon
819572a8d9 logic improvements 2024-04-20 16:47:42 -04:00
William McKinnon
107bcde87c removed unneeded debug lines 2024-04-20 16:47:29 -04:00
William McKinnon
f595d42ed9 removed old import 2024-04-18 02:07:07 -04:00
William McKinnon
bdd985c30e Merge remote-tracking branch 'origin/master' into fade-animations 2024-04-18 02:04:25 -04:00
William McKinnon
f92b99ac31 updated comments 2024-03-04 02:05:50 -05:00
William McKinnon
d1fe55031a made appearance of rapidly closing windows more pleasant 2024-03-04 02:04:28 -05:00
William McKinnon
ae1700fa1a added temp fix for h split 2024-02-29 19:05:53 -05:00
William McKinnon
508df2216a minor renaming and changed return val to 0 2024-02-29 18:31:16 -05:00
William McKinnon
8c7287d0ac update logic to damage track properly 2024-02-29 18:07:04 -05:00
William McKinnon
74a7d2562d improved performance 2024-02-25 17:15:55 -05:00
William McKinnon
e5587312a8 added animation manager 2024-02-24 22:32:13 -05:00
William McKinnon
d741e2415a fixed focus issues 2024-02-19 14:25:36 -05:00
William McKinnon
b1c8ff5f58 cleaned up some comments + print debug statements 2024-02-07 02:20:39 -05:00
William McKinnon
9de0237b20 added back save buffer on fade out 2024-02-07 01:01:18 -05:00
William McKinnon
a3ef0be4fc added cleanup 2024-02-06 02:03:19 -05:00
William McKinnon
30e18aae07 fixed many segfaults 2024-02-02 02:46:48 -05:00
William McKinnon
a27fa243ad render saved buffer on fade-out 2024-02-01 01:26:49 -05:00
William McKinnon
d7cf2986fa view_close now works as intended 2024-01-03 00:30:08 -05:00
William McKinnon
2c57e2af46 moved to fb approach, much broken 2023-12-27 10:14:24 -05:00
William McKinnon
71fa52f695 started the switch to a fb approach 2023-12-22 01:00:10 -05:00
William McKinnon
e20b8860da blur texture fades in / out with con 2023-09-20 21:46:07 -04:00
William McKinnon
1390f9d3cf blur texture fades in / out with con 2023-09-20 21:46:05 -04:00
William McKinnon
f119e9e9ee add shadow fade in / out with animation 2023-09-20 21:40:53 -04:00
William McKinnon
638373120b fixed fade-in delay 2023-09-20 21:40:53 -04:00
William McKinnon
87f33da112 added fade out 2023-09-20 21:40:53 -04:00
William McKinnon
07665971dc fixed con kill issue 2023-09-20 21:40:53 -04:00
William McKinnon
3cb407e65c moved animation to timer 2023-09-20 21:40:53 -04:00
William McKinnon
1c3b4a12ee fixed animation duration of 0 bug 2023-09-20 21:40:53 -04:00
William McKinnon
e51fda46d3 initial fade-out groundwork 2023-09-20 21:40:53 -04:00
William McKinnon
6084ea42ec fade-out skeleton 2023-09-20 21:40:53 -04:00
William McKinnon
5bfa2e030e added animation config 2023-09-20 21:40:50 -04:00
William McKinnon
4c6826386d optimized math of alpha_step 2023-09-20 21:40:15 -04:00
William McKinnon
2d14d1eaa4 fixed fade in for children cons 2023-09-20 21:40:15 -04:00
William McKinnon
f721ef703d renamed container alpha vars 2023-09-20 21:40:13 -04:00
William McKinnon
3f5511d09e ensured alpha isn't exceeded, added calculation for alpha_step from animation_duration 2023-09-20 21:38:40 -04:00
William McKinnon
b5410a123c initial fade-in work 2023-09-20 21:38:38 -04:00
24 changed files with 223 additions and 41 deletions

View file

@ -25,6 +25,14 @@ Sway is an incredible window manager, and certainly one of the most well establi
## New Configuration Options
+ Fade in / out animations: `animation_duration <val>`: specifies the length of the animation in seconds
+ Corner radius: `corner_radius <val>`
+ Smart corner radius: `smart_corner_radius enable|disable`
+ Window shadows:
- `shadows enable|disable`
- `shadows_on_csd enable|disable` (**Note**: The shadow might not fit some windows)
- `shadow_blur_radius <integer value 0 - 100>`
- `shadow_color <hex color with alpha> ex, #0000007F`
+ Window blur:
- `blur enable|disable`
- `blur_xray enable|disable`: this will set floating windows to blur based on the background, not the windows below. You probably want to set this to `disable` :)
@ -64,7 +72,6 @@ Sway is an incredible window manager, and certainly one of the most well establi
## Roadmap
+ fade in / out animations
+ window movement animations
## Compiling From Source
@ -137,4 +144,3 @@ We would also like to thank the talented artists in our community for contibutin
+ spooky_skeleton for the swayfx logo, and [Basil](https://basil.cafe) for making some fine adjustments to it
Lastly, we would like to thank you, the community, for enjoying and using window manager that we have spent so much time maintaining.

View file

@ -109,6 +109,7 @@ bool cmd_corner_radius_parse_value(char *arg, int* result);
sway_cmd cmd_exec_validate;
sway_cmd cmd_exec_process;
sway_cmd cmd_animation_duration;
sway_cmd cmd_assign;
sway_cmd cmd_bar;
sway_cmd cmd_bindcode;

View file

@ -478,6 +478,8 @@ enum xwayland_mode {
* The configuration struct. The result of loading a config file.
*/
struct sway_config {
float animation_duration;
int corner_radius;
bool smart_corner_radius;

View file

@ -77,6 +77,7 @@ struct sway_output {
struct timespec last_presentation;
uint32_t refresh_nsec;
float refresh_sec;
int max_render_time; // In milliseconds
struct wl_event_source *repaint_timer;
bool gamma_lut_changed;

View file

@ -143,6 +143,9 @@ struct sway_server {
// Stores the nodes that have been marked as "dirty" and will be put into
// the pending transaction.
list_t *dirty_nodes;
list_t *animated_containers;
struct wl_event_source *animation_tick;
};
extern struct sway_server server;

View file

@ -124,10 +124,13 @@ struct sway_container {
// Unused for non-scratchpad windows.
struct wlr_box transform;
// TODO: move alpha to state?
float alpha;
float target_alpha;
float max_alpha;
int corner_radius;
float dim;
struct wlr_texture *title_focused;

View file

@ -320,6 +320,8 @@ void view_for_each_popup_surface(struct sway_view *view,
void view_init(struct sway_view *view, enum sway_view_type type,
const struct sway_view_impl *impl);
void view_remove_container(struct sway_container *container);
void view_destroy(struct sway_view *view);
void view_begin_destroy(struct sway_view *view);

View file

@ -43,6 +43,7 @@ struct cmd_results *checkarg(int argc, const char *name, enum expected_args type
/* Keep alphabetized */
static const struct cmd_handler handlers[] = {
{ "animation_duration", cmd_animation_duration },
{ "assign", cmd_assign },
{ "bar", cmd_bar },
{ "bindcode", cmd_bindcode },

View file

@ -0,0 +1,21 @@
#include <string.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "log.h"
struct cmd_results *cmd_animation_duration(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "animation_duration", EXPECTED_EQUAL_TO, 1))) {
return error;
}
char *err;
float value = strtof(argv[0], &err);
if (*err || value < 0.0f || value > 1.0f) {
return cmd_results_new(CMD_FAILURE, "animation_duration value invalid");
}
config->animation_duration = value;
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -24,9 +24,9 @@ struct cmd_results *cmd_opacity(int argc, char **argv) {
}
if (!strcasecmp(argv[0], "plus")) {
val = con->alpha + val;
val = con->max_alpha + val;
} else if (!strcasecmp(argv[0], "minus")) {
val = con->alpha - val;
val = con->max_alpha - val;
} else if (argc > 1 && strcasecmp(argv[0], "set")) {
return cmd_results_new(CMD_INVALID,
"Expected: set|plus|minus <0..1>: %s", argv[0]);
@ -36,7 +36,8 @@ struct cmd_results *cmd_opacity(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE, "opacity value out of bounds");
}
con->alpha = val;
con->max_alpha = val;
con->target_alpha = val;
container_damage_whole(con);
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -342,6 +342,8 @@ static void config_defaults(struct sway_config *config) {
color_to_rgba(config->border_colors.background, 0xFFFFFFFF);
// SwayFX defaults
config->animation_duration = 0;
config->corner_radius = 0;
config->smart_corner_radius = true;

View file

@ -660,6 +660,7 @@ static int output_repaint_timer_handler(void *data) {
pixman_region32_t damage;
pixman_region32_init(&damage);
wlr_damage_ring_get_buffer_damage(&output->damage_ring, buffer_age, &damage);
if (debug.damage == DAMAGE_RERENDER) {
@ -729,7 +730,7 @@ static void handle_frame(struct wl_listener *listener, void *user_data) {
const long NSEC_IN_SECONDS = 1000000000;
struct timespec predicted_refresh = output->last_presentation;
predicted_refresh.tv_nsec += output->refresh_nsec % NSEC_IN_SECONDS;
predicted_refresh.tv_sec += output->refresh_nsec / NSEC_IN_SECONDS;
predicted_refresh.tv_sec += output->refresh_sec;
if (predicted_refresh.tv_nsec >= NSEC_IN_SECONDS) {
predicted_refresh.tv_sec += 1;
predicted_refresh.tv_nsec -= NSEC_IN_SECONDS;
@ -1030,6 +1031,9 @@ static void handle_present(struct wl_listener *listener, void *data) {
output->last_presentation = *output_event->when;
output->refresh_nsec = output_event->refresh;
const long NSEC_IN_SECONDS = 1000000000;
output->refresh_sec = (float)output_event->refresh / NSEC_IN_SECONDS;
}
static void handle_request_state(struct wl_listener *listener, void *data) {

View file

@ -92,6 +92,14 @@ struct decoration_data get_undecorated_decoration_data() {
};
}
// TODO: don't need pointer
float get_animation_completion_percentage(struct sway_container *con) {
if (con->alpha == 1.0f) {
return 1.0f;
}
return con->alpha < con->target_alpha ? con->alpha / con->target_alpha : con->alpha / con->max_alpha;
}
/**
* Apply scale to a width or height.
*
@ -375,10 +383,11 @@ static void render_surface_iterator(struct sway_output *output,
if (has_alpha) {
bool should_optimize_blur = view ?
!container_is_floating_or_child(view->container) || config->blur_xray
: false;
!container_is_floating_or_child(view->container) || config->blur_xray : false;
struct decoration_data blur_deco_data = deco_data;
blur_deco_data.alpha = view ? get_animation_completion_percentage(view->container) : 1.0f;
render_blur(data->ctx, texture, &src_box, &clip_box,
should_optimize_blur, &opaque_region, deco_data);
should_optimize_blur, &opaque_region, blur_deco_data);
}
pixman_region32_fini(&opaque_region);
@ -677,9 +686,11 @@ static void render_saved_view(struct fx_render_context *ctx, struct sway_view *v
pixman_region32_union_rect(&opaque_region, &opaque_region, 0, 0, 0, 0);
bool should_optimize_blur = !container_is_floating_or_child(view->container) || config->blur_xray;
render_blur(ctx, saved_buf->buffer->texture,
&saved_buf->source_box, &clip_box, should_optimize_blur,
&opaque_region, deco_data);
struct decoration_data blur_deco_data = deco_data;
blur_deco_data.alpha = get_animation_completion_percentage(view->container);
render_blur(ctx, saved_buf->buffer->texture, &saved_buf->source_box, &clip_box,
should_optimize_blur, &opaque_region, blur_deco_data);
pixman_region32_fini(&opaque_region);
}
@ -729,6 +740,7 @@ static void render_view(struct fx_render_context *ctx, struct sway_container *co
int shadow_corner_radius = corner_radius == 0 ? 0 : corner_radius + state->border_thickness;
float* shadow_color = view_is_urgent(view) || state->focused ?
config->shadow_color : config->shadow_inactive_color;
shadow_color[3] *= get_animation_completion_percentage(con);
render_box_shadow(ctx, &box, shadow_color, config->shadow_blur_sigma * output_scale,
shadow_corner_radius * output_scale, config->shadow_offset_x * output_scale,

View file

@ -256,7 +256,7 @@ static void apply_container_state(struct sway_container *container,
memcpy(&container->current, state, sizeof(struct sway_container_state));
if (view && !wl_list_empty(&view->saved_buffers)) {
if (view && !wl_list_empty(&view->saved_buffers) && view->surface) {
if (!container->node.destroying || container->node.ntxnrefs == 1) {
view_remove_saved_buffer(view);
}
@ -365,6 +365,9 @@ static bool should_configure(struct sway_node *node,
if (!node_is_view(node)) {
return false;
}
if (!node->sway_container->view->surface) {
return false;
}
if (node->destroying) {
return false;
}

View file

@ -525,6 +525,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
}
static void handle_destroy(struct wl_listener *listener, void *data) {
/*
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, destroy);
struct sway_view *view = &xdg_shell_view->view;
@ -539,6 +540,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
view->xdg_decoration->view = NULL;
}
view_begin_destroy(view);
*/
}
struct sway_view *view_from_wlr_xdg_surface(

View file

@ -269,7 +269,7 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) {
while (next_focus == NULL && parent != NULL) {
struct sway_container *con =
seat_get_focus_inactive_view(seat, parent);
next_focus = con ? &con->node : NULL;
next_focus = (con && !con->node.destroying) ? &con->node : NULL;
if (next_focus == NULL && parent->type == N_WORKSPACE) {
next_focus = parent;
@ -1092,6 +1092,9 @@ void seat_configure_xcursor(struct sway_seat *seat) {
bool seat_is_input_allowed(struct sway_seat *seat,
struct wlr_surface *surface) {
if (surface == NULL) {
return false;
}
if (server.session_lock.locked) {
if (server.session_lock.lock == NULL) {
return false;
@ -1109,7 +1112,7 @@ bool seat_is_input_allowed(struct sway_seat *seat,
}
static void send_unfocus(struct sway_container *con, void *data) {
if (con->view) {
if (con->view && con->view->surface) {
view_set_activated(con->view, false);
}
}
@ -1257,7 +1260,7 @@ static void seat_set_workspace_focus(struct sway_seat *seat, struct sway_node *n
}
// Close any popups on the old focus
if (last_focus && node_is_view(last_focus)) {
if (last_focus && node_is_view(last_focus) && last_focus->sway_container->view->surface) {
view_close_popups(last_focus->sway_container->view);
}

View file

@ -583,7 +583,7 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
// This is where we handle the common case. We don't want to focus inactive
// tabs, hence the view_is_visible check.
if (node_is_view(hovered_node) &&
if (node_is_view(hovered_node) && hovered_node->sway_container->view->surface &&
view_is_visible(hovered_node->sway_container->view)) {
// e->previous_node is the node which the cursor was over previously.
// If focus_follows_mouse is yes and the cursor got over the view due

View file

@ -792,7 +792,8 @@ static void ipc_json_describe_container(struct sway_container *c, json_object *o
json_object_object_add(object, "marks", marks);
if (c->view) {
// check if view exists and if it has not been unmapped
if (c->view && c->view->surface) {
ipc_json_describe_view(c, object);
}
}

View file

@ -43,6 +43,7 @@ sway_sources = files(
'config/seat.c',
'config/input.c',
'commands/animation_duration.c',
'commands/assign.c',
'commands/bar.c',
'commands/bind.c',

View file

@ -44,6 +44,7 @@
#include "log.h"
#include "sway/config.h"
#include "sway/desktop/idle_inhibit_v1.h"
#include "sway/desktop/transaction.h"
#include "sway/input/input-manager.h"
#include "sway/output.h"
#include "sway/server.h"
@ -76,6 +77,74 @@ static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
}
#endif
float get_fastest_output_refresh_s() {
float fastest_output_refresh_s = 0.0166667; // fallback to 60 Hz
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
if (output->refresh_nsec > 0) {
fastest_output_refresh_s = MIN(fastest_output_refresh_s, output->refresh_sec);
}
}
return fastest_output_refresh_s;
}
// TODO: animation struct with callback on completion
// TODO: fix new window placement when a container is fading out
static int animation_timer(void *data) {
clock_t start = clock();
struct sway_server *server = data;
float fastest_output_refresh_s = get_fastest_output_refresh_s();
int num_containers;
memcpy(&num_containers, &server->animated_containers->length, sizeof(int));
if (num_containers == 0) {
goto animation_timer_queue_next;
}
bool is_container_close_animation_complete = false;
bool should_delay_transaction_commit = false;
// update state from end to start of list: this ensures removing containers from the list won't
// impact indices of later list members that are iterated through
for (int i = num_containers - 1; i >= 0; i--) {
struct sway_container *con = server->animated_containers->items[i];
sway_assert(con->view, "container being animated is not a view container");
bool is_closing = con->alpha > con->target_alpha;
float alpha_step = config->animation_duration ?
(con->max_alpha * fastest_output_refresh_s) / config->animation_duration : con->max_alpha;
con->alpha = is_closing ? MAX(con->alpha - alpha_step, con->target_alpha) :
MIN(con->alpha + alpha_step, con->target_alpha);
if (con->alpha == con->target_alpha) {
list_del(server->animated_containers, i);
if (con->alpha == 0) {
view_remove_container(con);
is_container_close_animation_complete = true;
}
} else if (is_closing) {
should_delay_transaction_commit = true;
}
if (view_is_visible(con->view)) {
container_damage_whole(con);
}
}
// damage track
if (is_container_close_animation_complete && !should_delay_transaction_commit) {
transaction_commit_dirty();
}
animation_timer_queue_next:
float seconds_to_complete_animation_frame = (float)(clock() - start) / CLOCKS_PER_SEC;
float time_delta_s = MAX(fastest_output_refresh_s - seconds_to_complete_animation_frame, 0.001);
wl_event_source_timer_update(server->animation_tick, time_delta_s * 1000);
return 0;
}
#define SWAY_XDG_SHELL_VERSION 2
static bool is_privileged(const struct wl_global *global) {
#if WLR_HAS_DRM_BACKEND
if (server.drm_lease_manager != NULL) {
@ -340,6 +409,10 @@ bool server_init(struct sway_server *server) {
server->input = input_manager_create(server);
input_manager_get_default_seat(); // create seat0
server->animated_containers = create_list();
server->animation_tick = wl_event_loop_add_timer(server->wl_event_loop, animation_timer, server);
wl_event_source_timer_update(server->animation_tick, 1);
return true;
}
@ -351,6 +424,8 @@ void server_fini(struct sway_server *server) {
wl_display_destroy_clients(server->wl_display);
wl_display_destroy(server->wl_display);
list_free(server->dirty_nodes);
list_free(server->animated_containers);
wl_event_source_remove(server->animation_tick);
}
bool server_start(struct sway_server *server) {

View file

@ -378,6 +378,9 @@ set|plus|minus|toggle <amount>
The following commands may be used either in the configuration file or at
runtime.
*animation_duration <seconds>*
Specifies the length of the animation in seconds, between 0 and 1 second.
*assign* <criteria> [→] [workspace] [number] <workspace>
Assigns views matching _criteria_ (see *CRITERIA* for details) to
_workspace_. The → (U+2192) is optional and cosmetic. This command is

View file

@ -36,7 +36,9 @@ struct sway_container *container_create(struct sway_view *view) {
node_init(&c->node, N_CONTAINER, c);
c->pending.layout = L_NONE;
c->view = view;
c->alpha = 1.0f;
c->alpha = 0.0f;
c->target_alpha = 1.0f;
c->max_alpha = 1.0f;
c->saturation = 1.0f;
c->dim = config->default_dim_inactive;
c->shadow_enabled = config->shadow_enabled;
@ -46,17 +48,21 @@ struct sway_container *container_create(struct sway_view *view) {
if (!view) {
c->pending.children = create_list();
c->current.children = create_list();
} else {
list_add(server.animated_containers, c);
}
c->marks = create_list();
c->outputs = create_list();
wl_signal_init(&c->events.destroy);
wl_signal_emit_mutable(&root->events.new_node, &c->node);
return c;
}
void container_destroy(struct sway_container *con) {
printf("destroying container\n");
if (!sway_assert(con->node.destroying,
"Tried to free container which wasn't marked as destroying")) {
return;
@ -94,6 +100,7 @@ void container_destroy(struct sway_container *con) {
}
void container_begin_destroy(struct sway_container *con) {
printf("container begin destroy\n");
if (con->view) {
ipc_event_window(con, "close");
}
@ -182,6 +189,9 @@ static struct sway_container *surface_at_view(struct sway_container *con, double
return NULL;
}
struct sway_view *view = con->view;
if (!view->surface) {
return NULL;
}
double view_sx = lx - con->surface_x + view->geometry.x;
double view_sy = ly - con->surface_y + view->geometry.y;
@ -632,7 +642,7 @@ size_t container_build_representation(enum sway_container_layout layout,
}
struct sway_container *child = children->items[i];
const char *identifier = NULL;
if (child->view) {
if (child->view && child->view->surface) {
identifier = view_get_class(child->view);
if (!identifier) {
identifier = view_get_app_id(child->view);

View file

@ -47,6 +47,7 @@ void view_init(struct sway_view *view, enum sway_view_type type,
}
void view_destroy(struct sway_view *view) {
printf("view destroy\n");
if (!sway_assert(view->surface == NULL, "Tried to free mapped view")) {
return;
}
@ -76,7 +77,31 @@ void view_destroy(struct sway_view *view) {
}
}
void view_remove_container(struct sway_container *container) {
if (!wl_list_empty(&container->view->saved_buffers)) {
view_remove_saved_buffer(container->view);
}
struct sway_container *parent = container->pending.parent;
struct sway_workspace *ws = container->pending.workspace;
container_begin_destroy(container);
if (parent) {
container_reap_empty(parent);
} else if (ws) {
workspace_consider_destroy(ws);
}
if (root->fullscreen_global) {
// Container may have been a child of the root fullscreen container
arrange_root();
} else if (ws && !ws->node.destroying) {
arrange_workspace(ws);
workspace_detect_urgent(ws);
}
}
void view_begin_destroy(struct sway_view *view) {
printf("view begin destroy\n");
if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) {
return;
}
@ -170,7 +195,7 @@ void view_get_constraints(struct sway_view *view, double *min_width,
uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
int height) {
if (view->impl->configure) {
if (view->impl->configure && view->surface) {
return view->impl->configure(view, lx, ly, width, height);
}
return 0;
@ -438,7 +463,7 @@ void view_set_tiled(struct sway_view *view, bool tiled) {
}
void view_close(struct sway_view *view) {
if (view->impl->close) {
if (view->impl->close && view->surface) {
view->impl->close(view);
}
}
@ -916,6 +941,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
}
void view_unmap(struct sway_view *view) {
printf("unmapping view\n");
wl_signal_emit_mutable(&view->events.unmap, view);
wl_list_remove(&view->surface_new_subsurface.link);
@ -932,22 +958,18 @@ void view_unmap(struct sway_view *view) {
view->foreign_toplevel = NULL;
}
struct sway_container *parent = view->container->pending.parent;
struct sway_workspace *ws = view->container->pending.workspace;
container_begin_destroy(view->container);
if (parent) {
container_reap_empty(parent);
} else if (ws) {
workspace_consider_destroy(ws);
}
if (root->fullscreen_global) {
// Container may have been a child of the root fullscreen container
arrange_root();
} else if (ws && !ws->node.destroying) {
arrange_workspace(ws);
workspace_detect_urgent(ws);
}
/*
if (!config->animation_duration) {
view_remove_container(view);
transaction_commit_dirty();
} else {*/
wl_signal_emit_mutable(&view->container->node.events.destroy, &view->container->node);
if (wl_list_empty(&view->saved_buffers)) {
view_save_buffer(view);
}
view->container->target_alpha = 0;
list_add(server.animated_containers, view->container);
//}
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
@ -962,7 +984,6 @@ void view_unmap(struct sway_view *view) {
seat_consider_warp_to_focus(seat);
}
transaction_commit_dirty();
view->surface = NULL;
}
@ -1369,6 +1390,9 @@ void view_update_title(struct sway_view *view, bool force) {
}
bool view_is_visible(struct sway_view *view) {
if (!view->container) {
return false;
}
if (view->container->node.destroying) {
return false;
}

View file

@ -682,7 +682,8 @@ struct blur_region_data {
static void find_blurred_region_iterator(struct sway_container *con, void *data) {
struct sway_view *view = con->view;
if (!view) {
// TODO: proper view cleanup
if (!view || !view->surface) {
return;
}