diff options
author | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-07-18 16:13:28 +1000 |
---|---|---|
committer | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-07-22 23:10:19 +1000 |
commit | 9fbe13b9be18c732b58033a57a22a299af91a170 (patch) | |
tree | a24901c1bb4eff87877c0d9fb96767b662a9d533 | |
parent | Merge pull request #2320 from RedSoxFan/reset-outputs-on-reload (diff) | |
download | sway-9fbe13b9be18c732b58033a57a22a299af91a170.tar.gz sway-9fbe13b9be18c732b58033a57a22a299af91a170.tar.zst sway-9fbe13b9be18c732b58033a57a22a299af91a170.zip |
Implement floating_modifier and mouse operations for floating views
This implements the following:
* `floating_modifier` configuration directive
* Drag a floating window by its title bar
* Hold mod + drag a floating window from anywhere
* Resize a floating view by dragging the border
* Resize a floating view by holding mod and right clicking anywhere on
the view
* Resize a floating view and keep aspect ratio by holding shift while
resizing using either method
* Mouse cursor turns into resize when hovering floating border or corner
-rw-r--r-- | include/sway/commands.h | 2 | ||||
-rw-r--r-- | include/sway/input/seat.h | 16 | ||||
-rw-r--r-- | include/sway/tree/container.h | 12 | ||||
-rw-r--r-- | include/sway/tree/layout.h | 9 | ||||
-rw-r--r-- | sway/commands.c | 1 | ||||
-rw-r--r-- | sway/commands/floating_modifier.c | 30 | ||||
-rw-r--r-- | sway/input/cursor.c | 322 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/tree/container.c | 16 | ||||
-rw-r--r-- | sway/tree/layout.c | 1 | ||||
-rw-r--r-- | sway/tree/view.c | 2 |
11 files changed, 395 insertions, 17 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/seat.h b/include/sway/input/seat.h index eac1626b..be1f3610 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h | |||
@@ -34,6 +34,8 @@ struct sway_drag_icon { | |||
34 | struct wl_listener destroy; | 34 | struct wl_listener destroy; |
35 | }; | 35 | }; |
36 | 36 | ||
37 | enum resize_edge; | ||
38 | |||
37 | struct sway_seat { | 39 | struct sway_seat { |
38 | struct wlr_seat *wlr_seat; | 40 | struct wlr_seat *wlr_seat; |
39 | struct sway_cursor *cursor; | 41 | struct sway_cursor *cursor; |
@@ -52,6 +54,20 @@ struct sway_seat { | |||
52 | int32_t touch_id; | 54 | int32_t touch_id; |
53 | double touch_x, touch_y; | 55 | double touch_x, touch_y; |
54 | 56 | ||
57 | // Operations (drag and resize) | ||
58 | enum { | ||
59 | OP_NONE, | ||
60 | OP_DRAG, | ||
61 | OP_RESIZE, | ||
62 | } operation; | ||
63 | struct sway_container *op_container; | ||
64 | enum resize_edge 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 | |||
55 | struct wl_listener focus_destroy; | 71 | struct wl_listener focus_destroy; |
56 | struct wl_listener new_container; | 72 | struct wl_listener new_container; |
57 | struct wl_listener new_drag_icon; | 73 | struct wl_listener new_drag_icon; |
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/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..1ced50af --- /dev/null +++ b/sway/commands/floating_modifier.c | |||
@@ -0,0 +1,30 @@ | |||
1 | #ifdef __linux__ | ||
2 | #include <linux/input-event-codes.h> | ||
3 | #elif __FreeBSD__ | ||
4 | #include <dev/evdev/input-event-codes.h> | ||
5 | #endif | ||
6 | #include <xkbcommon/xkbcommon.h> | ||
7 | #include <xkbcommon/xkbcommon-names.h> | ||
8 | #include <strings.h> | ||
9 | #include "sway/commands.h" | ||
10 | #include "sway/config.h" | ||
11 | #include "list.h" | ||
12 | #include "log.h" | ||
13 | #include "util.h" | ||
14 | |||
15 | struct cmd_results *cmd_floating_modifier(int argc, char **argv) { | ||
16 | struct cmd_results *error = NULL; | ||
17 | if ((error = checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1))) { | ||
18 | return error; | ||
19 | } | ||
20 | |||
21 | uint32_t mod = get_modifier_mask_by_name(argv[0]); | ||
22 | if (!mod) { | ||
23 | return cmd_results_new(CMD_INVALID, "floating_modifier", | ||
24 | "Invalid modifier"); | ||
25 | } | ||
26 | |||
27 | config->floating_mod = mod; | ||
28 | |||
29 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
30 | } | ||
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index c76c20b3..6ad214b5 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,173 @@ static struct sway_container *container_at_coords( | |||
139 | return output->swayc; | 143 | return output->swayc; |
140 | } | 144 | } |
141 | 145 | ||
146 | static enum resize_edge find_resize_edge(struct sway_container *cont, | ||
147 | struct sway_cursor *cursor) { | ||
148 | if (cont->type != C_VIEW) { | ||
149 | return RESIZE_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 RESIZE_EDGE_NONE; | ||
154 | } | ||
155 | |||
156 | enum resize_edge edge = 0; | ||
157 | if (cursor->cursor->x < cont->x + view->border_thickness) { | ||
158 | edge |= RESIZE_EDGE_LEFT; | ||
159 | } | ||
160 | if (cursor->cursor->y < cont->y + view->border_thickness) { | ||
161 | edge |= RESIZE_EDGE_TOP; | ||
162 | } | ||
163 | if (cursor->cursor->x >= cont->x + cont->width - view->border_thickness) { | ||
164 | edge |= RESIZE_EDGE_RIGHT; | ||
165 | } | ||
166 | if (cursor->cursor->y >= cont->y + cont->height - view->border_thickness) { | ||
167 | edge |= RESIZE_EDGE_BOTTOM; | ||
168 | } | ||
169 | return edge; | ||
170 | } | ||
171 | |||
172 | static void handle_drag_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 | static void handle_resize_motion(struct sway_seat *seat, | ||
219 | struct sway_cursor *cursor) { | ||
220 | struct sway_container *con = seat->op_container; | ||
221 | double center_lx = con->x + con->width / 2; | ||
222 | double center_ly = con->y + con->height / 2; | ||
223 | enum resize_edge edge = seat->op_resize_edge; | ||
224 | |||
225 | // The amount the mouse has moved since the start of the resize operation | ||
226 | // Positive is down/right | ||
227 | double mouse_move_x = cursor->cursor->x - seat->op_ref_lx; | ||
228 | double mouse_move_y = cursor->cursor->y - seat->op_ref_ly; | ||
229 | |||
230 | if (edge == RESIZE_EDGE_TOP || edge == RESIZE_EDGE_BOTTOM) { | ||
231 | mouse_move_x = 0; | ||
232 | } | ||
233 | if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) { | ||
234 | mouse_move_y = 0; | ||
235 | } | ||
236 | |||
237 | double grow_width = seat->op_ref_lx > center_lx ? | ||
238 | mouse_move_x : -mouse_move_x; | ||
239 | double grow_height = seat->op_ref_ly > center_ly ? | ||
240 | mouse_move_y : -mouse_move_y; | ||
241 | |||
242 | if (seat->op_resize_preserve_ratio) { | ||
243 | double x_multiplier = grow_width / seat->op_ref_width; | ||
244 | double y_multiplier = grow_height / seat->op_ref_height; | ||
245 | double avg_multiplier = (x_multiplier + y_multiplier) / 2; | ||
246 | grow_width = seat->op_ref_width * avg_multiplier; | ||
247 | grow_height = seat->op_ref_height * avg_multiplier; | ||
248 | } | ||
249 | |||
250 | // If we're resizing from the center (mod + right click), we need to double | ||
251 | // the amount we're growing because we're doing it in both directions. | ||
252 | if (edge == RESIZE_EDGE_NONE) { | ||
253 | grow_width *= 2; | ||
254 | grow_height *= 2; | ||
255 | } | ||
256 | |||
257 | // Determine new width/height, and accommodate for min/max values | ||
258 | double width = seat->op_ref_width + grow_width; | ||
259 | double height = seat->op_ref_height + grow_height; | ||
260 | int min_width, max_width, min_height, max_height; | ||
261 | calculate_floating_constraints(con, &min_width, &max_width, | ||
262 | &min_height, &max_height); | ||
263 | width = fmax(min_width, fmin(width, max_width)); | ||
264 | height = fmax(min_height, fmin(height, max_height)); | ||
265 | |||
266 | // Recalculate these, in case we hit a min/max limit | ||
267 | grow_width = width - seat->op_ref_width; | ||
268 | grow_height = height - seat->op_ref_height; | ||
269 | |||
270 | // Determine grow x/y values - these are relative to the container's x/y at | ||
271 | // the start of the resize operation. | ||
272 | double grow_x = 0, grow_y = 0; | ||
273 | if (edge & RESIZE_EDGE_LEFT) { | ||
274 | grow_x = -grow_width; | ||
275 | } else if (edge & RESIZE_EDGE_RIGHT) { | ||
276 | grow_x = 0; | ||
277 | } else { | ||
278 | grow_x = -grow_width / 2; | ||
279 | } | ||
280 | if (edge & RESIZE_EDGE_TOP) { | ||
281 | grow_y = -grow_height; | ||
282 | } else if (edge & RESIZE_EDGE_BOTTOM) { | ||
283 | grow_y = 0; | ||
284 | } else { | ||
285 | grow_y = -grow_height / 2; | ||
286 | } | ||
287 | |||
288 | // Determine the amounts we need to bump everything relative to the current | ||
289 | // size. | ||
290 | int relative_grow_width = width - con->width; | ||
291 | int relative_grow_height = height - con->height; | ||
292 | int relative_grow_x = (seat->op_ref_con_lx + grow_x) - con->x; | ||
293 | int relative_grow_y = (seat->op_ref_con_ly + grow_y) - con->y; | ||
294 | |||
295 | // Actually resize stuff | ||
296 | con->x += relative_grow_x; | ||
297 | con->y += relative_grow_y; | ||
298 | con->width += relative_grow_width; | ||
299 | con->height += relative_grow_height; | ||
300 | |||
301 | if (con->type == C_VIEW) { | ||
302 | struct sway_view *view = con->sway_view; | ||
303 | view->x += relative_grow_x; | ||
304 | view->y += relative_grow_y; | ||
305 | view->width += relative_grow_width; | ||
306 | view->height += relative_grow_height; | ||
307 | } | ||
308 | |||
309 | arrange_windows(con); | ||
310 | transaction_commit_dirty(); | ||
311 | } | ||
312 | |||
142 | void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | 313 | void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, |
143 | bool allow_refocusing) { | 314 | bool allow_refocusing) { |
144 | if (time_msec == 0) { | 315 | if (time_msec == 0) { |
@@ -146,6 +317,18 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | |||
146 | } | 317 | } |
147 | 318 | ||
148 | struct sway_seat *seat = cursor->seat; | 319 | struct sway_seat *seat = cursor->seat; |
320 | |||
321 | if (seat->operation != OP_NONE) { | ||
322 | if (seat->operation == OP_DRAG) { | ||
323 | handle_drag_motion(seat, cursor); | ||
324 | } else { | ||
325 | handle_resize_motion(seat, cursor); | ||
326 | } | ||
327 | cursor->previous.x = cursor->cursor->x; | ||
328 | cursor->previous.y = cursor->cursor->y; | ||
329 | return; | ||
330 | } | ||
331 | |||
149 | struct wlr_seat *wlr_seat = seat->wlr_seat; | 332 | struct wlr_seat *wlr_seat = seat->wlr_seat; |
150 | struct wlr_surface *surface = NULL; | 333 | struct wlr_surface *surface = NULL; |
151 | double sx, sy; | 334 | double sx, sy; |
@@ -194,15 +377,54 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | |||
194 | } | 377 | } |
195 | } | 378 | } |
196 | 379 | ||
197 | // reset cursor if switching between clients | 380 | // Handle cursor image |
198 | struct wl_client *client = NULL; | 381 | if (surface) { |
199 | if (surface != NULL) { | 382 | // Reset cursor if switching between clients |
200 | client = wl_resource_get_client(surface->resource); | 383 | struct wl_client *client = wl_resource_get_client(surface->resource); |
201 | } | 384 | if (client != cursor->image_client) { |
202 | if (client != cursor->image_client) { | 385 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, |
386 | "left_ptr", cursor->cursor); | ||
387 | cursor->image_client = client; | ||
388 | } | ||
389 | } else if (c && container_is_floating(c)) { | ||
390 | // Try a floating container's resize edge | ||
391 | enum resize_edge edge = find_resize_edge(c, cursor); | ||
392 | if (edge == RESIZE_EDGE_NONE) { | ||
393 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, | ||
394 | "left_ptr", cursor->cursor); | ||
395 | } else if (edge == RESIZE_EDGE_TOP) { | ||
396 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, | ||
397 | "top_side", cursor->cursor); | ||
398 | } else if (edge == RESIZE_EDGE_RIGHT) { | ||
399 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, | ||
400 | "right_side", cursor->cursor); | ||
401 | } else if (edge == RESIZE_EDGE_BOTTOM) { | ||
402 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, | ||
403 | "bottom_side", cursor->cursor); | ||
404 | } else if (edge == RESIZE_EDGE_LEFT) { | ||
405 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, | ||
406 | "left_side", cursor->cursor); | ||
407 | } else if (edge == (RESIZE_EDGE_TOP | RESIZE_EDGE_LEFT)) { | ||
408 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, | ||
409 | "top_left_corner", cursor->cursor); | ||
410 | } else if (edge == (RESIZE_EDGE_TOP | RESIZE_EDGE_RIGHT)) { | ||
411 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, | ||
412 | "top_right_corner", cursor->cursor); | ||
413 | } else if (edge == (RESIZE_EDGE_BOTTOM | RESIZE_EDGE_LEFT)) { | ||
414 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, | ||
415 | "bottom_left_corner", cursor->cursor); | ||
416 | } else if (edge == (RESIZE_EDGE_BOTTOM | RESIZE_EDGE_RIGHT)) { | ||
417 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, | ||
418 | "bottom_right_corner", cursor->cursor); | ||
419 | } else { | ||
420 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, | ||
421 | "left_ptr", cursor->cursor); | ||
422 | } | ||
423 | cursor->image_client = NULL; | ||
424 | } else { | ||
203 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, | 425 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, |
204 | "left_ptr", cursor->cursor); | 426 | "left_ptr", cursor->cursor); |
205 | cursor->image_client = client; | 427 | cursor->image_client = NULL; |
206 | } | 428 | } |
207 | 429 | ||
208 | // send pointer enter/leave | 430 | // send pointer enter/leave |
@@ -243,8 +465,79 @@ static void handle_cursor_motion_absolute( | |||
243 | transaction_commit_dirty(); | 465 | transaction_commit_dirty(); |
244 | } | 466 | } |
245 | 467 | ||
468 | static void handle_end_operation(struct sway_seat *seat) { | ||
469 | if (seat->operation == OP_DRAG) { | ||
470 | // We "move" the container to its own location so it discovers its | ||
471 | // output again. | ||
472 | struct sway_container *con = seat->op_container; | ||
473 | container_floating_move_to(con, con->x, con->y); | ||
474 | seat->operation = OP_NONE; | ||
475 | seat->op_container = NULL; | ||
476 | } else { | ||
477 | // OP_RESIZE | ||
478 | seat->operation = OP_NONE; | ||
479 | seat->op_container = NULL; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | static void dispatch_cursor_button_floating(struct sway_cursor *cursor, | ||
484 | uint32_t time_msec, uint32_t button, enum wlr_button_state state, | ||
485 | struct wlr_surface *surface, double sx, double sy, | ||
486 | struct sway_container *cont) { | ||
487 | struct sway_seat *seat = cursor->seat; | ||
488 | |||
489 | // Deny dragging or resizing a fullscreen view | ||
490 | if (cont->type == C_VIEW && cont->sway_view->is_fullscreen) { | ||
491 | wlr_seat_pointer_notify_button(seat->wlr_seat, time_msec, button, state); | ||
492 | return; | ||
493 | } | ||
494 | |||
495 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); | ||
496 | bool mod_pressed = keyboard && | ||
497 | (keyboard->modifiers.depressed & config->floating_mod); | ||
498 | enum resize_edge edge = find_resize_edge(cont, cursor); | ||
499 | bool over_title = edge == RESIZE_EDGE_NONE && !surface; | ||
500 | |||
501 | // Check for beginning drag | ||
502 | if (button == BTN_LEFT && state == WLR_BUTTON_PRESSED && | ||
503 | (mod_pressed || over_title)) { | ||
504 | seat->operation = OP_DRAG; | ||
505 | seat->op_container = cont; | ||
506 | seat->op_button = button; | ||
507 | return; | ||
508 | } | ||
509 | |||
510 | // Check for beginning resize | ||
511 | bool resizing_via_border = button == BTN_LEFT && edge; | ||
512 | bool resizing_via_mod = button == BTN_RIGHT && mod_pressed; | ||
513 | if ((resizing_via_border || resizing_via_mod) && | ||
514 | state == WLR_BUTTON_PRESSED) { | ||
515 | seat->operation = OP_RESIZE; | ||
516 | seat->op_container = cont; | ||
517 | seat->op_resize_preserve_ratio = keyboard && | ||
518 | (keyboard->modifiers.depressed & 1); // Shift | ||
519 | seat->op_resize_edge = edge; | ||
520 | seat->op_button = button; | ||
521 | seat->op_ref_lx = cursor->cursor->x; | ||
522 | seat->op_ref_ly = cursor->cursor->y; | ||
523 | seat->op_ref_con_lx = cont->x; | ||
524 | seat->op_ref_con_ly = cont->y; | ||
525 | seat->op_ref_width = cont->width; | ||
526 | seat->op_ref_height = cont->height; | ||
527 | return; | ||
528 | } | ||
529 | |||
530 | // Send event to surface | ||
531 | wlr_seat_pointer_notify_button(seat->wlr_seat, time_msec, button, state); | ||
532 | } | ||
533 | |||
246 | void dispatch_cursor_button(struct sway_cursor *cursor, | 534 | void dispatch_cursor_button(struct sway_cursor *cursor, |
247 | uint32_t time_msec, uint32_t button, enum wlr_button_state state) { | 535 | uint32_t time_msec, uint32_t button, enum wlr_button_state state) { |
536 | if (cursor->seat->operation != OP_NONE && | ||
537 | button == cursor->seat->op_button && state == WLR_BUTTON_RELEASED) { | ||
538 | handle_end_operation(cursor->seat); | ||
539 | return; | ||
540 | } | ||
248 | if (time_msec == 0) { | 541 | if (time_msec == 0) { |
249 | time_msec = get_current_time_msec(); | 542 | time_msec = get_current_time_msec(); |
250 | } | 543 | } |
@@ -259,6 +552,11 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
259 | if (layer->current.keyboard_interactive) { | 552 | if (layer->current.keyboard_interactive) { |
260 | seat_set_focus_layer(cursor->seat, layer); | 553 | seat_set_focus_layer(cursor->seat, layer); |
261 | } | 554 | } |
555 | wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, | ||
556 | time_msec, button, state); | ||
557 | } else if (cont && container_is_floating(cont)) { | ||
558 | dispatch_cursor_button_floating(cursor, time_msec, button, state, | ||
559 | surface, sx, sy, cont); | ||
262 | } else if (surface && cont && cont->type != C_VIEW) { | 560 | } else if (surface && cont && cont->type != C_VIEW) { |
263 | // Avoid moving keyboard focus from a surface that accepts it to one | 561 | // 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. | 562 | // that does not unless the change would move us to a new workspace. |
@@ -275,12 +573,14 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
275 | if (new_ws != old_ws) { | 573 | if (new_ws != old_ws) { |
276 | seat_set_focus(cursor->seat, cont); | 574 | seat_set_focus(cursor->seat, cont); |
277 | } | 575 | } |
576 | wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, | ||
577 | time_msec, button, state); | ||
278 | } else if (cont) { | 578 | } else if (cont) { |
279 | seat_set_focus(cursor->seat, cont); | 579 | seat_set_focus(cursor->seat, cont); |
580 | wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, | ||
581 | time_msec, button, state); | ||
280 | } | 582 | } |
281 | 583 | ||
282 | wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, | ||
283 | time_msec, button, state); | ||
284 | transaction_commit_dirty(); | 584 | transaction_commit_dirty(); |
285 | } | 585 | } |
286 | 586 | ||
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..ba4af352 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,13 @@ 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->op_container = NULL; | ||
1118 | seat->operation = OP_NONE; | ||
1119 | } | ||
1120 | } | ||
1121 | } | ||
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..24594950 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -387,6 +387,8 @@ void view_set_fullscreen(struct sway_view *view, bool fullscreen) { | |||
387 | } | 387 | } |
388 | } | 388 | } |
389 | 389 | ||
390 | container_end_mouse_operation(view->swayc); | ||
391 | |||
390 | ipc_event_window(view->swayc, "fullscreen_mode"); | 392 | ipc_event_window(view->swayc, "fullscreen_mode"); |
391 | } | 393 | } |
392 | 394 | ||