summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2015-08-23 15:38:51 -0400
committerLibravatar Drew DeVault <sir@cmpwn.com>2015-08-23 15:38:51 -0400
commit9a7f48f87272dea8cb1e678673b2fe95dc993d68 (patch)
tree1a9e633ead0ff50f55987310621dab39531d2305
parentRefactor keyboard to consider modified keysyms (diff)
parentmerge (diff)
downloadsway-9a7f48f87272dea8cb1e678673b2fe95dc993d68.tar.gz
sway-9a7f48f87272dea8cb1e678673b2fe95dc993d68.tar.zst
sway-9a7f48f87272dea8cb1e678673b2fe95dc993d68.zip
Merge pull request #121 from taiyu-len/pointer_mod
Pointer mode clean and fix.
-rw-r--r--include/input_state.h72
-rw-r--r--include/layout.h2
-rw-r--r--include/resize.h3
-rw-r--r--sway/handlers.c247
-rw-r--r--sway/input_state.c281
-rw-r--r--sway/layout.c140
-rw-r--r--sway/resize.c261
7 files changed, 508 insertions, 498 deletions
diff --git a/include/input_state.h b/include/input_state.h
index 29064fd0..d87ae18c 100644
--- a/include/input_state.h
+++ b/include/input_state.h
@@ -15,6 +15,7 @@ void press_key(uint32_t key_sym, uint32_t key_code);
15// unsets a key as pressed 15// unsets a key as pressed
16void release_key(uint32_t key_sym, uint32_t key_code); 16void release_key(uint32_t key_sym, uint32_t key_code);
17 17
18
18/* Pointer state */ 19/* Pointer state */
19 20
20enum pointer_values { 21enum pointer_values {
@@ -25,34 +26,55 @@ enum pointer_values {
25 M_SCROLL_DOWN = 276, 26 M_SCROLL_DOWN = 276,
26}; 27};
27 28
29enum pointer_mode {
30 // Target
31 M_FLOATING = 1,
32 M_TILING = 2,
33 // Action
34 M_DRAGGING = 4,
35 M_RESIZING = 8,
36};
37
38struct pointer_button_state {
39 bool held;
40 // state at the point it was pressed
41 int x, y;
42 swayc_t *view;
43};
44
28extern struct pointer_state { 45extern struct pointer_state {
29 bool l_held; 46 // mouse clicks
30 bool r_held; 47 struct pointer_button_state left;
31 struct pointer_floating { 48 struct pointer_button_state right;
32 bool drag; 49 struct pointer_button_state scroll;
33 bool resize; 50
34 } floating; 51 // pointer position
35 struct pointer_tiling { 52 struct mouse_origin{
36 bool resize; 53 int x, y;
37 swayc_t *init_view; 54 } origin;
38 struct wlc_origin lock_pos; 55
39 } tiling; 56 // change in pointer position
40 struct pointer_lock { 57 struct {
41 // Lock movement for certain edges 58 int x, y;
42 bool left; 59 } delta;
43 bool right; 60
44 bool top; 61 // view pointer is currently over
45 bool bottom; 62 swayc_t *view;
46 // Lock movement in certain directions 63
47 bool temp_left; 64 // Pointer mode
48 bool temp_right; 65 int mode;
49 bool temp_up;
50 bool temp_down;
51 } lock;
52} pointer_state; 66} pointer_state;
53 67
54void start_floating(swayc_t *view); 68// on button release unset mode depending on the button.
55void reset_floating(swayc_t *view); 69// on button press set mode conditionally depending on the button
70void pointer_mode_set(uint32_t button, bool condition);
71
72// Update mode in mouse motion
73void pointer_mode_update(void);
74
75// Reset mode on any keypress;
76void pointer_mode_reset(void);
77
56void input_init(void); 78void input_init(void);
57 79
58#endif 80#endif
diff --git a/include/layout.h b/include/layout.h
index f8aebe0a..8f269607 100644
--- a/include/layout.h
+++ b/include/layout.h
@@ -19,10 +19,12 @@ void add_floating(swayc_t *ws, swayc_t *child);
19swayc_t *add_sibling(swayc_t *sibling, swayc_t *child); 19swayc_t *add_sibling(swayc_t *sibling, swayc_t *child);
20swayc_t *replace_child(swayc_t *child, swayc_t *new_child); 20swayc_t *replace_child(swayc_t *child, swayc_t *new_child);
21swayc_t *remove_child(swayc_t *child); 21swayc_t *remove_child(swayc_t *child);
22void swap_container(swayc_t *a, swayc_t *b);
22 23
23void move_container(swayc_t* container,swayc_t* root,enum movement_direction direction); 24void move_container(swayc_t* container,swayc_t* root,enum movement_direction direction);
24 25
25// Layout 26// Layout
27void update_geometry(swayc_t *view);
26void arrange_windows(swayc_t *container, double width, double height); 28void arrange_windows(swayc_t *container, double width, double height);
27 29
28swayc_t *get_focused_container(swayc_t *parent); 30swayc_t *get_focused_container(swayc_t *parent);
diff --git a/include/resize.h b/include/resize.h
index 4ace1815..8d205d3b 100644
--- a/include/resize.h
+++ b/include/resize.h
@@ -1,8 +1,7 @@
1#ifndef _SWAY_RESIZE_H 1#ifndef _SWAY_RESIZE_H
2#define _SWAY_RESIZE_H 2#define _SWAY_RESIZE_H
3#include <stdbool.h>
3 4
4bool mouse_resize_tiled(struct wlc_origin prev_pos);
5bool resize_floating(struct wlc_origin prev_pos);
6bool resize_tiled(int amount, bool use_width); 5bool resize_tiled(int amount, bool use_width);
7 6
8#endif 7#endif
diff --git a/sway/handlers.c b/sway/handlers.c
index acf3e6a4..27f6d294 100644
--- a/sway/handlers.c
+++ b/sway/handlers.c
@@ -17,10 +17,14 @@
17#include "input_state.h" 17#include "input_state.h"
18#include "resize.h" 18#include "resize.h"
19 19
20struct wlc_origin mouse_origin; 20// Event should be sent to client
21#define EVENT_PASSTHROUGH false
22
23// Event handled by sway and should not be sent to client
24#define EVENT_HANDLED true
21 25
22static bool pointer_test(swayc_t *view, void *_origin) { 26static bool pointer_test(swayc_t *view, void *_origin) {
23 const struct wlc_origin *origin = _origin; 27 const struct mouse_origin *origin = _origin;
24 // Determine the output that the view is under 28 // Determine the output that the view is under
25 swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT); 29 swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
26 if (origin->x >= view->x && origin->y >= view->y 30 if (origin->x >= view->x && origin->y >= view->y
@@ -55,7 +59,7 @@ swayc_t *container_under_pointer(void) {
55 i = len = lookup->floating->length; 59 i = len = lookup->floating->length;
56 bool got_floating = false; 60 bool got_floating = false;
57 while (--i > -1) { 61 while (--i > -1) {
58 if (pointer_test(lookup->floating->items[i], &mouse_origin)) { 62 if (pointer_test(lookup->floating->items[i], &pointer_state.origin)) {
59 lookup = lookup->floating->items[i]; 63 lookup = lookup->floating->items[i];
60 got_floating = true; 64 got_floating = true;
61 break; 65 break;
@@ -68,7 +72,7 @@ swayc_t *container_under_pointer(void) {
68 // search children 72 // search children
69 len = lookup->children->length; 73 len = lookup->children->length;
70 for (i = 0; i < len; ++i) { 74 for (i = 0; i < len; ++i) {
71 if (pointer_test(lookup->children->items[i], &mouse_origin)) { 75 if (pointer_test(lookup->children->items[i], &pointer_state.origin)) {
72 lookup = lookup->children->items[i]; 76 lookup = lookup->children->items[i];
73 break; 77 break;
74 } 78 }
@@ -284,13 +288,12 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
284 uint32_t key, uint32_t sym, enum wlc_key_state state) { 288 uint32_t key, uint32_t sym, enum wlc_key_state state) {
285 289
286 if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) { 290 if (locked_view_focus && state == WLC_KEY_STATE_PRESSED) {
287 return false; 291 return EVENT_PASSTHROUGH;
288 } 292 }
289 293
290 // Revert floating container back to original position on keypress 294 // reset pointer mode on keypress
291 if (state == WLC_KEY_STATE_PRESSED && 295 if (state == WLC_KEY_STATE_PRESSED && pointer_state.mode) {
292 (pointer_state.floating.drag || pointer_state.floating.resize)) { 296 pointer_mode_reset();
293 reset_floating(get_focused_view(&root_container));
294 } 297 }
295 298
296 struct sway_mode *mode = config->current_mode; 299 struct sway_mode *mode = config->current_mode;
@@ -319,125 +322,119 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
319 if (match) { 322 if (match) {
320 if (state == WLC_KEY_STATE_PRESSED) { 323 if (state == WLC_KEY_STATE_PRESSED) {
321 handle_command(config, binding->command); 324 handle_command(config, binding->command);
322 return true; 325 return EVENT_HANDLED;
323 } else if (state == WLC_KEY_STATE_RELEASED) { 326 } else if (state == WLC_KEY_STATE_RELEASED) {
324 // TODO: --released 327 // TODO: --released
325 } 328 }
326 } 329 }
327 } 330 }
328 } 331 }
329 return false; 332 return EVENT_PASSTHROUGH;
330} 333}
331 334
332static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_origin *origin) { 335static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_origin *origin) {
333 static struct wlc_origin prev_pos; 336 // Update pointer origin
334 static wlc_handle prev_handle = 0; 337 pointer_state.delta.x = origin->x - pointer_state.origin.x;
335 mouse_origin = *origin; 338 pointer_state.delta.y = origin->y - pointer_state.origin.y;
336 bool changed_floating = false; 339 pointer_state.origin.x = origin->x;
337 bool changed_tiling = false; 340 pointer_state.origin.y = origin->y;
338 if (!swayc_active_workspace()) { 341
339 return false; 342 // Update view under pointer
340 } 343 swayc_t *prev_view = pointer_state.view;
341 // Do checks to determine if proper keys are being held 344 pointer_state.view = container_under_pointer();
342 swayc_t *view = container_under_pointer(); 345
343 if (pointer_state.floating.drag && view) { 346 // If pointer is in a mode, update it
344 if (view->is_floating) { 347 if (pointer_state.mode) {
345 int dx = mouse_origin.x - prev_pos.x; 348 pointer_mode_update();
346 int dy = mouse_origin.y - prev_pos.y;
347 view->x += dx;
348 view->y += dy;
349 struct wlc_geometry geometry = {
350 .origin = {
351 .x = view->x,
352 .y = view->y
353 },
354 .size = {
355 .w = view->width,
356 .h = view->height
357 }
358 };
359 wlc_view_set_geometry(view->handle, 0, &geometry);
360 changed_floating = true;
361 } else {
362 swayc_t *init_view = pointer_state.tiling.init_view;
363 if (view != init_view && view->type == C_VIEW) {
364 changed_tiling = true;
365 int i, j;
366 for (i = 0; i < view->parent->children->length; i++) {
367 if (view->parent->children->items[i] == view) {
368 for (j = 0; j < init_view->parent->children->length; j++) {
369 if (init_view->parent->children->items[j] == init_view) {
370 double temp_w = view->width;
371 double temp_h = view->height;
372 view->width = init_view->width;
373 view->height = init_view->height;
374 init_view->width = temp_w;
375 init_view->height = temp_h;
376
377 init_view->parent->children->items[j] = view;
378 view->parent->children->items[i] = init_view;
379
380 swayc_t *temp = view->parent;
381 view->parent = init_view->parent;
382 init_view->parent = temp;
383
384 arrange_windows(&root_container, -1, -1);
385 break;
386 }
387 }
388 break;
389 }
390 }
391 }
392 }
393 } else if (pointer_state.floating.resize && view) {
394 changed_floating = resize_floating(prev_pos);
395 } else if (pointer_state.tiling.resize && view) {
396 changed_tiling = mouse_resize_tiled(prev_pos);
397 } 349 }
398 if (config->focus_follows_mouse && prev_handle != handle) { 350 // Otherwise change focus if config is set an
399 // Dont change focus if fullscreen 351 else if (prev_view != pointer_state.view && config->focus_follows_mouse) {
400 swayc_t *focused = get_focused_view(view); 352 if (pointer_state.view && pointer_state.view->type == C_VIEW) {
401 if (!swayc_is_fullscreen(focused) 353 set_focused_container(pointer_state.view);
402 && !(pointer_state.l_held || pointer_state.r_held)) {
403 set_focused_container(container_under_pointer());
404 } 354 }
405 } 355 }
406 prev_handle = handle; 356 return EVENT_PASSTHROUGH;
407 prev_pos = mouse_origin;
408 if (changed_tiling || changed_floating) {
409 return true;
410 }
411 return false;
412} 357}
413 358
414 359
415static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, 360static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers,
416 uint32_t button, enum wlc_button_state state, const struct wlc_origin *origin) { 361 uint32_t button, enum wlc_button_state state, const struct wlc_origin *origin) {
417 swayc_t *focused = get_focused_container(&root_container); 362
418 // dont change focus if fullscreen 363 // Update view pointer is on
419 if (swayc_is_fullscreen(focused)) { 364 pointer_state.view = container_under_pointer();
420 return false; 365
421 } 366 // Update pointer origin
422 if (state == WLC_BUTTON_STATE_PRESSED) { 367 pointer_state.origin.x = origin->x;
423 sway_log(L_DEBUG, "Mouse button %u pressed", button); 368 pointer_state.origin.y = origin->y;
424 if (button == M_LEFT_CLICK) { 369
425 pointer_state.l_held = true; 370 // Update pointer_state
371 switch (button) {
372 case M_LEFT_CLICK:
373 if (state == WLC_BUTTON_STATE_PRESSED) {
374 pointer_state.left.held = true;
375 pointer_state.left.x = origin->x;
376 pointer_state.left.y = origin->y;
377 pointer_state.left.view = pointer_state.view;
378 } else {
379 pointer_state.left.held = false;
426 } 380 }
427 if (button == M_RIGHT_CLICK) { 381 break;
428 pointer_state.r_held = true; 382
383 case M_RIGHT_CLICK:
384 if (state == WLC_BUTTON_STATE_PRESSED) {
385 pointer_state.right.held = true;
386 pointer_state.right.x = origin->x;
387 pointer_state.right.y = origin->y;
388 pointer_state.right.view = pointer_state.view;
389 } else {
390 pointer_state.right.held = false;
429 } 391 }
430 swayc_t *pointer = container_under_pointer(); 392 break;
431 if (pointer) { 393
432 set_focused_container(pointer); 394 case M_SCROLL_CLICK:
433 int midway_x = pointer->x + pointer->width/2; 395 if (state == WLC_BUTTON_STATE_PRESSED) {
434 int midway_y = pointer->y + pointer->height/2; 396 pointer_state.scroll.held = true;
435 pointer_state.lock.bottom = origin->y < midway_y; 397 pointer_state.scroll.x = origin->x;
436 pointer_state.lock.top = !pointer_state.lock.bottom; 398 pointer_state.scroll.y = origin->y;
437 pointer_state.lock.right = origin->x < midway_x; 399 pointer_state.scroll.view = pointer_state.view;
438 pointer_state.lock.left = !pointer_state.lock.right; 400 } else {
401 pointer_state.scroll.held = false;
439 } 402 }
403 break;
404
405 //TODO scrolling behavior
406 case M_SCROLL_UP:
407 case M_SCROLL_DOWN:
408 break;
409 }
410
411 // get focused window and check if to change focus on mouse click
412 swayc_t *focused = get_focused_container(&root_container);
413
414 // dont change focus or mode if fullscreen
415 if (swayc_is_fullscreen(focused)) {
416 return EVENT_PASSTHROUGH;
417 }
418
419 // set pointer mode
420 pointer_mode_set(button,
421 (modifiers->mods & config->floating_mod) == config->floating_mod);
440 422
423 // Return if mode has been set
424 if (pointer_state.mode) {
425 return EVENT_HANDLED;
426 }
427
428 // Always send mouse release
429 if (state == WLC_BUTTON_STATE_RELEASED) {
430 return EVENT_PASSTHROUGH;
431 }
432
433 // Check whether to change focus
434 swayc_t *pointer = pointer_state.view;
435 if (pointer && focused != pointer) {
436 set_focused_container(pointer_state.view);
437 // Send to front if floating
441 if (pointer->is_floating) { 438 if (pointer->is_floating) {
442 int i; 439 int i;
443 for (i = 0; i < pointer->parent->floating->length; i++) { 440 for (i = 0; i < pointer->parent->floating->length; i++) {
@@ -447,40 +444,12 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w
447 break; 444 break;
448 } 445 }
449 } 446 }
450 arrange_windows(pointer->parent, -1, -1); 447 wlc_view_bring_to_front(view);
451 if (modifiers->mods & config->floating_mod) {
452 pointer_state.floating.drag = pointer_state.l_held;
453 pointer_state.floating.resize = pointer_state.r_held;
454 start_floating(pointer);
455 }
456 // Dont want pointer sent to window while dragging or resizing
457 return (pointer_state.floating.drag || pointer_state.floating.resize);
458 } else {
459 if (modifiers->mods & config->floating_mod) {
460 pointer_state.floating.drag = pointer_state.l_held;
461 pointer_state.tiling.resize = pointer_state.r_held;
462 pointer_state.tiling.init_view = pointer;
463 // Dont want pointer sent when resizing
464 return (pointer_state.tiling.resize);
465 }
466 }
467 return (pointer && pointer != focused);
468 } else {
469 sway_log(L_DEBUG, "Mouse button %u released", button);
470 if (button == M_LEFT_CLICK) {
471 pointer_state.l_held = false;
472 pointer_state.floating.drag = false;
473 pointer_state.tiling.init_view = NULL;
474 }
475 if (button == M_RIGHT_CLICK) {
476 pointer_state.r_held = false;
477 pointer_state.floating.resize = false;
478 pointer_state.tiling.resize = false;
479 pointer_state.tiling.init_view = NULL;
480 pointer_state.lock = (struct pointer_lock){false ,false ,false ,false, false, false, false, false};
481 } 448 }
482 } 449 }
483 return false; 450
451 // Finally send click
452 return EVENT_PASSTHROUGH;
484} 453}
485 454
486static void handle_wlc_ready(void) { 455static void handle_wlc_ready(void) {
diff --git a/sway/input_state.c b/sway/input_state.c
index 9e065e60..e911d9cf 100644
--- a/sway/input_state.c
+++ b/sway/input_state.c
@@ -74,27 +74,276 @@ void release_key(uint32_t key_sym, uint32_t key_code) {
74 } 74 }
75} 75}
76 76
77// Pointer state and mode
78
77struct pointer_state pointer_state; 79struct pointer_state pointer_state;
78 80
79static struct wlc_geometry saved_floating; 81static struct mode_state {
82 // initial view state
83 double x, y, w, h;
84 swayc_t *ptr;
85 // Containers used for resizing horizontally
86 struct {
87 double w;
88 swayc_t *ptr;
89 struct {
90 double w;
91 swayc_t *ptr;
92 } parent;
93 } horiz;
94 // Containers used for resizing vertically
95 struct {
96 double h;
97 swayc_t *ptr;
98 struct {
99 double h;
100 swayc_t *ptr;
101 } parent;
102 } vert;
103} initial;
104
105static struct {
106 bool left;
107 bool top;
108} lock;
109
110// initial set/unset
111
112static void set_initial_view(swayc_t *view) {
113 initial.ptr = view;
114 initial.x = view->x;
115 initial.y = view->y;
116 initial.w = view->width;
117 initial.h = view->height;
118}
119
120static void set_initial_sibling(void) {
121 bool reset = true;
122 if ((initial.horiz.ptr = get_swayc_in_direction(initial.ptr, lock.left ? MOVE_RIGHT: MOVE_LEFT))) {
123 initial.horiz.w = initial.horiz.ptr->width;
124 initial.horiz.parent.ptr = get_swayc_in_direction(initial.horiz.ptr, lock.left ? MOVE_LEFT : MOVE_RIGHT);
125 initial.horiz.parent.w = initial.horiz.parent.ptr->width;
126 reset = false;
127 }
128 if ((initial.vert.ptr = get_swayc_in_direction(initial.ptr, lock.top ? MOVE_DOWN: MOVE_UP))) {
129 initial.vert.h = initial.vert.ptr->height;
130 initial.vert.parent.ptr = get_swayc_in_direction(initial.vert.ptr, lock.top ? MOVE_UP : MOVE_DOWN);
131 initial.vert.parent.h = initial.vert.parent.ptr->height;
132 reset = false;
133 }
134 // If nothing will change just undo the mode
135 if (reset) {
136 pointer_state.mode = 0;
137 }
138}
139
140static void reset_initial_view(void) {
141 initial.ptr->x = initial.x;
142 initial.ptr->y = initial.y;
143 initial.ptr->width = initial.w;
144 initial.ptr->height = initial.h;
145 arrange_windows(initial.ptr, -1, -1);
146 pointer_state.mode = 0;
147}
148
149static void reset_initial_sibling(void) {
150 initial.horiz.ptr->width = initial.horiz.w;
151 initial.horiz.parent.ptr->width = initial.horiz.parent.w;
152 initial.vert.ptr->height = initial.vert.h;
153 initial.vert.parent.ptr->height = initial.vert.parent.h;
154 arrange_windows(initial.horiz.ptr->parent, -1, -1);
155 arrange_windows(initial.vert.ptr->parent, -1, -1);
156 pointer_state.mode = 0;
157}
158
159// Mode set left/right click
160
161static void pointer_mode_set_left(void) {
162 set_initial_view(pointer_state.left.view);
163 if (initial.ptr->is_floating) {
164 pointer_state.mode = M_DRAGGING | M_FLOATING;
165 } else {
166 pointer_state.mode = M_DRAGGING | M_TILING;
167 }
168}
169
170static void pointer_mode_set_right(void) {
171 set_initial_view(pointer_state.right.view);
172 // Setup locking information
173 int midway_x = initial.ptr->x + initial.ptr->width/2;
174 int midway_y = initial.ptr->y + initial.ptr->height/2;
175
176 lock.left = pointer_state.origin.x > midway_x;
177 lock.top = pointer_state.origin.y > midway_y;
178
179 if (initial.ptr->is_floating) {
180 pointer_state.mode = M_RESIZING | M_FLOATING;
181 } else {
182 pointer_state.mode = M_RESIZING | M_TILING;
183 set_initial_sibling();
184 }
185}
186
187// Mode set/update/reset
188
189void pointer_mode_set(uint32_t button, bool condition) {
190 // switch on drag/resize mode
191 switch (pointer_state.mode & (M_DRAGGING | M_RESIZING)) {
192 case M_DRAGGING:
193 // end drag mode when left click is unpressed
194 if (!pointer_state.left.held) {
195 pointer_state.mode = 0;
196 }
197 break;
198
199 case M_RESIZING:
200 // end resize mode when right click is unpressed
201 if (!pointer_state.right.held) {
202 pointer_state.mode = 0;
203 }
204 break;
205
206 // No mode case
207 default:
208 // return if failed condition, or no view
209 if (!condition || !pointer_state.view) {
210 break;
211 }
80 212
81void start_floating(swayc_t *view) { 213 // Set mode depending on current button press
82 if (view->is_floating) { 214 switch (button) {
83 saved_floating.origin.x = view->x; 215 // Start dragging mode
84 saved_floating.origin.y = view->y; 216 case M_LEFT_CLICK:
85 saved_floating.size.w = view->width; 217 // if button release dont do anything
86 saved_floating.size.h = view->height; 218 if (pointer_state.left.held) {
219 pointer_mode_set_left();
220 }
221 break;
222
223 // Start resize mode
224 case M_RIGHT_CLICK:
225 // if button release dont do anyhting
226 if (pointer_state.right.held) {
227 pointer_mode_set_right();
228 }
229 break;
230 }
87 } 231 }
88} 232}
89 233
90void reset_floating(swayc_t *view) { 234void pointer_mode_update(void) {
91 if (view->is_floating) { 235 if (initial.ptr->type != C_VIEW) {
92 view->x = saved_floating.origin.x; 236 pointer_state.mode = 0;
93 view->y = saved_floating.origin.y; 237 return;
94 view->width = saved_floating.size.w; 238 }
95 view->height = saved_floating.size.h; 239 int dx = pointer_state.origin.x;
96 arrange_windows(view->parent, -1, -1); 240 int dy = pointer_state.origin.y;
241
242 switch (pointer_state.mode) {
243 case M_FLOATING | M_DRAGGING:
244 // Update position
245 dx -= pointer_state.left.x;
246 dy -= pointer_state.left.y;
247 if (initial.x + dx != initial.ptr->x) {
248 initial.ptr->x = initial.x + dx;
249 }
250 if (initial.y + dy != initial.ptr->y) {
251 initial.ptr->y = initial.y + dy;
252 }
253 update_geometry(initial.ptr);
254 break;
255
256 case M_FLOATING | M_RESIZING:
257 dx -= pointer_state.right.x;
258 dy -= pointer_state.right.y;
259 initial.ptr = pointer_state.right.view;
260 if (lock.left) {
261 if (initial.w + dx > min_sane_w) {
262 initial.ptr->width = initial.w + dx;
263 }
264 } else { // lock.right
265 if (initial.w - dx > min_sane_w) {
266 initial.ptr->width = initial.w - dx;
267 initial.ptr->x = initial.x + dx;
268 }
269 }
270 if (lock.top) {
271 if (initial.h + dy > min_sane_h) {
272 initial.ptr->height = initial.h + dy;
273 }
274 } else { // lock.bottom
275 if (initial.h - dy > min_sane_h) {
276 initial.ptr->height = initial.h - dy;
277 initial.ptr->y = initial.y + dy;
278 }
279 }
280 update_geometry(initial.ptr);
281 break;
282
283 case M_TILING | M_DRAGGING:
284 // swap current view under pointer with dragged view
285 if (pointer_state.view && pointer_state.view->type == C_VIEW
286 && pointer_state.view != initial.ptr) {
287 // Swap them around
288 swap_container(pointer_state.view, initial.ptr);
289 update_geometry(pointer_state.view);
290 update_geometry(initial.ptr);
291 // Set focus back to initial view
292 set_focused_container(initial.ptr);
293 }
294 break;
295
296 case M_TILING | M_RESIZING:
297 dx -= pointer_state.right.x;
298 dy -= pointer_state.right.y;
299 // resize if we can
300 if (initial.horiz.ptr) {
301 if (lock.left) {
302 // Check whether its fine to resize
303 if (initial.w + dx > min_sane_w && initial.horiz.w - dx > min_sane_w) {
304 initial.horiz.ptr->width = initial.horiz.w - dx;
305 initial.horiz.parent.ptr->width = initial.horiz.parent.w + dx;
306 }
307 } else { // lock.right
308 if (initial.w - dx > min_sane_w && initial.horiz.w + dx > min_sane_w) {
309 initial.horiz.ptr->width = initial.horiz.w + dx;
310 initial.horiz.parent.ptr->width = initial.horiz.parent.w - dx;
311 }
312 }
313 arrange_windows(initial.horiz.ptr->parent, -1, -1);
314 }
315 if (initial.vert.ptr) {
316 if (lock.top) {
317 if (initial.h + dy > min_sane_h && initial.vert.h - dy > min_sane_h) {
318 initial.vert.ptr->height = initial.vert.h - dy;
319 initial.vert.parent.ptr->height = initial.vert.parent.h + dy;
320 }
321 } else { // lock.bottom
322 if (initial.h - dy > min_sane_h && initial.vert.h + dy > min_sane_h) {
323 initial.vert.ptr->height = initial.vert.h + dy;
324 initial.vert.parent.ptr->height = initial.vert.parent.h - dy;
325 }
326 }
327 arrange_windows(initial.vert.ptr->parent, -1, -1);
328 }
329 default:
330 return;
331 }
332}
333
334void pointer_mode_reset(void) {
335 switch (pointer_state.mode) {
336 case M_FLOATING | M_RESIZING:
337 case M_FLOATING | M_DRAGGING:
338 reset_initial_view();
339 break;
340
341 case M_TILING | M_RESIZING:
342 (void) reset_initial_sibling;
343 break;
344
345 case M_TILING | M_DRAGGING:
346 default:
347 break;
97 } 348 }
98 pointer_state.floating = (struct pointer_floating){0, 0};
99 pointer_state.lock = (struct pointer_lock){0, 0, 0, 0, 0, 0, 0, 0};
100} 349}
diff --git a/sway/layout.c b/sway/layout.c
index 035fea34..bc12b9b1 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -20,7 +20,8 @@ void init_layout(void) {
20 root_container.handle = -1; 20 root_container.handle = -1;
21} 21}
22 22
23static int index_child(swayc_t *parent, swayc_t *child) { 23static int index_child(swayc_t *child) {
24 swayc_t *parent = child->parent;
24 int i; 25 int i;
25 for (i = 0; i < parent->children->length; ++i) { 26 for (i = 0; i < parent->children->length; ++i) {
26 if (parent->children->items[i] == child) { 27 if (parent->children->items[i] == child) {
@@ -54,7 +55,7 @@ void add_floating(swayc_t *ws, swayc_t *child) {
54 55
55swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) { 56swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) {
56 swayc_t *parent = sibling->parent; 57 swayc_t *parent = sibling->parent;
57 int i = index_child(parent, sibling); 58 int i = index_child(sibling);
58 if (i == parent->children->length) { 59 if (i == parent->children->length) {
59 --i; 60 --i;
60 } 61 }
@@ -68,17 +69,65 @@ swayc_t *replace_child(swayc_t *child, swayc_t *new_child) {
68 if (parent == NULL) { 69 if (parent == NULL) {
69 return NULL; 70 return NULL;
70 } 71 }
71 int i = index_child(parent, child); 72 int i = index_child(child);
72 parent->children->items[i] = new_child; 73 parent->children->items[i] = new_child;
73 new_child->parent = child->parent; 74 new_child->parent = child->parent;
74 75
76 // Set parent for new child
75 if (child->parent->focused == child) { 77 if (child->parent->focused == child) {
76 child->parent->focused = new_child; 78 child->parent->focused = new_child;
77 } 79 }
78 child->parent = NULL; 80 child->parent = NULL;
81 // Set geometry for new child
82 new_child->x = child->x;
83 new_child->y = child->y;
84 new_child->width = child->width;
85 new_child->height = child->height;
86 // set child geometry to 0
87 child->x = 0;
88 child->y = 0;
89 child->width = 0;
90 child->height = 0;
79 return parent; 91 return parent;
80} 92}
81 93
94void swap_container(swayc_t *a, swayc_t *b) {
95 //TODO doesnt handle floating <-> tiling swap
96 if (!sway_assert(a&&b, "%s: parameters must be non null",__func__) ||
97 !sway_assert(a->parent && b->parent, "%s: containers must have parents",__func__)) {
98 return;
99 }
100 size_t a_index = index_child(a);
101 size_t b_index = index_child(b);
102 swayc_t *a_parent = a->parent;
103 swayc_t *b_parent = b->parent;
104 // Swap the pointers
105 a_parent->children->items[a_index] = b;
106 b_parent->children->items[b_index] = a;
107 a->parent = b_parent;
108 b->parent = a_parent;
109 if (a_parent->focused == a) {
110 a_parent->focused = b;
111 }
112 // dont want to double switch
113 if (b_parent->focused == b && a_parent != b_parent) {
114 b_parent->focused = a;
115 }
116 // and their geometry
117 double x = a->x;
118 double y = a->y;
119 double w = a->width;
120 double h = a->height;
121 a->x = b->x;
122 a->y = b->y;
123 a->width = b->width;
124 a->height = b->height;
125 b->x = x;
126 b->y = y;
127 b->width = w;
128 b->height = h;
129}
130
82swayc_t *remove_child(swayc_t *child) { 131swayc_t *remove_child(swayc_t *child) {
83 int i; 132 int i;
84 swayc_t *parent = child->parent; 133 swayc_t *parent = child->parent;
@@ -154,6 +203,30 @@ void move_container(swayc_t *container,swayc_t* root,enum movement_direction dir
154 203
155} 204}
156 205
206void update_geometry(swayc_t *container) {
207 if (container->type != C_VIEW) {
208 return;
209 }
210 struct wlc_geometry geometry = {
211 .origin = {
212 .x = container->x + (container->is_floating ? 0 : container->gaps / 2),
213 .y = container->y + (container->is_floating ? 0 : container->gaps / 2)
214 },
215 .size = {
216 .w = container->width - (container->is_floating ? 0 : container->gaps),
217 .h = container->height - (container->is_floating ? 0 : container->gaps)
218 }
219 };
220 if (swayc_is_fullscreen(container)) {
221 swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT);
222 geometry.origin.x = 0;
223 geometry.origin.y = 0;
224 geometry.size.w = parent->width;
225 geometry.size.h = parent->height;
226 }
227 wlc_view_set_geometry(container->handle, 0, &geometry);
228 return;
229}
157 230
158void arrange_windows(swayc_t *container, double width, double height) { 231void arrange_windows(swayc_t *container, double width, double height) {
159 int i; 232 int i;
@@ -189,31 +262,11 @@ void arrange_windows(swayc_t *container, double width, double height) {
189 return; 262 return;
190 case C_VIEW: 263 case C_VIEW:
191 { 264 {
192 struct wlc_geometry geometry = { 265 container->width = width;
193 .origin = { 266 container->height = height;
194 .x = container->x + container->gaps / 2, 267 update_geometry(container);
195 .y = container->y + container->gaps / 2 268 sway_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f", container->width,
196 }, 269 container->height, container->x, container->y);
197 .size = {
198 .w = width - container->gaps,
199 .h = height - container->gaps
200 }
201 };
202 if (swayc_is_fullscreen(container)) {
203 swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT);
204 geometry.origin.x = 0;
205 geometry.origin.y = 0;
206 geometry.size.w = parent->width;
207 geometry.size.h = parent->height;
208 wlc_view_set_geometry(container->handle, 0, &geometry);
209 wlc_view_bring_to_front(container->handle);
210 } else {
211 wlc_view_set_geometry(container->handle, 0, &geometry);
212 container->width = width;
213 container->height = height;
214 }
215 sway_log(L_DEBUG, "Set view to %d x %d @ %d, %d", geometry.size.w, geometry.size.h,
216 geometry.origin.x, geometry.origin.y);
217 } 270 }
218 return; 271 return;
219 default: 272 default:
@@ -287,35 +340,12 @@ void arrange_windows(swayc_t *container, double width, double height) {
287 for (i = 0; i < container->floating->length; ++i) { 340 for (i = 0; i < container->floating->length; ++i) {
288 swayc_t *view = container->floating->items[i]; 341 swayc_t *view = container->floating->items[i];
289 if (view->type == C_VIEW) { 342 if (view->type == C_VIEW) {
290 // Set the geometry 343 update_geometry(view);
291 struct wlc_geometry geometry = {
292 .origin = {
293 .x = view->x,
294 .y = view->y
295 },
296 .size = {
297 .w = view->width,
298 .h = view->height
299 }
300 };
301 if (swayc_is_fullscreen(view)) { 344 if (swayc_is_fullscreen(view)) {
302 swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
303 geometry.origin.x = 0;
304 geometry.origin.y = 0;
305 geometry.size.w = parent->width;
306 geometry.size.h = parent->height;
307 wlc_view_set_geometry(view->handle, 0, &geometry);
308 wlc_view_bring_to_front(view->handle); 345 wlc_view_bring_to_front(view->handle);
309 } else { 346 } else if (!container->focused
310 wlc_view_set_geometry(view->handle, 0, &geometry); 347 || !swayc_is_fullscreen(container->focused)) {
311 // Bring the views to the front in order of the list, the list 348 wlc_view_bring_to_front(view->handle);
312 // will be kept up to date so that more recently focused views
313 // have higher indexes
314 // This is conditional on there not being a fullscreen view in the workspace
315 if (!container->focused
316 || !swayc_is_fullscreen(container->focused)) {
317 wlc_view_bring_to_front(view->handle);
318 }
319 } 349 }
320 } 350 }
321 } 351 }
diff --git a/sway/resize.c b/sway/resize.c
index a08ef4a1..22d520af 100644
--- a/sway/resize.c
+++ b/sway/resize.c
@@ -6,267 +6,6 @@
6#include "input_state.h" 6#include "input_state.h"
7#include "handlers.h" 7#include "handlers.h"
8 8
9bool mouse_resize_tiled(struct wlc_origin prev_pos) {
10 swayc_t *view = container_under_pointer();
11 bool valid = true;
12 bool changed_tiling = false;
13 double dx = mouse_origin.x - prev_pos.x;
14 double dy = mouse_origin.y - prev_pos.y;
15 if (view != pointer_state.tiling.init_view) {
16 changed_tiling = true;
17 valid = false;
18 if (view->type != C_WORKSPACE) {
19 if (get_swayc_in_direction(pointer_state.tiling.init_view, MOVE_LEFT) == view) {
20 pointer_state.tiling.lock_pos.x = pointer_state.tiling.init_view->x + 20;
21 pointer_state.lock.temp_left = true;
22 } else if (get_swayc_in_direction(pointer_state.tiling.init_view, MOVE_RIGHT) == view) {
23 pointer_state.tiling.lock_pos.x = pointer_state.tiling.init_view->x + pointer_state.tiling.init_view->width - 20;
24 pointer_state.lock.temp_right = true;
25 } else if (get_swayc_in_direction(pointer_state.tiling.init_view, MOVE_UP) == view) {
26 pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + 20;
27 pointer_state.lock.temp_up = true;
28 } else if (get_swayc_in_direction(pointer_state.tiling.init_view, MOVE_DOWN) == view) {
29 pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + pointer_state.tiling.init_view->height - 20;
30 pointer_state.lock.temp_down = true;
31 }
32 }
33 }
34
35 if ((dx < 0 || mouse_origin.x < pointer_state.tiling.lock_pos.x) && pointer_state.lock.temp_left) {
36 changed_tiling = true;
37 valid = false;
38 } else if (dx > 0 && pointer_state.lock.temp_left) {
39 pointer_state.lock.temp_left = false;
40 pointer_state.tiling.lock_pos.x = 0;
41 }
42
43 if ((dx > 0 || mouse_origin.x > pointer_state.tiling.lock_pos.x) && pointer_state.lock.temp_right) {
44 changed_tiling = true;
45 valid = false;
46 } else if (dx < 0 && pointer_state.lock.temp_right) {
47 pointer_state.lock.temp_right = false;
48 pointer_state.tiling.lock_pos.x = 0;
49 }
50
51 if ((dy < 0 || mouse_origin.y < pointer_state.tiling.lock_pos.y) && pointer_state.lock.temp_up) {
52 changed_tiling = true;
53 valid = false;
54 } else if (dy > 0 && pointer_state.lock.temp_up) {
55 pointer_state.lock.temp_up = false;
56 pointer_state.tiling.lock_pos.y = 0;
57 }
58
59 if ((dy > 0 || mouse_origin.y > pointer_state.tiling.lock_pos.y) && pointer_state.lock.temp_down) {
60 changed_tiling = true;
61 valid = false;
62 } else if (dy < 0 && pointer_state.lock.temp_down) {
63 pointer_state.lock.temp_down = false;
64 pointer_state.tiling.lock_pos.y = 0;
65 }
66
67 if (!view->is_floating && valid) {
68 // Handle layout resizes -- Find the biggest parent container then apply resizes to that
69 // and its bordering siblings
70 swayc_t *parent = view;
71 if (!pointer_state.lock.bottom) {
72 while (parent->type != C_WORKSPACE) {
73 // TODO: Absolute value is a bad hack here to compensate for rounding. Find a better
74 // way of doing this.
75 if (fabs(parent->parent->y + parent->parent->height - (view->y + view->height)) <= 1) {
76 parent = parent->parent;
77 } else {
78 break;
79 }
80 }
81 if (parent->parent->children->length > 1 && parent->parent->layout == L_VERT) {
82 swayc_t *sibling = get_swayc_in_direction(parent, MOVE_DOWN);
83 if (sibling) {
84 if ((parent->height > min_sane_h || dy > 0) && (sibling->height > min_sane_h || dy < 0)) {
85 recursive_resize(parent, dy, WLC_RESIZE_EDGE_BOTTOM);
86 recursive_resize(sibling, -1 * dy, WLC_RESIZE_EDGE_TOP);
87 changed_tiling = true;
88 } else {
89 if (parent->height < min_sane_h) {
90 //pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + 20;
91 pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + pointer_state.tiling.init_view->height - 20;
92 pointer_state.lock.temp_up = true;
93 } else if (sibling->height < min_sane_h) {
94 pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + pointer_state.tiling.init_view->height - 20;
95 pointer_state.lock.temp_down = true;
96 }
97 }
98 }
99 }
100 } else if (!pointer_state.lock.top) {
101 while (parent->type != C_WORKSPACE) {
102 if (fabs(parent->parent->y - view->y) <= 1) {
103 parent = parent->parent;
104 } else {
105 break;
106 }
107 }
108 if (parent->parent->children->length > 1 && parent->parent->layout == L_VERT) {
109 swayc_t *sibling = get_swayc_in_direction(parent, MOVE_UP);
110 if (sibling) {
111 if ((parent->height > min_sane_h || dy < 0) && (sibling->height > min_sane_h || dy > 0)) {
112 recursive_resize(parent, -1 * dy, WLC_RESIZE_EDGE_TOP);
113 recursive_resize(sibling, dy, WLC_RESIZE_EDGE_BOTTOM);
114 changed_tiling = true;
115 } else {
116 if (parent->height < min_sane_h) {
117 //pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + pointer_state.tiling.init_view->height - 20;
118 pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + 20;
119 pointer_state.lock.temp_down = true;
120 } else if (sibling->height < min_sane_h) {
121 pointer_state.tiling.lock_pos.y = pointer_state.tiling.init_view->y + 20;
122 pointer_state.lock.temp_up = true;
123 }
124 }
125 }
126 }
127 }
128
129 parent = view;
130 if (!pointer_state.lock.right) {
131 while (parent->type != C_WORKSPACE) {
132 if (fabs(parent->parent->x + parent->parent->width - (view->x + view->width)) <= 1) {
133 parent = parent->parent;
134 } else {
135 sway_log(L_DEBUG, "view: %f vs parent: %f", view->x + view->width, parent->parent->x + parent->parent->width);
136 break;
137 }
138 }
139 if (parent->parent->children->length > 1 && parent->parent->layout == L_HORIZ) {
140 swayc_t *sibling = get_swayc_in_direction(parent, MOVE_RIGHT);
141 if (sibling) {
142 if ((parent->width > min_sane_w || dx > 0) && (sibling->width > min_sane_w || dx < 0)) {
143 recursive_resize(parent, dx, WLC_RESIZE_EDGE_RIGHT);
144 recursive_resize(sibling, -1 * dx, WLC_RESIZE_EDGE_LEFT);
145 changed_tiling = true;
146 } else {
147 if (parent->width < min_sane_w) {
148 pointer_state.lock.temp_left = true;
149 pointer_state.tiling.lock_pos.x = pointer_state.tiling.init_view->x + pointer_state.tiling.init_view->width - 20;
150 } else if (sibling->width < min_sane_w) {
151 pointer_state.lock.temp_right = true;
152 pointer_state.tiling.lock_pos.x = pointer_state.tiling.init_view->x + pointer_state.tiling.init_view->width - 20;
153 }
154 }
155 }
156 }
157 } else if (!pointer_state.lock.left) {
158 while (parent->type != C_WORKSPACE) {
159 if (fabs(parent->parent->x - view->x) <= 1 && parent->parent) {
160 parent = parent->parent;
161 } else {
162 break;
163 }
164 }
165 if (parent->parent->children->length > 1 && parent->parent->layout == L_HORIZ) {
166 swayc_t *sibling = get_swayc_in_direction(parent, MOVE_LEFT);
167 if (sibling) {
168 if ((parent->width > min_sane_w || dx < 0) && (sibling->width > min_sane_w || dx > 0)) {
169 recursive_resize(parent, -1 * dx, WLC_RESIZE_EDGE_LEFT);
170 recursive_resize(sibling, dx, WLC_RESIZE_EDGE_RIGHT);
171 changed_tiling = true;
172 } else {
173 if (parent->width < min_sane_w) {
174 pointer_state.lock.temp_right = true;
175 pointer_state.tiling.lock_pos.x = pointer_state.tiling.init_view->x + 20;
176 } else if (sibling->width < min_sane_w) {
177 pointer_state.lock.temp_left = true;
178 pointer_state.tiling.lock_pos.x = pointer_state.tiling.init_view->x + 20;
179 }
180 }
181 }
182 }
183 }
184 arrange_windows(swayc_active_workspace(), -1, -1);
185 }
186 return changed_tiling;
187}
188
189bool resize_floating(struct wlc_origin prev_pos) {
190 bool changed = false;
191 swayc_t *view = container_under_pointer();
192 uint32_t edge = 0;
193 int dx = mouse_origin.x - prev_pos.x;
194 int dy = mouse_origin.y - prev_pos.y;
195
196 // Move and resize the view based on the dx/dy and mouse position
197 int midway_x = view->x + view->width/2;
198 int midway_y = view->y + view->height/2;
199 if (dx < 0) {
200 if (!pointer_state.lock.right) {
201 if (view->width > min_sane_w) {
202 changed = true;
203 view->width += dx;
204 edge += WLC_RESIZE_EDGE_RIGHT;
205 }
206 } else if (mouse_origin.x < midway_x && !pointer_state.lock.left) {
207 changed = true;
208 view->x += dx;
209 view->width -= dx;
210 edge += WLC_RESIZE_EDGE_LEFT;
211 }
212 } else if (dx > 0) {
213 if (mouse_origin.x > midway_x && !pointer_state.lock.right) {
214 changed = true;
215 view->width += dx;
216 edge += WLC_RESIZE_EDGE_RIGHT;
217 } else if (!pointer_state.lock.left) {
218 if (view->width > min_sane_w) {
219 changed = true;
220 view->x += dx;
221 view->width -= dx;
222 edge += WLC_RESIZE_EDGE_LEFT;
223 }
224 }
225 }
226
227 if (dy < 0) {
228 if (!pointer_state.lock.bottom) {
229 if (view->height > min_sane_h) {
230 changed = true;
231 view->height += dy;
232 edge += WLC_RESIZE_EDGE_BOTTOM;
233 }
234 } else if (mouse_origin.y < midway_y && !pointer_state.lock.top) {
235 changed = true;
236 view->y += dy;
237 view->height -= dy;
238 edge += WLC_RESIZE_EDGE_TOP;
239 }
240 } else if (dy > 0) {
241 if (mouse_origin.y > midway_y && !pointer_state.lock.bottom) {
242 changed = true;
243 view->height += dy;
244 edge += WLC_RESIZE_EDGE_BOTTOM;
245 } else if (!pointer_state.lock.top) {
246 if (view->height > min_sane_h) {
247 changed = true;
248 view->y += dy;
249 view->height -= dy;
250 edge += WLC_RESIZE_EDGE_TOP;
251 }
252 }
253 }
254 if (changed) {
255 struct wlc_geometry geometry = {
256 .origin = {
257 .x = view->x,
258 .y = view->y
259 },
260 .size = {
261 .w = view->width,
262 .h = view->height
263 }
264 };
265 wlc_view_set_geometry(view->handle, edge, &geometry);
266 }
267 return changed;
268}
269
270bool resize_tiled(int amount, bool use_width) { 9bool resize_tiled(int amount, bool use_width) {
271 swayc_t *parent = get_focused_view(swayc_active_workspace()); 10 swayc_t *parent = get_focused_view(swayc_active_workspace());
272 swayc_t *focused = parent; 11 swayc_t *focused = parent;