diff options
author | emersion <contact@emersion.fr> | 2018-07-22 19:25:41 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-22 19:25:41 +0100 |
commit | be60e44b7c08b87400fed0b9ea586c449883ba11 (patch) | |
tree | 5005c92ed70e19fcd9a316b9a9fad0d3ba07b6ad | |
parent | Merge pull request #2320 from RedSoxFan/reset-outputs-on-reload (diff) | |
parent | Set cursor when beginning resize and move operations (diff) | |
download | sway-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.h | 2 | ||||
-rw-r--r-- | include/sway/input/cursor.h | 4 | ||||
-rw-r--r-- | include/sway/input/seat.h | 30 | ||||
-rw-r--r-- | include/sway/tree/container.h | 12 | ||||
-rw-r--r-- | include/sway/tree/layout.h | 9 | ||||
-rw-r--r-- | include/sway/tree/view.h | 5 | ||||
-rw-r--r-- | sway/commands.c | 1 | ||||
-rw-r--r-- | sway/commands/floating_modifier.c | 20 | ||||
-rw-r--r-- | sway/desktop/output.c | 9 | ||||
-rw-r--r-- | sway/desktop/transaction.c | 14 | ||||
-rw-r--r-- | sway/desktop/xdg_shell.c | 50 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 50 | ||||
-rw-r--r-- | sway/desktop/xwayland.c | 41 | ||||
-rw-r--r-- | sway/input/cursor.c | 275 | ||||
-rw-r--r-- | sway/input/seat.c | 71 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/tree/container.c | 15 | ||||
-rw-r--r-- | sway/tree/layout.c | 1 | ||||
-rw-r--r-- | sway/tree/view.c | 15 |
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; | |||
106 | sway_cmd cmd_floating; | 106 | sway_cmd cmd_floating; |
107 | sway_cmd cmd_floating_maximum_size; | 107 | sway_cmd cmd_floating_maximum_size; |
108 | sway_cmd cmd_floating_minimum_size; | 108 | sway_cmd cmd_floating_minimum_size; |
109 | sway_cmd cmd_floating_mod; | 109 | sway_cmd cmd_floating_modifier; |
110 | sway_cmd cmd_floating_scroll; | 110 | sway_cmd cmd_floating_scroll; |
111 | sway_cmd cmd_focus; | 111 | sway_cmd cmd_focus; |
112 | sway_cmd cmd_focus_follows_mouse; | 112 | sway_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, | |||
37 | void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec, | 38 | void 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 | ||
41 | void 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 | ||
8 | struct sway_seat_device { | 9 | struct 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 | ||
135 | void drag_icon_update_position(struct sway_drag_icon *icon); | 154 | void drag_icon_update_position(struct sway_drag_icon *icon); |
136 | 155 | ||
156 | void seat_begin_move(struct sway_seat *seat, struct sway_container *con, | ||
157 | uint32_t button); | ||
158 | |||
159 | void seat_begin_resize(struct sway_seat *seat, struct sway_container *con, | ||
160 | uint32_t button, enum wlr_edges edge); | ||
161 | |||
162 | void seat_end_mouse_operation(struct sway_seat *seat); | ||
163 | |||
164 | void 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); | |||
305 | void container_get_box(struct sway_container *container, struct wlr_box *box); | 305 | void 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 | */ | ||
310 | void 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 | */ |
310 | void container_floating_move_to(struct sway_container *con, | 316 | void container_floating_move_to(struct sway_container *con, |
@@ -318,4 +324,10 @@ void container_set_dirty(struct sway_container *container); | |||
318 | 324 | ||
319 | bool container_has_urgent_child(struct sway_container *container); | 325 | bool 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 | */ | ||
331 | void 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 | ||
16 | enum resize_edge { | 16 | enum 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 | ||
23 | struct sway_container; | 24 | struct 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 | ||
28 | struct sway_view_impl { | 28 | struct 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 | ||
216 | const char *view_get_shell(struct sway_view *view); | 218 | const char *view_get_shell(struct sway_view *view); |
217 | 219 | ||
220 | void view_get_constraints(struct sway_view *view, double *min_width, | ||
221 | double *max_width, double *min_height, double *max_height); | ||
222 | |||
218 | uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, | 223 | uint32_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 | |||
5 | struct 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 | ||
464 | void output_damage_whole_container(struct sway_output *output, | 464 | void 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 | */ | ||
228 | static void transaction_progress_queue() { | 225 | static 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 | ||
99 | static 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 | |||
98 | static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) { | 109 | static 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 | ||
190 | static const struct sway_view_impl view_impl = { | 201 | static 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 | ||
263 | static 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 | |||
277 | static 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 | |||
251 | static void handle_unmap(struct wl_listener *listener, void *data) { | 291 | static 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 | ||
267 | static void handle_map(struct wl_listener *listener, void *data) { | 309 | static 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 | ||
304 | static void handle_destroy(struct wl_listener *listener, void *data) { | 354 | static 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 | ||
98 | static 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 | |||
97 | static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) { | 108 | static 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 | ||
186 | static const struct sway_view_impl view_impl = { | 197 | static 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 | ||
258 | static 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 | |||
272 | static 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 | |||
246 | static void handle_unmap(struct wl_listener *listener, void *data) { | 286 | static 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 | ||
262 | static void handle_map(struct wl_listener *listener, void *data) { | 304 | static 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 | ||
299 | static void handle_destroy(struct wl_listener *listener, void *data) { | 349 | static 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 | ||
405 | static 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 | |||
420 | static 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 | |||
403 | static void handle_set_title(struct wl_listener *listener, void *data) { | 436 | static 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 | ||
146 | static 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 | |||
172 | static 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 | |||
182 | static 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 | |||
219 | static 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 | |||
142 | void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | 311 | void 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 | ||
433 | static 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 | |||
246 | void dispatch_cursor_button(struct sway_cursor *cursor, | 472 | void 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 | ||
732 | void 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 | |||
491 | void sway_cursor_destroy(struct sway_cursor *cursor) { | 742 | void 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 | |||
904 | void 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 | |||
916 | void 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 | |||
942 | void 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 | |||
962 | void 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 | */ |
1012 | static void container_floating_translate(struct sway_container *con, | 1016 | void 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, | |||
1105 | bool container_has_urgent_child(struct sway_container *container) { | 1109 | bool 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 | |||
1113 | void 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 | ||
567 | enum sway_container_layout container_get_default_layout( | 568 | enum 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 | ||
144 | void 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 | |||
144 | uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, | 157 | uint32_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 | ||