Compare commits
41 commits
master
...
fade-anima
Author | SHA1 | Date | |
---|---|---|---|
|
6293a2370e | ||
|
ae12a9cb13 | ||
|
1d1b4fbb2f | ||
|
ad0b9171b2 | ||
|
e8f7a90104 | ||
|
819572a8d9 | ||
|
107bcde87c | ||
|
f595d42ed9 | ||
|
bdd985c30e | ||
|
f92b99ac31 | ||
|
d1fe55031a | ||
|
ae1700fa1a | ||
|
508df2216a | ||
|
8c7287d0ac | ||
|
74a7d2562d | ||
|
e5587312a8 | ||
|
d741e2415a | ||
|
b1c8ff5f58 | ||
|
9de0237b20 | ||
|
a3ef0be4fc | ||
|
30e18aae07 | ||
|
a27fa243ad | ||
|
d7cf2986fa | ||
|
2c57e2af46 | ||
|
71fa52f695 | ||
|
e20b8860da | ||
|
1390f9d3cf | ||
|
f119e9e9ee | ||
|
638373120b | ||
|
87f33da112 | ||
|
07665971dc | ||
|
3cb407e65c | ||
|
1c3b4a12ee | ||
|
e51fda46d3 | ||
|
6084ea42ec | ||
|
5bfa2e030e | ||
|
4c6826386d | ||
|
2d14d1eaa4 | ||
|
f721ef703d | ||
|
3f5511d09e | ||
|
b5410a123c |
24 changed files with 223 additions and 41 deletions
10
README.md
10
README.md
|
@ -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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 },
|
||||
|
|
21
sway/commands/animation_duration.c
Normal file
21
sway/commands/animation_duration.c
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue