diff options
author | Brian Ashworth <bosrsf04@gmail.com> | 2019-03-31 23:27:18 -0400 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2019-04-13 08:48:37 -0600 |
commit | 69a1a0ff99171f15c7842bfde23ed90f09a37256 (patch) | |
tree | 6d03653b20e1c5f62200d7cc6905d768fced8d52 /sway/input/seat.c | |
parent | Fix potential null accesses (diff) | |
download | sway-69a1a0ff99171f15c7842bfde23ed90f09a37256.tar.gz sway-69a1a0ff99171f15c7842bfde23ed90f09a37256.tar.zst sway-69a1a0ff99171f15c7842bfde23ed90f09a37256.zip |
Fix scratchpad fullscreen behavior and crash
When setting fullscreen on a hidden scratchpad container, there was a
check to see if there was an existing fullscreen container on the
workspace so it could be fullscreen disabled first. Since the workspace
is NULL, it would cause a SIGSEGV. This adds a NULL check to avoid the
crash.
This also changes the behavior of how fullscreen is handled when adding
a container to the scratchpad or changing visibility of a scratchpad
container to match i3's. The behavior is as follows:
- When adding a container to the scratchpad or hiding a container back
into the scratchpad, there is an implicit fullscreen disable
- When setting fullscreen on a container that is hidden in the
scratchpad, it will be fullscreen when shown (and fullscreen disabled
when hidden as stated above)
- When setting fullscreen global on a container that is hidden in the
scratchpad, it will be shown immediately as fullscreen global. The
container is not moved to a workspace and remains in the
scratchpad. The container will be visible until fullscreen disabled
or killed. Since the container is in the scratchpad, running
`scratchpad show` or `move container to scratchpad` will have no
effect
This also changes `container_replace` to transfer fullscreen and
scratchpad status.
Diffstat (limited to 'sway/input/seat.c')
-rw-r--r-- | sway/input/seat.c | 50 |
1 files changed, 43 insertions, 7 deletions
diff --git a/sway/input/seat.c b/sway/input/seat.c index bdab8b81..ce009d7e 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -172,14 +172,14 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) { | |||
172 | 172 | ||
173 | seat_node_destroy(seat_node); | 173 | seat_node_destroy(seat_node); |
174 | 174 | ||
175 | if (!parent) { | 175 | if (!parent && !needs_new_focus) { |
176 | // Destroying a container that is no longer in the tree | 176 | // Destroying a container that is no longer in the tree |
177 | return; | 177 | return; |
178 | } | 178 | } |
179 | 179 | ||
180 | // Find new focus_inactive (ie. sibling, or workspace if no siblings left) | 180 | // Find new focus_inactive (ie. sibling, or workspace if no siblings left) |
181 | struct sway_node *next_focus = NULL; | 181 | struct sway_node *next_focus = NULL; |
182 | while (next_focus == NULL) { | 182 | while (next_focus == NULL && parent != NULL) { |
183 | struct sway_container *con = | 183 | struct sway_container *con = |
184 | seat_get_focus_inactive_view(seat, parent); | 184 | seat_get_focus_inactive_view(seat, parent); |
185 | next_focus = con ? &con->node : NULL; | 185 | next_focus = con ? &con->node : NULL; |
@@ -192,6 +192,16 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) { | |||
192 | parent = node_get_parent(parent); | 192 | parent = node_get_parent(parent); |
193 | } | 193 | } |
194 | 194 | ||
195 | if (!next_focus) { | ||
196 | struct sway_workspace *ws = seat_get_last_known_workspace(seat); | ||
197 | if (!ws) { | ||
198 | return; | ||
199 | } | ||
200 | struct sway_container *con = | ||
201 | seat_get_focus_inactive_view(seat, &ws->node); | ||
202 | next_focus = con ? &(con->node) : &(ws->node); | ||
203 | } | ||
204 | |||
195 | if (next_focus->type == N_WORKSPACE && | 205 | if (next_focus->type == N_WORKSPACE && |
196 | !workspace_is_visible(next_focus->sway_workspace)) { | 206 | !workspace_is_visible(next_focus->sway_workspace)) { |
197 | // Do not change focus to a non-visible workspace | 207 | // Do not change focus to a non-visible workspace |
@@ -199,6 +209,10 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) { | |||
199 | } | 209 | } |
200 | 210 | ||
201 | if (needs_new_focus) { | 211 | if (needs_new_focus) { |
212 | // Make sure the workspace IPC event gets sent | ||
213 | if (node->type == N_CONTAINER && node->sway_container->scratchpad) { | ||
214 | seat_set_focus(seat, NULL); | ||
215 | } | ||
202 | // The structure change might have caused it to move up to the top of | 216 | // The structure change might have caused it to move up to the top of |
203 | // the focus stack without sending focus notifications to the view | 217 | // the focus stack without sending focus notifications to the view |
204 | seat_send_focus(next_focus, seat); | 218 | seat_send_focus(next_focus, seat); |
@@ -207,7 +221,7 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) { | |||
207 | // Setting focus_inactive | 221 | // Setting focus_inactive |
208 | focus = seat_get_focus_inactive(seat, &root->node); | 222 | focus = seat_get_focus_inactive(seat, &root->node); |
209 | seat_set_raw_focus(seat, next_focus); | 223 | seat_set_raw_focus(seat, next_focus); |
210 | if (focus->type == N_CONTAINER) { | 224 | if (focus->type == N_CONTAINER && focus->sway_container->workspace) { |
211 | seat_set_raw_focus(seat, &focus->sway_container->workspace->node); | 225 | seat_set_raw_focus(seat, &focus->sway_container->workspace->node); |
212 | } | 226 | } |
213 | seat_set_raw_focus(seat, focus); | 227 | seat_set_raw_focus(seat, focus); |
@@ -795,7 +809,13 @@ void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node) { | |||
795 | wl_list_remove(&seat_node->link); | 809 | wl_list_remove(&seat_node->link); |
796 | wl_list_insert(&seat->focus_stack, &seat_node->link); | 810 | wl_list_insert(&seat->focus_stack, &seat_node->link); |
797 | node_set_dirty(node); | 811 | node_set_dirty(node); |
798 | node_set_dirty(node_get_parent(node)); | 812 | |
813 | // If focusing a scratchpad container that is fullscreen global, parent | ||
814 | // will be NULL | ||
815 | struct sway_node *parent = node_get_parent(node); | ||
816 | if (parent) { | ||
817 | node_set_dirty(parent); | ||
818 | } | ||
799 | } | 819 | } |
800 | 820 | ||
801 | void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { | 821 | void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { |
@@ -850,7 +870,8 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { | |||
850 | } | 870 | } |
851 | } | 871 | } |
852 | 872 | ||
853 | struct sway_output *new_output = new_workspace->output; | 873 | struct sway_output *new_output = |
874 | new_workspace ? new_workspace->output : NULL; | ||
854 | 875 | ||
855 | if (last_workspace != new_workspace && new_output) { | 876 | if (last_workspace != new_workspace && new_output) { |
856 | node_set_dirty(&new_output->node); | 877 | node_set_dirty(&new_output->node); |
@@ -894,7 +915,8 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { | |||
894 | } | 915 | } |
895 | 916 | ||
896 | // Move sticky containers to new workspace | 917 | // Move sticky containers to new workspace |
897 | if (new_output_last_ws && new_workspace != new_output_last_ws) { | 918 | if (new_workspace && new_output_last_ws |
919 | && new_workspace != new_output_last_ws) { | ||
898 | for (int i = 0; i < new_output_last_ws->floating->length; ++i) { | 920 | for (int i = 0; i < new_output_last_ws->floating->length; ++i) { |
899 | struct sway_container *floater = | 921 | struct sway_container *floater = |
900 | new_output_last_ws->floating->items[i]; | 922 | new_output_last_ws->floating->items[i]; |
@@ -940,7 +962,7 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { | |||
940 | 962 | ||
941 | seat->has_focus = true; | 963 | seat->has_focus = true; |
942 | 964 | ||
943 | if (config->smart_gaps) { | 965 | if (config->smart_gaps && new_workspace) { |
944 | // When smart gaps is on, gaps may change when the focus changes so | 966 | // When smart gaps is on, gaps may change when the focus changes so |
945 | // the workspace needs to be arranged | 967 | // the workspace needs to be arranged |
946 | arrange_workspace(new_workspace); | 968 | arrange_workspace(new_workspace); |
@@ -1134,6 +1156,20 @@ struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat) { | |||
1134 | return NULL; // output doesn't have a workspace yet | 1156 | return NULL; // output doesn't have a workspace yet |
1135 | } | 1157 | } |
1136 | 1158 | ||
1159 | struct sway_workspace *seat_get_last_known_workspace(struct sway_seat *seat) { | ||
1160 | struct sway_seat_node *current; | ||
1161 | wl_list_for_each(current, &seat->focus_stack, link) { | ||
1162 | struct sway_node *node = current->node; | ||
1163 | if (node->type == N_CONTAINER && | ||
1164 | node->sway_container->workspace) { | ||
1165 | return node->sway_container->workspace; | ||
1166 | } else if (node->type == N_WORKSPACE) { | ||
1167 | return node->sway_workspace; | ||
1168 | } | ||
1169 | } | ||
1170 | return NULL; | ||
1171 | } | ||
1172 | |||
1137 | struct sway_container *seat_get_focused_container(struct sway_seat *seat) { | 1173 | struct sway_container *seat_get_focused_container(struct sway_seat *seat) { |
1138 | struct sway_node *focus = seat_get_focus(seat); | 1174 | struct sway_node *focus = seat_get_focus(seat); |
1139 | if (focus && focus->type == N_CONTAINER) { | 1175 | if (focus && focus->type == N_CONTAINER) { |