diff --git a/CHANGELOG.md b/CHANGELOG.md index fecef31f..8f3d4905 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] ### Changed - Properly return focus to the active window on the current space when a window is moved through a rule [#418](https://github.com/koekeishiya/yabai/issues/418) +- Prevent space operations (create, destroy, focus, swap, move and send to display) from applying while mission-control is active or the display is animating [#417](https://github.com/koekeishiya/yabai/issues/417) ## [2.3.0] - 2020-02-14 ### Added diff --git a/src/message.c b/src/message.c index 5b575e10..b3355000 100644 --- a/src/message.c +++ b/src/message.c @@ -1295,7 +1295,14 @@ static void handle_domain_space(FILE *rsp, struct token domain, char *message) if (token_equals(command, COMMAND_SPACE_FOCUS)) { struct selector selector = parse_space_selector(rsp, &message, acting_sid); if (selector.did_parse && selector.sid) { - space_manager_focus_space(selector.sid); + enum space_op_error result = space_manager_focus_space(selector.sid); + if (result == SPACE_OP_ERROR_SAME_SPACE) { + daemon_fail(rsp, "cannot focus an already focused space.\n"); + } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) { + daemon_fail(rsp, "cannot focus space because the display is in the middle of an animation.\n"); + } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) { + daemon_fail(rsp, "cannot focus space because mission-control is active.\n"); + } } } else if (token_equals(command, COMMAND_SPACE_MOVE)) { struct selector selector = parse_space_selector(rsp, &message, acting_sid); @@ -1305,6 +1312,10 @@ static void handle_domain_space(FILE *rsp, struct token domain, char *message) daemon_fail(rsp, "cannot move space to itself.\n"); } else if (result == SPACE_OP_ERROR_SAME_DISPLAY) { daemon_fail(rsp, "cannot move space across display boundaries. use --display instead.\n"); + } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) { + daemon_fail(rsp, "cannot move space because the display is in the middle of an animation.\n"); + } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) { + daemon_fail(rsp, "cannot move space because mission-control is active.\n"); } } } else if (token_equals(command, COMMAND_SPACE_SWAP)) { @@ -1315,6 +1326,10 @@ static void handle_domain_space(FILE *rsp, struct token domain, char *message) daemon_fail(rsp, "cannot swap space with itself.\n"); } else if (result == SPACE_OP_ERROR_SAME_DISPLAY) { daemon_fail(rsp, "cannot swap space across display boundaries. use --display instead.\n"); + } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) { + daemon_fail(rsp, "cannot swap space because the display is in the middle of an animation.\n"); + } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) { + daemon_fail(rsp, "cannot swap space because mission-control is active.\n"); } } } else if (token_equals(command, COMMAND_SPACE_DISPLAY)) { @@ -1329,10 +1344,21 @@ static void handle_domain_space(FILE *rsp, struct token domain, char *message) daemon_fail(rsp, "acting space is the last user-space on the source display and cannot be moved.\n"); } else if (result == SPACE_OP_ERROR_INVALID_DST) { daemon_fail(rsp, "acting space is already located on the given display.\n"); + } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) { + daemon_fail(rsp, "cannot send space to display because it is in the middle of an animation.\n"); + } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) { + daemon_fail(rsp, "cannot send space to display because mission-control is active.\n"); } } } else if (token_equals(command, COMMAND_SPACE_CREATE)) { - space_manager_add_space(acting_sid); + enum space_op_error result = space_manager_add_space(acting_sid); + if (result == SPACE_OP_ERROR_MISSING_SRC) { + daemon_fail(rsp, "could not locate the space to act on.\n"); + } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) { + daemon_fail(rsp, "cannot create space because the display is in the middle of an animation.\n"); + } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) { + daemon_fail(rsp, "cannot create space because mission-control is active.\n"); + } } else if (token_equals(command, COMMAND_SPACE_DESTROY)) { enum space_op_error result = space_manager_destroy_space(acting_sid); if (result == SPACE_OP_ERROR_MISSING_SRC) { @@ -1341,6 +1367,10 @@ static void handle_domain_space(FILE *rsp, struct token domain, char *message) daemon_fail(rsp, "acting space is the last user-space on the source display and cannot be destroyed.\n"); } else if (result == SPACE_OP_ERROR_INVALID_TYPE) { daemon_fail(rsp, "cannot destroy a macOS fullscreen space.\n"); + } else if (result == SPACE_OP_ERROR_DISPLAY_IS_ANIMATING) { + daemon_fail(rsp, "cannot destroy space because the display is in the middle of an animation.\n"); + } else if (result == SPACE_OP_ERROR_IN_MISSION_CONTROL) { + daemon_fail(rsp, "cannot destroy space because mission-control is active.\n"); } } else if (token_equals(command, COMMAND_SPACE_BALANCE)) { space_manager_balance_space(&g_space_manager, acting_sid); diff --git a/src/space_manager.c b/src/space_manager.c index eb57516d..052f9011 100644 --- a/src/space_manager.c +++ b/src/space_manager.c @@ -2,6 +2,7 @@ extern struct window_manager g_window_manager; extern char g_sa_socket_file[MAXLEN]; +extern bool g_mission_control_active; extern int g_connection; static TABLE_HASH_FUNC(hash_view) @@ -595,25 +596,34 @@ void space_manager_move_window_to_space(uint64_t sid, struct window *window) CFRelease(window_list_ref); } -void space_manager_focus_space(uint64_t sid) +enum space_op_error space_manager_focus_space(uint64_t sid) { int sockfd; char message[MAXLEN]; + bool is_in_mc = g_mission_control_active; + if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL; + uint64_t cur_sid = space_manager_active_space(); + if (cur_sid == sid) return SPACE_OP_ERROR_SAME_SPACE; + uint32_t cur_did = space_display_id(cur_sid); uint32_t new_did = space_display_id(sid); + bool focus_display = cur_did != new_did; + + bool is_animating = display_manager_display_is_animating(new_did); + if (is_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING; if (socket_connect_un(&sockfd, g_sa_socket_file)) { snprintf(message, sizeof(message), "space %lld", sid); socket_write(sockfd, message); socket_wait(sockfd); - if (cur_did != new_did) { - display_manager_focus_display(new_did); - } + if (focus_display) display_manager_focus_display(new_did); } socket_close(sockfd); + + return SPACE_OP_ERROR_SUCCESS; } static inline bool space_manager_is_space_last_user_space(uint64_t sid) @@ -656,12 +666,18 @@ static void space_manager_move_space_after_space(uint64_t src_sid, uint64_t dst_ enum space_op_error space_manager_swap_space_with_space(uint64_t acting_sid, uint64_t selector_sid) { + bool is_in_mc = g_mission_control_active; + if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL; + uint32_t acting_did = space_display_id(acting_sid); uint32_t selector_did = space_display_id(selector_sid); if (acting_sid == selector_sid) return SPACE_OP_ERROR_SAME_SPACE; if (acting_did != selector_did) return SPACE_OP_ERROR_SAME_DISPLAY; + bool is_animating = display_manager_display_is_animating(acting_did); + if (is_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING; + uint64_t acting_prev_sid = space_manager_prev_space(acting_sid); uint64_t selector_prev_sid = space_manager_prev_space(selector_sid); @@ -699,12 +715,18 @@ enum space_op_error space_manager_swap_space_with_space(uint64_t acting_sid, uin enum space_op_error space_manager_move_space_to_space(uint64_t acting_sid, uint64_t selector_sid) { + bool is_in_mc = g_mission_control_active; + if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL; + uint32_t acting_did = space_display_id(acting_sid); uint32_t selector_did = space_display_id(selector_sid); if (acting_sid == selector_sid) return SPACE_OP_ERROR_SAME_SPACE; if (acting_did != selector_did) return SPACE_OP_ERROR_SAME_DISPLAY; + bool is_animating = display_manager_display_is_animating(acting_did); + if (is_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING; + uint64_t acting_prev_sid = space_manager_prev_space(acting_sid); uint64_t selector_prev_sid = space_manager_prev_space(selector_sid); @@ -733,14 +755,25 @@ enum space_op_error space_manager_move_space_to_space(uint64_t acting_sid, uint6 enum space_op_error space_manager_move_space_to_display(struct space_manager *sm, uint64_t sid, uint32_t did) { int sockfd; - uint64_t d_sid; char message[MAXLEN]; - if (!sid) return SPACE_OP_ERROR_MISSING_SRC; - if (space_display_id(sid) == did) return SPACE_OP_ERROR_INVALID_DST; - if (space_manager_is_space_last_user_space(sid)) return SPACE_OP_ERROR_INVALID_SRC; + bool is_in_mc = g_mission_control_active; + if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL; + if (!sid) return SPACE_OP_ERROR_MISSING_SRC; + + uint32_t s_did = space_display_id(sid); + if (s_did == did) return SPACE_OP_ERROR_INVALID_DST; + + bool is_src_animating = display_manager_display_is_animating(s_did); + if (is_src_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING; + + bool last_space = space_manager_is_space_last_user_space(sid); + if (last_space) return SPACE_OP_ERROR_INVALID_SRC; + + bool is_dst_animating = display_manager_display_is_animating(did); + if (is_dst_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING; - d_sid = display_space_id(did); + uint64_t d_sid = display_space_id(did); if (!d_sid) return SPACE_OP_ERROR_MISSING_DST; if (socket_connect_un(&sockfd, g_sa_socket_file)) { @@ -761,10 +794,16 @@ enum space_op_error space_manager_destroy_space(uint64_t sid) int sockfd; char message[MAXLEN]; + bool is_in_mc = g_mission_control_active; + if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL; + if (!sid) return SPACE_OP_ERROR_MISSING_SRC; if (!space_is_user(sid)) return SPACE_OP_ERROR_INVALID_TYPE; if (space_manager_is_space_last_user_space(sid)) return SPACE_OP_ERROR_INVALID_SRC; + bool is_animating = display_manager_display_is_animating(space_display_id(sid)); + if (is_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING; + if (socket_connect_un(&sockfd, g_sa_socket_file)) { snprintf(message, sizeof(message), "space_destroy %lld", sid); socket_write(sockfd, message); @@ -775,12 +814,17 @@ enum space_op_error space_manager_destroy_space(uint64_t sid) return SPACE_OP_ERROR_SUCCESS; } -void space_manager_add_space(uint64_t sid) +enum space_op_error space_manager_add_space(uint64_t sid) { int sockfd; char message[MAXLEN]; - if (!sid) return; + bool is_in_mc = g_mission_control_active; + if (is_in_mc) return SPACE_OP_ERROR_IN_MISSION_CONTROL; + if (!sid) return SPACE_OP_ERROR_MISSING_SRC; + + bool is_animating = display_manager_display_is_animating(space_display_id(sid)); + if (is_animating) return SPACE_OP_ERROR_DISPLAY_IS_ANIMATING; if (socket_connect_un(&sockfd, g_sa_socket_file)) { snprintf(message, sizeof(message), "space_create %lld", sid); @@ -788,6 +832,8 @@ void space_manager_add_space(uint64_t sid) socket_wait(sockfd); } socket_close(sockfd); + + return SPACE_OP_ERROR_SUCCESS; } void space_manager_assign_process_to_space(pid_t pid, uint64_t sid) diff --git a/src/space_manager.h b/src/space_manager.h index f37ff01c..2f2b0cc9 100644 --- a/src/space_manager.h +++ b/src/space_manager.h @@ -34,14 +34,16 @@ struct space_manager enum space_op_error { - SPACE_OP_ERROR_SUCCESS = 0, - SPACE_OP_ERROR_MISSING_SRC = 1, - SPACE_OP_ERROR_MISSING_DST = 2, - SPACE_OP_ERROR_INVALID_SRC = 3, - SPACE_OP_ERROR_INVALID_DST = 4, - SPACE_OP_ERROR_INVALID_TYPE = 5, - SPACE_OP_ERROR_SAME_SPACE = 6, - SPACE_OP_ERROR_SAME_DISPLAY = 7, + SPACE_OP_ERROR_SUCCESS = 0, + SPACE_OP_ERROR_MISSING_SRC = 1, + SPACE_OP_ERROR_MISSING_DST = 2, + SPACE_OP_ERROR_INVALID_SRC = 3, + SPACE_OP_ERROR_INVALID_DST = 4, + SPACE_OP_ERROR_INVALID_TYPE = 5, + SPACE_OP_ERROR_SAME_SPACE = 6, + SPACE_OP_ERROR_SAME_DISPLAY = 7, + SPACE_OP_ERROR_DISPLAY_IS_ANIMATING = 8, + SPACE_OP_ERROR_IN_MISSION_CONTROL = 9, }; bool space_manager_has_separate_spaces(void); @@ -85,12 +87,12 @@ void space_manager_toggle_padding_for_space(struct space_manager *sm, uint64_t s void space_manager_rotate_space(struct space_manager *sm, uint64_t sid, int degrees); void space_manager_mirror_space(struct space_manager *sm, uint64_t sid, enum window_node_split axis); void space_manager_move_window_to_space(uint64_t sid, struct window *window); -void space_manager_focus_space(uint64_t sid); +enum space_op_error space_manager_focus_space(uint64_t sid); enum space_op_error space_manager_swap_space_with_space(uint64_t acting_sid, uint64_t selector_sid); enum space_op_error space_manager_move_space_to_space(uint64_t acting_sid, uint64_t selector_sid); enum space_op_error space_manager_move_space_to_display(struct space_manager *sm, uint64_t sid, uint32_t did); enum space_op_error space_manager_destroy_space(uint64_t sid); -void space_manager_add_space(uint64_t sid); +enum space_op_error space_manager_add_space(uint64_t sid); void space_manager_assign_process_to_space(pid_t pid, uint64_t sid); void space_manager_assign_process_to_all_spaces(pid_t pid); bool space_manager_is_window_on_active_space(struct window *window);