aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar emersion <contact@emersion.fr>2018-07-22 19:25:41 +0100
committerLibravatar GitHub <noreply@github.com>2018-07-22 19:25:41 +0100
commitbe60e44b7c08b87400fed0b9ea586c449883ba11 (patch)
tree5005c92ed70e19fcd9a316b9a9fad0d3ba07b6ad
parentMerge pull request #2320 from RedSoxFan/reset-outputs-on-reload (diff)
parentSet cursor when beginning resize and move operations (diff)
downloadsway-be60e44b7c08b87400fed0b9ea586c449883ba11.tar.gz
sway-be60e44b7c08b87400fed0b9ea586c449883ba11.tar.zst
sway-be60e44b7c08b87400fed0b9ea586c449883ba11.zip
Merge pull request #2296 from RyanDwyer/floating-modifier
Implement floating_modifier and mouse operations for floating views
-rw-r--r--include/sway/commands.h2
-rw-r--r--include/sway/input/cursor.h4
-rw-r--r--include/sway/input/seat.h30
-rw-r--r--include/sway/tree/container.h12
-rw-r--r--include/sway/tree/layout.h9
-rw-r--r--include/sway/tree/view.h5
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/floating_modifier.c20
-rw-r--r--sway/desktop/output.c9
-rw-r--r--sway/desktop/transaction.c14
-rw-r--r--sway/desktop/xdg_shell.c50
-rw-r--r--sway/desktop/xdg_shell_v6.c50
-rw-r--r--sway/desktop/xwayland.c41
-rw-r--r--sway/input/cursor.c275
-rw-r--r--sway/input/seat.c71
-rw-r--r--sway/meson.build1
-rw-r--r--sway/tree/container.c15
-rw-r--r--sway/tree/layout.c1
-rw-r--r--sway/tree/view.c15
19 files changed, 592 insertions, 33 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index e71a7228..f53d335a 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -106,7 +106,7 @@ sway_cmd cmd_exit;
106sway_cmd cmd_floating; 106sway_cmd cmd_floating;
107sway_cmd cmd_floating_maximum_size; 107sway_cmd cmd_floating_maximum_size;
108sway_cmd cmd_floating_minimum_size; 108sway_cmd cmd_floating_minimum_size;
109sway_cmd cmd_floating_mod; 109sway_cmd cmd_floating_modifier;
110sway_cmd cmd_floating_scroll; 110sway_cmd cmd_floating_scroll;
111sway_cmd cmd_focus; 111sway_cmd cmd_focus;
112sway_cmd cmd_focus_follows_mouse; 112sway_cmd cmd_focus_follows_mouse;
diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h
index 5dd109ca..b0a3a7c5 100644
--- a/include/sway/input/cursor.h
+++ b/include/sway/input/cursor.h
@@ -11,6 +11,7 @@ struct sway_cursor {
11 } previous; 11 } previous;
12 struct wlr_xcursor_manager *xcursor_manager; 12 struct wlr_xcursor_manager *xcursor_manager;
13 13
14 const char *image;
14 struct wl_client *image_client; 15 struct wl_client *image_client;
15 16
16 struct wl_listener motion; 17 struct wl_listener motion;
@@ -37,4 +38,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
37void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec, 38void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec,
38 uint32_t button, enum wlr_button_state state); 39 uint32_t button, enum wlr_button_state state);
39 40
41void cursor_set_image(struct sway_cursor *cursor, const char *image,
42 struct wl_client *client);
43
40#endif 44#endif
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index eac1626b..ab25788f 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -3,6 +3,7 @@
3 3
4#include <wlr/types/wlr_layer_shell.h> 4#include <wlr/types/wlr_layer_shell.h>
5#include <wlr/types/wlr_seat.h> 5#include <wlr/types/wlr_seat.h>
6#include <wlr/util/edges.h>
6#include "sway/input/input-manager.h" 7#include "sway/input/input-manager.h"
7 8
8struct sway_seat_device { 9struct sway_seat_device {
@@ -52,6 +53,24 @@ struct sway_seat {
52 int32_t touch_id; 53 int32_t touch_id;
53 double touch_x, touch_y; 54 double touch_x, touch_y;
54 55
56 // Operations (drag and resize)
57 enum {
58 OP_NONE,
59 OP_MOVE,
60 OP_RESIZE,
61 } operation;
62
63 struct sway_container *op_container;
64 enum wlr_edges op_resize_edge;
65 uint32_t op_button;
66 bool op_resize_preserve_ratio;
67 double op_ref_lx, op_ref_ly; // cursor's x/y at start of op
68 double op_ref_width, op_ref_height; // container's size at start of op
69 double op_ref_con_lx, op_ref_con_ly; // container's x/y at start of op
70
71 uint32_t last_button;
72 uint32_t last_button_serial;
73
55 struct wl_listener focus_destroy; 74 struct wl_listener focus_destroy;
56 struct wl_listener new_container; 75 struct wl_listener new_container;
57 struct wl_listener new_drag_icon; 76 struct wl_listener new_drag_icon;
@@ -134,4 +153,15 @@ bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface);
134 153
135void drag_icon_update_position(struct sway_drag_icon *icon); 154void drag_icon_update_position(struct sway_drag_icon *icon);
136 155
156void seat_begin_move(struct sway_seat *seat, struct sway_container *con,
157 uint32_t button);
158
159void seat_begin_resize(struct sway_seat *seat, struct sway_container *con,
160 uint32_t button, enum wlr_edges edge);
161
162void seat_end_mouse_operation(struct sway_seat *seat);
163
164void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,
165 uint32_t button, enum wlr_button_state state);
166
137#endif 167#endif
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index ca7a3288..59c5b4c7 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -305,6 +305,12 @@ bool container_is_floating(struct sway_container *container);
305void container_get_box(struct sway_container *container, struct wlr_box *box); 305void container_get_box(struct sway_container *container, struct wlr_box *box);
306 306
307/** 307/**
308 * Move a floating container by the specified amount.
309 */
310void container_floating_translate(struct sway_container *con,
311 double x_amount, double y_amount);
312
313/**
308 * Move a floating container to a new layout-local position. 314 * Move a floating container to a new layout-local position.
309 */ 315 */
310void container_floating_move_to(struct sway_container *con, 316void container_floating_move_to(struct sway_container *con,
@@ -318,4 +324,10 @@ void container_set_dirty(struct sway_container *container);
318 324
319bool container_has_urgent_child(struct sway_container *container); 325bool container_has_urgent_child(struct sway_container *container);
320 326
327/**
328 * If the container is involved in a drag or resize operation via a mouse, this
329 * ends the operation.
330 */
331void container_end_mouse_operation(struct sway_container *container);
332
321#endif 333#endif
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h
index ba265623..5a78fd58 100644
--- a/include/sway/tree/layout.h
+++ b/include/sway/tree/layout.h
@@ -14,10 +14,11 @@ enum movement_direction {
14}; 14};
15 15
16enum resize_edge { 16enum resize_edge {
17 RESIZE_EDGE_LEFT, 17 RESIZE_EDGE_NONE = 0,
18 RESIZE_EDGE_RIGHT, 18 RESIZE_EDGE_LEFT = 1,
19 RESIZE_EDGE_TOP, 19 RESIZE_EDGE_RIGHT = 2,
20 RESIZE_EDGE_BOTTOM, 20 RESIZE_EDGE_TOP = 4,
21 RESIZE_EDGE_BOTTOM = 8,
21}; 22};
22 23
23struct sway_container; 24struct sway_container;
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 068d92c6..1dfb218b 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -26,6 +26,8 @@ enum sway_view_prop {
26}; 26};
27 27
28struct sway_view_impl { 28struct sway_view_impl {
29 void (*get_constraints)(struct sway_view *view, double *min_width,
30 double *max_width, double *min_height, double *max_height);
29 const char *(*get_string_prop)(struct sway_view *view, 31 const char *(*get_string_prop)(struct sway_view *view,
30 enum sway_view_prop prop); 32 enum sway_view_prop prop);
31 uint32_t (*get_int_prop)(struct sway_view *view, enum sway_view_prop prop); 33 uint32_t (*get_int_prop)(struct sway_view *view, enum sway_view_prop prop);
@@ -215,6 +217,9 @@ uint32_t view_get_window_type(struct sway_view *view);
215 217
216const char *view_get_shell(struct sway_view *view); 218const char *view_get_shell(struct sway_view *view);
217 219
220void view_get_constraints(struct sway_view *view, double *min_width,
221 double *max_width, double *min_height, double *max_height);
222
218uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, 223uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
219 int height); 224 int height);
220 225
diff --git a/sway/commands.c b/sway/commands.c
index f1f03574..f40f0e9d 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -103,6 +103,7 @@ static struct cmd_handler handlers[] = {
103 { "exec_always", cmd_exec_always }, 103 { "exec_always", cmd_exec_always },
104 { "floating_maximum_size", cmd_floating_maximum_size }, 104 { "floating_maximum_size", cmd_floating_maximum_size },
105 { "floating_minimum_size", cmd_floating_minimum_size }, 105 { "floating_minimum_size", cmd_floating_minimum_size },
106 { "floating_modifier", cmd_floating_modifier },
106 { "focus", cmd_focus }, 107 { "focus", cmd_focus },
107 { "focus_follows_mouse", cmd_focus_follows_mouse }, 108 { "focus_follows_mouse", cmd_focus_follows_mouse },
108 { "focus_wrapping", cmd_focus_wrapping }, 109 { "focus_wrapping", cmd_focus_wrapping },
diff --git a/sway/commands/floating_modifier.c b/sway/commands/floating_modifier.c
new file mode 100644
index 00000000..9432c9f1
--- /dev/null
+++ b/sway/commands/floating_modifier.c
@@ -0,0 +1,20 @@
1#include "sway/commands.h"
2#include "sway/config.h"
3#include "util.h"
4
5struct cmd_results *cmd_floating_modifier(int argc, char **argv) {
6 struct cmd_results *error = NULL;
7 if ((error = checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1))) {
8 return error;
9 }
10
11 uint32_t mod = get_modifier_mask_by_name(argv[0]);
12 if (!mod) {
13 return cmd_results_new(CMD_INVALID, "floating_modifier",
14 "Invalid modifier");
15 }
16
17 config->floating_mod = mod;
18
19 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
20}
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index a9808406..a206ac6b 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -463,11 +463,12 @@ static void output_damage_whole_container_iterator(struct sway_container *con,
463 463
464void output_damage_whole_container(struct sway_output *output, 464void output_damage_whole_container(struct sway_output *output,
465 struct sway_container *con) { 465 struct sway_container *con) {
466 // Pad the box by 1px, because the width is a double and might be a fraction
466 struct wlr_box box = { 467 struct wlr_box box = {
467 .x = con->current.swayc_x - output->wlr_output->lx, 468 .x = con->current.swayc_x - output->wlr_output->lx - 1,
468 .y = con->current.swayc_y - output->wlr_output->ly, 469 .y = con->current.swayc_y - output->wlr_output->ly - 1,
469 .width = con->current.swayc_width, 470 .width = con->current.swayc_width + 2,
470 .height = con->current.swayc_height, 471 .height = con->current.swayc_height + 2,
471 }; 472 };
472 scale_box(&box, output->wlr_output->scale); 473 scale_box(&box, output->wlr_output->scale);
473 wlr_output_damage_add_box(output->damage, &box); 474 wlr_output_damage_add_box(output->damage, &box);
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index 19f41efc..2a89880a 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -222,24 +222,16 @@ static void transaction_apply(struct sway_transaction *transaction) {
222 } 222 }
223} 223}
224 224
225/**
226 * For simplicity, we only progress the queue if it can be completely flushed.
227 */
228static void transaction_progress_queue() { 225static void transaction_progress_queue() {
229 // We iterate this list in reverse because we're more likely to find a 226 while (server.transactions->length) {
230 // waiting transactions at the end of the list. 227 struct sway_transaction *transaction = server.transactions->items[0];
231 for (int i = server.transactions->length - 1; i >= 0; --i) {
232 struct sway_transaction *transaction = server.transactions->items[i];
233 if (transaction->num_waiting) { 228 if (transaction->num_waiting) {
234 return; 229 return;
235 } 230 }
236 }
237 for (int i = 0; i < server.transactions->length; ++i) {
238 struct sway_transaction *transaction = server.transactions->items[i];
239 transaction_apply(transaction); 231 transaction_apply(transaction);
240 transaction_destroy(transaction); 232 transaction_destroy(transaction);
233 list_del(server.transactions, 0);
241 } 234 }
242 server.transactions->length = 0;
243 idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); 235 idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
244} 236}
245 237
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index 98c16faf..706b35c3 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -1,4 +1,5 @@
1#define _POSIX_C_SOURCE 199309L 1#define _POSIX_C_SOURCE 199309L
2#include <float.h>
2#include <stdbool.h> 3#include <stdbool.h>
3#include <stdlib.h> 4#include <stdlib.h>
4#include <wayland-server.h> 5#include <wayland-server.h>
@@ -95,6 +96,16 @@ static struct sway_xdg_shell_view *xdg_shell_view_from_view(
95 return (struct sway_xdg_shell_view *)view; 96 return (struct sway_xdg_shell_view *)view;
96} 97}
97 98
99static void get_constraints(struct sway_view *view, double *min_width,
100 double *max_width, double *min_height, double *max_height) {
101 struct wlr_xdg_toplevel_state *state =
102 &view->wlr_xdg_surface->toplevel->current;
103 *min_width = state->min_width > 0 ? state->min_width : DBL_MIN;
104 *max_width = state->max_width > 0 ? state->max_width : DBL_MAX;
105 *min_height = state->min_height > 0 ? state->min_height : DBL_MIN;
106 *max_height = state->max_height > 0 ? state->max_height : DBL_MAX;
107}
108
98static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) { 109static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) {
99 if (xdg_shell_view_from_view(view) == NULL) { 110 if (xdg_shell_view_from_view(view) == NULL) {
100 return NULL; 111 return NULL;
@@ -188,6 +199,7 @@ static void destroy(struct sway_view *view) {
188} 199}
189 200
190static const struct sway_view_impl view_impl = { 201static const struct sway_view_impl view_impl = {
202 .get_constraints = get_constraints,
191 .get_string_prop = get_string_prop, 203 .get_string_prop = get_string_prop,
192 .configure = configure, 204 .configure = configure,
193 .set_activated = set_activated, 205 .set_activated = set_activated,
@@ -248,6 +260,34 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
248 transaction_commit_dirty(); 260 transaction_commit_dirty();
249} 261}
250 262
263static void handle_request_move(struct wl_listener *listener, void *data) {
264 struct sway_xdg_shell_view *xdg_shell_view =
265 wl_container_of(listener, xdg_shell_view, request_move);
266 struct sway_view *view = &xdg_shell_view->view;
267 if (!container_is_floating(view->swayc)) {
268 return;
269 }
270 struct wlr_xdg_toplevel_move_event *e = data;
271 struct sway_seat *seat = e->seat->seat->data;
272 if (e->serial == seat->last_button_serial) {
273 seat_begin_move(seat, view->swayc, seat->last_button);
274 }
275}
276
277static void handle_request_resize(struct wl_listener *listener, void *data) {
278 struct sway_xdg_shell_view *xdg_shell_view =
279 wl_container_of(listener, xdg_shell_view, request_resize);
280 struct sway_view *view = &xdg_shell_view->view;
281 if (!container_is_floating(view->swayc)) {
282 return;
283 }
284 struct wlr_xdg_toplevel_resize_event *e = data;
285 struct sway_seat *seat = e->seat->seat->data;
286 if (e->serial == seat->last_button_serial) {
287 seat_begin_resize(seat, view->swayc, seat->last_button, e->edges);
288 }
289}
290
251static void handle_unmap(struct wl_listener *listener, void *data) { 291static void handle_unmap(struct wl_listener *listener, void *data) {
252 struct sway_xdg_shell_view *xdg_shell_view = 292 struct sway_xdg_shell_view *xdg_shell_view =
253 wl_container_of(listener, xdg_shell_view, unmap); 293 wl_container_of(listener, xdg_shell_view, unmap);
@@ -262,6 +302,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
262 wl_list_remove(&xdg_shell_view->commit.link); 302 wl_list_remove(&xdg_shell_view->commit.link);
263 wl_list_remove(&xdg_shell_view->new_popup.link); 303 wl_list_remove(&xdg_shell_view->new_popup.link);
264 wl_list_remove(&xdg_shell_view->request_fullscreen.link); 304 wl_list_remove(&xdg_shell_view->request_fullscreen.link);
305 wl_list_remove(&xdg_shell_view->request_move.link);
306 wl_list_remove(&xdg_shell_view->request_resize.link);
265} 307}
266 308
267static void handle_map(struct wl_listener *listener, void *data) { 309static void handle_map(struct wl_listener *listener, void *data) {
@@ -299,6 +341,14 @@ static void handle_map(struct wl_listener *listener, void *data) {
299 xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen; 341 xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen;
300 wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, 342 wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
301 &xdg_shell_view->request_fullscreen); 343 &xdg_shell_view->request_fullscreen);
344
345 xdg_shell_view->request_move.notify = handle_request_move;
346 wl_signal_add(&xdg_surface->toplevel->events.request_move,
347 &xdg_shell_view->request_move);
348
349 xdg_shell_view->request_resize.notify = handle_request_resize;
350 wl_signal_add(&xdg_surface->toplevel->events.request_resize,
351 &xdg_shell_view->request_resize);
302} 352}
303 353
304static void handle_destroy(struct wl_listener *listener, void *data) { 354static void handle_destroy(struct wl_listener *listener, void *data) {
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 4d76f0a7..201b5b1e 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -1,4 +1,5 @@
1#define _POSIX_C_SOURCE 199309L 1#define _POSIX_C_SOURCE 199309L
2#include <float.h>
2#include <stdbool.h> 3#include <stdbool.h>
3#include <stdlib.h> 4#include <stdlib.h>
4#include <wayland-server.h> 5#include <wayland-server.h>
@@ -94,6 +95,16 @@ static struct sway_xdg_shell_v6_view *xdg_shell_v6_view_from_view(
94 return (struct sway_xdg_shell_v6_view *)view; 95 return (struct sway_xdg_shell_v6_view *)view;
95} 96}
96 97
98static void get_constraints(struct sway_view *view, double *min_width,
99 double *max_width, double *min_height, double *max_height) {
100 struct wlr_xdg_toplevel_v6_state *state =
101 &view->wlr_xdg_surface_v6->toplevel->current;
102 *min_width = state->min_width > 0 ? state->min_width : DBL_MIN;
103 *max_width = state->max_width > 0 ? state->max_width : DBL_MAX;
104 *min_height = state->min_height > 0 ? state->min_height : DBL_MIN;
105 *max_height = state->max_height > 0 ? state->max_height : DBL_MAX;
106}
107
97static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) { 108static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) {
98 if (xdg_shell_v6_view_from_view(view) == NULL) { 109 if (xdg_shell_v6_view_from_view(view) == NULL) {
99 return NULL; 110 return NULL;
@@ -184,6 +195,7 @@ static void destroy(struct sway_view *view) {
184} 195}
185 196
186static const struct sway_view_impl view_impl = { 197static const struct sway_view_impl view_impl = {
198 .get_constraints = get_constraints,
187 .get_string_prop = get_string_prop, 199 .get_string_prop = get_string_prop,
188 .configure = configure, 200 .configure = configure,
189 .set_activated = set_activated, 201 .set_activated = set_activated,
@@ -243,6 +255,34 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
243 transaction_commit_dirty(); 255 transaction_commit_dirty();
244} 256}
245 257
258static void handle_request_move(struct wl_listener *listener, void *data) {
259 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
260 wl_container_of(listener, xdg_shell_v6_view, request_move);
261 struct sway_view *view = &xdg_shell_v6_view->view;
262 if (!container_is_floating(view->swayc)) {
263 return;
264 }
265 struct wlr_xdg_toplevel_v6_move_event *e = data;
266 struct sway_seat *seat = e->seat->seat->data;
267 if (e->serial == seat->last_button_serial) {
268 seat_begin_move(seat, view->swayc, seat->last_button);
269 }
270}
271
272static void handle_request_resize(struct wl_listener *listener, void *data) {
273 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
274 wl_container_of(listener, xdg_shell_v6_view, request_resize);
275 struct sway_view *view = &xdg_shell_v6_view->view;
276 if (!container_is_floating(view->swayc)) {
277 return;
278 }
279 struct wlr_xdg_toplevel_v6_resize_event *e = data;
280 struct sway_seat *seat = e->seat->seat->data;
281 if (e->serial == seat->last_button_serial) {
282 seat_begin_resize(seat, view->swayc, seat->last_button, e->edges);
283 }
284}
285
246static void handle_unmap(struct wl_listener *listener, void *data) { 286static void handle_unmap(struct wl_listener *listener, void *data) {
247 struct sway_xdg_shell_v6_view *xdg_shell_v6_view = 287 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
248 wl_container_of(listener, xdg_shell_v6_view, unmap); 288 wl_container_of(listener, xdg_shell_v6_view, unmap);
@@ -257,6 +297,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
257 wl_list_remove(&xdg_shell_v6_view->commit.link); 297 wl_list_remove(&xdg_shell_v6_view->commit.link);
258 wl_list_remove(&xdg_shell_v6_view->new_popup.link); 298 wl_list_remove(&xdg_shell_v6_view->new_popup.link);
259 wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link); 299 wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link);
300 wl_list_remove(&xdg_shell_v6_view->request_move.link);
301 wl_list_remove(&xdg_shell_v6_view->request_resize.link);
260} 302}
261 303
262static void handle_map(struct wl_listener *listener, void *data) { 304static void handle_map(struct wl_listener *listener, void *data) {
@@ -294,6 +336,14 @@ static void handle_map(struct wl_listener *listener, void *data) {
294 xdg_shell_v6_view->request_fullscreen.notify = handle_request_fullscreen; 336 xdg_shell_v6_view->request_fullscreen.notify = handle_request_fullscreen;
295 wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, 337 wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
296 &xdg_shell_v6_view->request_fullscreen); 338 &xdg_shell_v6_view->request_fullscreen);
339
340 xdg_shell_v6_view->request_move.notify = handle_request_move;
341 wl_signal_add(&xdg_surface->toplevel->events.request_move,
342 &xdg_shell_v6_view->request_move);
343
344 xdg_shell_v6_view->request_resize.notify = handle_request_resize;
345 wl_signal_add(&xdg_surface->toplevel->events.request_resize,
346 &xdg_shell_v6_view->request_resize);
297} 347}
298 348
299static void handle_destroy(struct wl_listener *listener, void *data) { 349static void handle_destroy(struct wl_listener *listener, void *data) {
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index bce0a37b..2546168b 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -305,6 +305,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
305 wl_list_remove(&xwayland_view->destroy.link); 305 wl_list_remove(&xwayland_view->destroy.link);
306 wl_list_remove(&xwayland_view->request_configure.link); 306 wl_list_remove(&xwayland_view->request_configure.link);
307 wl_list_remove(&xwayland_view->request_fullscreen.link); 307 wl_list_remove(&xwayland_view->request_fullscreen.link);
308 wl_list_remove(&xwayland_view->request_move.link);
309 wl_list_remove(&xwayland_view->request_resize.link);
308 wl_list_remove(&xwayland_view->set_title.link); 310 wl_list_remove(&xwayland_view->set_title.link);
309 wl_list_remove(&xwayland_view->set_class.link); 311 wl_list_remove(&xwayland_view->set_class.link);
310 wl_list_remove(&xwayland_view->set_window_type.link); 312 wl_list_remove(&xwayland_view->set_window_type.link);
@@ -400,6 +402,37 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
400 transaction_commit_dirty(); 402 transaction_commit_dirty();
401} 403}
402 404
405static void handle_request_move(struct wl_listener *listener, void *data) {
406 struct sway_xwayland_view *xwayland_view =
407 wl_container_of(listener, xwayland_view, request_move);
408 struct sway_view *view = &xwayland_view->view;
409 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
410 if (!xsurface->mapped) {
411 return;
412 }
413 if (!container_is_floating(view->swayc)) {
414 return;
415 }
416 struct sway_seat *seat = input_manager_current_seat(input_manager);
417 seat_begin_move(seat, view->swayc, seat->last_button);
418}
419
420static void handle_request_resize(struct wl_listener *listener, void *data) {
421 struct sway_xwayland_view *xwayland_view =
422 wl_container_of(listener, xwayland_view, request_resize);
423 struct sway_view *view = &xwayland_view->view;
424 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
425 if (!xsurface->mapped) {
426 return;
427 }
428 if (!container_is_floating(view->swayc)) {
429 return;
430 }
431 struct wlr_xwayland_resize_event *e = data;
432 struct sway_seat *seat = input_manager_current_seat(input_manager);
433 seat_begin_resize(seat, view->swayc, seat->last_button, e->edges);
434}
435
403static void handle_set_title(struct wl_listener *listener, void *data) { 436static void handle_set_title(struct wl_listener *listener, void *data) {
404 struct sway_xwayland_view *xwayland_view = 437 struct sway_xwayland_view *xwayland_view =
405 wl_container_of(listener, xwayland_view, set_title); 438 wl_container_of(listener, xwayland_view, set_title);
@@ -495,6 +528,14 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
495 &xwayland_view->request_fullscreen); 528 &xwayland_view->request_fullscreen);
496 xwayland_view->request_fullscreen.notify = handle_request_fullscreen; 529 xwayland_view->request_fullscreen.notify = handle_request_fullscreen;
497 530
531 wl_signal_add(&xsurface->events.request_move,
532 &xwayland_view->request_move);
533 xwayland_view->request_move.notify = handle_request_move;
534
535 wl_signal_add(&xsurface->events.request_resize,
536 &xwayland_view->request_resize);
537 xwayland_view->request_resize.notify = handle_request_resize;
538
498 wl_signal_add(&xsurface->events.set_title, &xwayland_view->set_title); 539 wl_signal_add(&xsurface->events.set_title, &xwayland_view->set_title);
499 xwayland_view->set_title.notify = handle_set_title; 540 xwayland_view->set_title.notify = handle_set_title;
500 541
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index c76c20b3..771ad01d 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -5,15 +5,19 @@
5#elif __FreeBSD__ 5#elif __FreeBSD__
6#include <dev/evdev/input-event-codes.h> 6#include <dev/evdev/input-event-codes.h>
7#endif 7#endif
8#include <limits.h>
8#include <wlr/types/wlr_cursor.h> 9#include <wlr/types/wlr_cursor.h>
9#include <wlr/types/wlr_xcursor_manager.h> 10#include <wlr/types/wlr_xcursor_manager.h>
10#include <wlr/types/wlr_idle.h> 11#include <wlr/types/wlr_idle.h>
11#include "list.h" 12#include "list.h"
12#include "log.h" 13#include "log.h"
14#include "sway/desktop.h"
13#include "sway/desktop/transaction.h" 15#include "sway/desktop/transaction.h"
14#include "sway/input/cursor.h" 16#include "sway/input/cursor.h"
17#include "sway/input/keyboard.h"
15#include "sway/layers.h" 18#include "sway/layers.h"
16#include "sway/output.h" 19#include "sway/output.h"
20#include "sway/tree/arrange.h"
17#include "sway/tree/view.h" 21#include "sway/tree/view.h"
18#include "sway/tree/workspace.h" 22#include "sway/tree/workspace.h"
19#include "wlr-layer-shell-unstable-v1-protocol.h" 23#include "wlr-layer-shell-unstable-v1-protocol.h"
@@ -127,7 +131,7 @@ static struct sway_container *container_at_coords(
127 return ws; 131 return ws;
128 } 132 }
129 133
130 c = seat_get_focus_inactive(seat, output->swayc); 134 c = seat_get_active_child(seat, output->swayc);
131 if (c) { 135 if (c) {
132 return c; 136 return c;
133 } 137 }
@@ -139,6 +143,171 @@ static struct sway_container *container_at_coords(
139 return output->swayc; 143 return output->swayc;
140} 144}
141 145
146static enum wlr_edges find_resize_edge(struct sway_container *cont,
147 struct sway_cursor *cursor) {
148 if (cont->type != C_VIEW) {
149 return WLR_EDGE_NONE;
150 }
151 struct sway_view *view = cont->sway_view;
152 if (view->border == B_NONE || !view->border_thickness || view->using_csd) {
153 return WLR_EDGE_NONE;
154 }
155
156 enum wlr_edges edge = 0;
157 if (cursor->cursor->x < cont->x + view->border_thickness) {
158 edge |= WLR_EDGE_LEFT;
159 }
160 if (cursor->cursor->y < cont->y + view->border_thickness) {
161 edge |= WLR_EDGE_TOP;
162 }
163 if (cursor->cursor->x >= cont->x + cont->width - view->border_thickness) {
164 edge |= WLR_EDGE_RIGHT;
165 }
166 if (cursor->cursor->y >= cont->y + cont->height - view->border_thickness) {
167 edge |= WLR_EDGE_BOTTOM;
168 }
169 return edge;
170}
171
172static void handle_move_motion(struct sway_seat *seat,
173 struct sway_cursor *cursor) {
174 struct sway_container *con = seat->op_container;
175 desktop_damage_whole_container(con);
176 container_floating_translate(con,
177 cursor->cursor->x - cursor->previous.x,
178 cursor->cursor->y - cursor->previous.y);
179 desktop_damage_whole_container(con);
180}
181
182static void calculate_floating_constraints(struct sway_container *con,
183 int *min_width, int *max_width, int *min_height, int *max_height) {
184 if (config->floating_minimum_width == -1) { // no minimum
185 *min_width = 0;
186 } else if (config->floating_minimum_width == 0) { // automatic
187 *min_width = 75;
188 } else {
189 *min_width = config->floating_minimum_width;
190 }
191
192 if (config->floating_minimum_height == -1) { // no minimum
193 *min_height = 0;
194 } else if (config->floating_minimum_height == 0) { // automatic
195 *min_height = 50;
196 } else {
197 *min_height = config->floating_minimum_height;
198 }
199
200 if (config->floating_maximum_width == -1) { // no maximum
201 *max_width = INT_MAX;
202 } else if (config->floating_maximum_width == 0) { // automatic
203 struct sway_container *ws = container_parent(con, C_WORKSPACE);
204 *max_width = ws->width;
205 } else {
206 *max_width = config->floating_maximum_width;
207 }
208
209 if (config->floating_maximum_height == -1) { // no maximum
210 *max_height = INT_MAX;
211 } else if (config->floating_maximum_height == 0) { // automatic
212 struct sway_container *ws = container_parent(con, C_WORKSPACE);
213 *max_height = ws->height;
214 } else {
215 *max_height = config->floating_maximum_height;
216 }
217}
218
219static void handle_resize_motion(struct sway_seat *seat,
220 struct sway_cursor *cursor) {
221 struct sway_container *con = seat->op_container;
222 enum wlr_edges edge = seat->op_resize_edge;
223
224 // The amount the mouse has moved since the start of the resize operation
225 // Positive is down/right
226 double mouse_move_x = cursor->cursor->x - seat->op_ref_lx;
227 double mouse_move_y = cursor->cursor->y - seat->op_ref_ly;
228
229 if (edge == WLR_EDGE_TOP || edge == WLR_EDGE_BOTTOM) {
230 mouse_move_x = 0;
231 }
232 if (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT) {
233 mouse_move_y = 0;
234 }
235
236 double grow_width = edge & WLR_EDGE_LEFT ? -mouse_move_x : mouse_move_x;
237 double grow_height = edge & WLR_EDGE_TOP ? -mouse_move_y : mouse_move_y;
238
239 if (seat->op_resize_preserve_ratio) {
240 double x_multiplier = grow_width / seat->op_ref_width;
241 double y_multiplier = grow_height / seat->op_ref_height;
242 double max_multiplier = fmax(x_multiplier, y_multiplier);
243 grow_width = seat->op_ref_width * max_multiplier;
244 grow_height = seat->op_ref_height * max_multiplier;
245 }
246
247 // Determine new width/height, and accommodate for floating min/max values
248 double width = seat->op_ref_width + grow_width;
249 double height = seat->op_ref_height + grow_height;
250 int min_width, max_width, min_height, max_height;
251 calculate_floating_constraints(con, &min_width, &max_width,
252 &min_height, &max_height);
253 width = fmax(min_width, fmin(width, max_width));
254 height = fmax(min_height, fmin(height, max_height));
255
256 // Apply the view's min/max size
257 if (con->type == C_VIEW) {
258 double view_min_width, view_max_width, view_min_height, view_max_height;
259 view_get_constraints(con->sway_view, &view_min_width, &view_max_width,
260 &view_min_height, &view_max_height);
261 width = fmax(view_min_width, fmin(width, view_max_width));
262 height = fmax(view_min_height, fmin(height, view_max_height));
263 }
264
265 // Recalculate these, in case we hit a min/max limit
266 grow_width = width - seat->op_ref_width;
267 grow_height = height - seat->op_ref_height;
268
269 // Determine grow x/y values - these are relative to the container's x/y at
270 // the start of the resize operation.
271 double grow_x = 0, grow_y = 0;
272 if (edge & WLR_EDGE_LEFT) {
273 grow_x = -grow_width;
274 } else if (edge & WLR_EDGE_RIGHT) {
275 grow_x = 0;
276 } else {
277 grow_x = -grow_width / 2;
278 }
279 if (edge & WLR_EDGE_TOP) {
280 grow_y = -grow_height;
281 } else if (edge & WLR_EDGE_BOTTOM) {
282 grow_y = 0;
283 } else {
284 grow_y = -grow_height / 2;
285 }
286
287 // Determine the amounts we need to bump everything relative to the current
288 // size.
289 int relative_grow_width = width - con->width;
290 int relative_grow_height = height - con->height;
291 int relative_grow_x = (seat->op_ref_con_lx + grow_x) - con->x;
292 int relative_grow_y = (seat->op_ref_con_ly + grow_y) - con->y;
293
294 // Actually resize stuff
295 con->x += relative_grow_x;
296 con->y += relative_grow_y;
297 con->width += relative_grow_width;
298 con->height += relative_grow_height;
299
300 if (con->type == C_VIEW) {
301 struct sway_view *view = con->sway_view;
302 view->x += relative_grow_x;
303 view->y += relative_grow_y;
304 view->width += relative_grow_width;
305 view->height += relative_grow_height;
306 }
307
308 arrange_windows(con);
309}
310
142void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, 311void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
143 bool allow_refocusing) { 312 bool allow_refocusing) {
144 if (time_msec == 0) { 313 if (time_msec == 0) {
@@ -146,6 +315,18 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
146 } 315 }
147 316
148 struct sway_seat *seat = cursor->seat; 317 struct sway_seat *seat = cursor->seat;
318
319 if (seat->operation != OP_NONE) {
320 if (seat->operation == OP_MOVE) {
321 handle_move_motion(seat, cursor);
322 } else {
323 handle_resize_motion(seat, cursor);
324 }
325 cursor->previous.x = cursor->cursor->x;
326 cursor->previous.y = cursor->cursor->y;
327 return;
328 }
329
149 struct wlr_seat *wlr_seat = seat->wlr_seat; 330 struct wlr_seat *wlr_seat = seat->wlr_seat;
150 struct wlr_surface *surface = NULL; 331 struct wlr_surface *surface = NULL;
151 double sx, sy; 332 double sx, sy;
@@ -194,15 +375,21 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
194 } 375 }
195 } 376 }
196 377
197 // reset cursor if switching between clients 378 // Handle cursor image
198 struct wl_client *client = NULL; 379 if (surface) {
199 if (surface != NULL) { 380 // Reset cursor if switching between clients
200 client = wl_resource_get_client(surface->resource); 381 struct wl_client *client = wl_resource_get_client(surface->resource);
201 } 382 if (client != cursor->image_client) {
202 if (client != cursor->image_client) { 383 cursor_set_image(cursor, "left_ptr", client);
203 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, 384 }
204 "left_ptr", cursor->cursor); 385 } else if (c && container_is_floating(c)) {
205 cursor->image_client = client; 386 // Try a floating container's resize edge
387 enum wlr_edges edge = find_resize_edge(c, cursor);
388 const char *image = edge == WLR_EDGE_NONE ?
389 "left_ptr" : wlr_xcursor_get_resize_name(edge);
390 cursor_set_image(cursor, image, NULL);
391 } else {
392 cursor_set_image(cursor, "left_ptr", NULL);
206 } 393 }
207 394
208 // send pointer enter/leave 395 // send pointer enter/leave
@@ -243,8 +430,53 @@ static void handle_cursor_motion_absolute(
243 transaction_commit_dirty(); 430 transaction_commit_dirty();
244} 431}
245 432
433static void dispatch_cursor_button_floating(struct sway_cursor *cursor,
434 uint32_t time_msec, uint32_t button, enum wlr_button_state state,
435 struct wlr_surface *surface, double sx, double sy,
436 struct sway_container *cont) {
437 struct sway_seat *seat = cursor->seat;
438
439 // Deny moving or resizing a fullscreen view
440 if (cont->type == C_VIEW && cont->sway_view->is_fullscreen) {
441 seat_pointer_notify_button(seat, time_msec, button, state);
442 return;
443 }
444
445 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
446 bool mod_pressed = keyboard &&
447 (wlr_keyboard_get_modifiers(keyboard) & config->floating_mod);
448 enum wlr_edges edge = find_resize_edge(cont, cursor);
449 bool over_title = edge == WLR_EDGE_NONE && !surface;
450
451 // Check for beginning move
452 if (button == BTN_LEFT && state == WLR_BUTTON_PRESSED &&
453 (mod_pressed || over_title)) {
454 seat_begin_move(seat, cont, BTN_LEFT);
455 return;
456 }
457
458 // Check for beginning resize
459 bool resizing_via_border = button == BTN_LEFT && edge != WLR_EDGE_NONE;
460 bool resizing_via_mod = button == BTN_RIGHT && mod_pressed;
461 if ((resizing_via_border || resizing_via_mod) &&
462 state == WLR_BUTTON_PRESSED) {
463 seat_begin_resize(seat, cont, button, edge);
464 return;
465 }
466
467 // Send event to surface
468 seat_set_focus(seat, cont);
469 seat_pointer_notify_button(seat, time_msec, button, state);
470}
471
246void dispatch_cursor_button(struct sway_cursor *cursor, 472void dispatch_cursor_button(struct sway_cursor *cursor,
247 uint32_t time_msec, uint32_t button, enum wlr_button_state state) { 473 uint32_t time_msec, uint32_t button, enum wlr_button_state state) {
474 if (cursor->seat->operation != OP_NONE &&
475 button == cursor->seat->op_button && state == WLR_BUTTON_RELEASED) {
476 seat_end_mouse_operation(cursor->seat);
477 seat_pointer_notify_button(cursor->seat, time_msec, button, state);
478 return;
479 }
248 if (time_msec == 0) { 480 if (time_msec == 0) {
249 time_msec = get_current_time_msec(); 481 time_msec = get_current_time_msec();
250 } 482 }
@@ -259,6 +491,10 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
259 if (layer->current.keyboard_interactive) { 491 if (layer->current.keyboard_interactive) {
260 seat_set_focus_layer(cursor->seat, layer); 492 seat_set_focus_layer(cursor->seat, layer);
261 } 493 }
494 seat_pointer_notify_button(cursor->seat, time_msec, button, state);
495 } else if (cont && container_is_floating(cont)) {
496 dispatch_cursor_button_floating(cursor, time_msec, button, state,
497 surface, sx, sy, cont);
262 } else if (surface && cont && cont->type != C_VIEW) { 498 } else if (surface && cont && cont->type != C_VIEW) {
263 // Avoid moving keyboard focus from a surface that accepts it to one 499 // Avoid moving keyboard focus from a surface that accepts it to one
264 // that does not unless the change would move us to a new workspace. 500 // that does not unless the change would move us to a new workspace.
@@ -275,12 +511,14 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
275 if (new_ws != old_ws) { 511 if (new_ws != old_ws) {
276 seat_set_focus(cursor->seat, cont); 512 seat_set_focus(cursor->seat, cont);
277 } 513 }
514 seat_pointer_notify_button(cursor->seat, time_msec, button, state);
278 } else if (cont) { 515 } else if (cont) {
279 seat_set_focus(cursor->seat, cont); 516 seat_set_focus(cursor->seat, cont);
517 seat_pointer_notify_button(cursor->seat, time_msec, button, state);
518 } else {
519 seat_pointer_notify_button(cursor->seat, time_msec, button, state);
280 } 520 }
281 521
282 wlr_seat_pointer_notify_button(cursor->seat->wlr_seat,
283 time_msec, button, state);
284 transaction_commit_dirty(); 522 transaction_commit_dirty();
285} 523}
286 524
@@ -467,6 +705,9 @@ static void handle_request_set_cursor(struct wl_listener *listener,
467 void *data) { 705 void *data) {
468 struct sway_cursor *cursor = 706 struct sway_cursor *cursor =
469 wl_container_of(listener, cursor, request_set_cursor); 707 wl_container_of(listener, cursor, request_set_cursor);
708 if (cursor->seat->operation != OP_NONE) {
709 return;
710 }
470 struct wlr_seat_pointer_request_set_cursor_event *event = data; 711 struct wlr_seat_pointer_request_set_cursor_event *event = data;
471 712
472 struct wl_client *focused_client = NULL; 713 struct wl_client *focused_client = NULL;
@@ -488,6 +729,16 @@ static void handle_request_set_cursor(struct wl_listener *listener,
488 cursor->image_client = focused_client; 729 cursor->image_client = focused_client;
489} 730}
490 731
732void cursor_set_image(struct sway_cursor *cursor, const char *image,
733 struct wl_client *client) {
734 if (!cursor->image || strcmp(cursor->image, image) != 0) {
735 wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image,
736 cursor->cursor);
737 cursor->image = image;
738 }
739 cursor->image_client = client;
740}
741
491void sway_cursor_destroy(struct sway_cursor *cursor) { 742void sway_cursor_destroy(struct sway_cursor *cursor) {
492 if (!cursor) { 743 if (!cursor) {
493 return; 744 return;
diff --git a/sway/input/seat.c b/sway/input/seat.c
index e77d88a8..273223db 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -1,6 +1,11 @@
1#define _XOPEN_SOURCE 700 1#define _XOPEN_SOURCE 700
2#define _POSIX_C_SOURCE 199309L 2#define _POSIX_C_SOURCE 199309L
3#include <assert.h> 3#include <assert.h>
4#ifdef __linux__
5#include <linux/input-event-codes.h>
6#elif __FreeBSD__
7#include <dev/evdev/input-event-codes.h>
8#endif
4#include <strings.h> 9#include <strings.h>
5#include <time.h> 10#include <time.h>
6#include <wlr/types/wlr_cursor.h> 11#include <wlr/types/wlr_cursor.h>
@@ -348,6 +353,7 @@ struct sway_seat *seat_create(struct sway_input_manager *input,
348 free(seat); 353 free(seat);
349 return NULL; 354 return NULL;
350 } 355 }
356 seat->wlr_seat->data = seat;
351 357
352 seat->cursor = sway_cursor_create(seat); 358 seat->cursor = sway_cursor_create(seat);
353 if (!seat->cursor) { 359 if (!seat->cursor) {
@@ -894,3 +900,68 @@ struct seat_config *seat_get_config(struct sway_seat *seat) {
894 900
895 return NULL; 901 return NULL;
896} 902}
903
904void seat_begin_move(struct sway_seat *seat, struct sway_container *con,
905 uint32_t button) {
906 if (!seat->cursor) {
907 wlr_log(WLR_DEBUG, "Ignoring move request due to no cursor device");
908 return;
909 }
910 seat->operation = OP_MOVE;
911 seat->op_container = con;
912 seat->op_button = button;
913 cursor_set_image(seat->cursor, "grab", NULL);
914}
915
916void seat_begin_resize(struct sway_seat *seat, struct sway_container *con,
917 uint32_t button, enum wlr_edges edge) {
918 if (!seat->cursor) {
919 wlr_log(WLR_DEBUG, "Ignoring resize request due to no cursor device");
920 return;
921 }
922 struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
923 seat->operation = OP_RESIZE;
924 seat->op_container = con;
925 seat->op_resize_preserve_ratio = keyboard &&
926 (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT);
927 seat->op_resize_edge = edge == WLR_EDGE_NONE ?
928 RESIZE_EDGE_BOTTOM | RESIZE_EDGE_RIGHT : edge;
929 seat->op_button = button;
930 seat->op_ref_lx = seat->cursor->cursor->x;
931 seat->op_ref_ly = seat->cursor->cursor->y;
932 seat->op_ref_con_lx = con->x;
933 seat->op_ref_con_ly = con->y;
934 seat->op_ref_width = con->width;
935 seat->op_ref_height = con->height;
936
937 const char *image = edge == WLR_EDGE_NONE ?
938 "se-resize" : wlr_xcursor_get_resize_name(edge);
939 cursor_set_image(seat->cursor, image, NULL);
940}
941
942void seat_end_mouse_operation(struct sway_seat *seat) {
943 switch (seat->operation) {
944 case OP_MOVE:
945 {
946 // We "move" the container to its own location so it discovers its
947 // output again.
948 struct sway_container *con = seat->op_container;
949 container_floating_move_to(con, con->x, con->y);
950 }
951 case OP_RESIZE:
952 // Don't need to do anything here.
953 break;
954 case OP_NONE:
955 break;
956 }
957 seat->operation = OP_NONE;
958 seat->op_container = NULL;
959 cursor_set_image(seat->cursor, "left_ptr", NULL);
960}
961
962void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,
963 uint32_t button, enum wlr_button_state state) {
964 seat->last_button = button;
965 seat->last_button_serial = wlr_seat_pointer_notify_button(seat->wlr_seat,
966 time_msec, button, state);
967}
diff --git a/sway/meson.build b/sway/meson.build
index 09bc40b8..f4fdc8ea 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -42,6 +42,7 @@ sway_sources = files(
42 'commands/exec_always.c', 42 'commands/exec_always.c',
43 'commands/floating.c', 43 'commands/floating.c',
44 'commands/floating_minmax_size.c', 44 'commands/floating_minmax_size.c',
45 'commands/floating_modifier.c',
45 'commands/focus.c', 46 'commands/focus.c',
46 'commands/focus_follows_mouse.c', 47 'commands/focus_follows_mouse.c',
47 'commands/focus_wrapping.c', 48 'commands/focus_wrapping.c',
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 4dbfbb29..42c1d024 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -323,6 +323,8 @@ static struct sway_container *container_destroy_noreaping(
323 } 323 }
324 } 324 }
325 325
326 container_end_mouse_operation(con);
327
326 con->destroying = true; 328 con->destroying = true;
327 container_set_dirty(con); 329 container_set_dirty(con);
328 330
@@ -964,6 +966,8 @@ void container_set_floating(struct sway_container *container, bool enable) {
964 container_reap_empty_recursive(workspace->sway_workspace->floating); 966 container_reap_empty_recursive(workspace->sway_workspace->floating);
965 } 967 }
966 968
969 container_end_mouse_operation(container);
970
967 ipc_event_window(container, "floating"); 971 ipc_event_window(container, "floating");
968} 972}
969 973
@@ -1009,7 +1013,7 @@ void container_get_box(struct sway_container *container, struct wlr_box *box) {
1009/** 1013/**
1010 * Translate the container's position as well as all children. 1014 * Translate the container's position as well as all children.
1011 */ 1015 */
1012static void container_floating_translate(struct sway_container *con, 1016void container_floating_translate(struct sway_container *con,
1013 double x_amount, double y_amount) { 1017 double x_amount, double y_amount) {
1014 con->x += x_amount; 1018 con->x += x_amount;
1015 con->y += y_amount; 1019 con->y += y_amount;
@@ -1105,3 +1109,12 @@ static bool find_urgent_iterator(struct sway_container *con,
1105bool container_has_urgent_child(struct sway_container *container) { 1109bool container_has_urgent_child(struct sway_container *container) {
1106 return container_find(container, find_urgent_iterator, NULL); 1110 return container_find(container, find_urgent_iterator, NULL);
1107} 1111}
1112
1113void container_end_mouse_operation(struct sway_container *container) {
1114 struct sway_seat *seat;
1115 wl_list_for_each(seat, &input_manager->seats, link) {
1116 if (seat->op_container == container) {
1117 seat_end_mouse_operation(seat);
1118 }
1119 }
1120}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 1f898f8a..533906fa 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -562,6 +562,7 @@ void container_move(struct sway_container *container,
562 workspace_detect_urgent(last_ws); 562 workspace_detect_urgent(last_ws);
563 workspace_detect_urgent(next_ws); 563 workspace_detect_urgent(next_ws);
564 } 564 }
565 container_end_mouse_operation(container);
565} 566}
566 567
567enum sway_container_layout container_get_default_layout( 568enum sway_container_layout container_get_default_layout(
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 7881e6d7..89150a69 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -141,6 +141,19 @@ const char *view_get_shell(struct sway_view *view) {
141 return "unknown"; 141 return "unknown";
142} 142}
143 143
144void view_get_constraints(struct sway_view *view, double *min_width,
145 double *max_width, double *min_height, double *max_height) {
146 if (view->impl->get_constraints) {
147 view->impl->get_constraints(view,
148 min_width, max_width, min_height, max_height);
149 } else {
150 *min_width = DBL_MIN;
151 *max_width = DBL_MAX;
152 *min_height = DBL_MIN;
153 *max_height = DBL_MAX;
154 }
155}
156
144uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, 157uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
145 int height) { 158 int height) {
146 if (view->impl->configure) { 159 if (view->impl->configure) {
@@ -387,6 +400,8 @@ void view_set_fullscreen(struct sway_view *view, bool fullscreen) {
387 } 400 }
388 } 401 }
389 402
403 container_end_mouse_operation(view->swayc);
404
390 ipc_event_window(view->swayc, "fullscreen_mode"); 405 ipc_event_window(view->swayc, "fullscreen_mode");
391} 406}
392 407