Fix keyboard and mouse resize in nested containers
Patch status: merged
Patch by jj
Long description:
fixes #1084 fixes #1085
To apply this patch, use:
curl http://cr.i3wm.org/patch/239/raw.patch | git am
b/include/resize.h
18 |
@@ -10,6 +10,8 @@ |
19 |
#ifndef I3_RESIZE_H |
20 |
#define I3_RESIZE_H |
21 |
|
22 |
+bool resize_find_tiling_participants(Con **current, Con **other, direction_t direction); |
23 |
+ |
24 |
int resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event); |
25 |
|
26 |
#endif |
b/src/click.c
31 |
@@ -28,45 +28,43 @@ typedef enum { CLICK_BORDER = 0, CLICK_DECORATION = 1, CLICK_INSIDE = 2 } click_ |
32 |
*/ |
33 |
static bool tiling_resize_for_border(Con *con, border_t border, xcb_button_press_event_t *event) { |
34 |
DLOG("border = %d, con = %p\n", border, con); |
35 |
- char way = (border == BORDER_TOP || border == BORDER_LEFT ? 'p' : 'n'); |
36 |
- orientation_t orientation = (border == BORDER_TOP || border == BORDER_BOTTOM ? VERT : HORIZ); |
37 |
- |
38 |
- /* look for a parent container with the right orientation */ |
39 |
- Con *first = NULL, *second = NULL; |
40 |
- Con *resize_con = con; |
41 |
- while (resize_con->type != CT_WORKSPACE && |
42 |
- resize_con->type != CT_FLOATING_CON && |
43 |
- con_orientation(resize_con->parent) != orientation) |
44 |
- resize_con = resize_con->parent; |
45 |
- |
46 |
- DLOG("resize_con = %p\n", resize_con); |
47 |
- if (resize_con->type != CT_WORKSPACE && |
48 |
- resize_con->type != CT_FLOATING_CON && |
49 |
- con_orientation(resize_con->parent) == orientation) { |
50 |
- first = resize_con; |
51 |
- second = (way == 'n') ? TAILQ_NEXT(first, nodes) : TAILQ_PREV(first, nodes_head, nodes); |
52 |
- if (second == TAILQ_END(&(first->nodes_head))) { |
53 |
- second = NULL; |
54 |
- } |
55 |
- else if (way == 'p') { |
56 |
- Con *tmp = first; |
57 |
- first = second; |
58 |
- second = tmp; |
59 |
- } |
60 |
- DLOG("first = %p, second = %p, resize_con = %p\n", |
61 |
- first, second, resize_con); |
62 |
+ Con *second = NULL; |
63 |
+ Con *first = con; |
64 |
+ direction_t search_direction; |
65 |
+ switch (border) { |
66 |
+ case BORDER_LEFT: |
67 |
+ search_direction = D_LEFT; |
68 |
+ break; |
69 |
+ case BORDER_RIGHT: |
70 |
+ search_direction = D_RIGHT; |
71 |
+ break; |
72 |
+ case BORDER_TOP: |
73 |
+ search_direction = D_UP; |
74 |
+ break; |
75 |
+ case BORDER_BOTTOM: |
76 |
+ search_direction = D_DOWN; |
77 |
+ break; |
78 |
} |
79 |
|
80 |
- if (first == NULL || second == NULL) { |
81 |
- DLOG("Resize not possible\n"); |
82 |
+ bool res = resize_find_tiling_participants(&first, &second, search_direction); |
83 |
+ if (!res) { |
84 |
+ LOG("No second container in this direction found.\n"); |
85 |
return false; |
86 |
} |
87 |
|
88 |
assert(first != second); |
89 |
assert(first->parent == second->parent); |
90 |
|
91 |
+ /* The first container should always be in front of the second container */ |
92 |
+ if (search_direction == D_UP || search_direction == D_LEFT) { |
93 |
+ Con *tmp = first; |
94 |
+ first = second; |
95 |
+ second = tmp; |
96 |
+ } |
97 |
+ |
98 |
/* We modify the X/Y position in the event so that the divider line is at |
99 |
* the actual position of the border, not at the position of the click. */ |
100 |
+ const orientation_t orientation = ((border == BORDER_LEFT || border == BORDER_RIGHT) ? HORIZ : VERT); |
101 |
if (orientation == HORIZ) |
102 |
event->root_x = second->rect.x; |
103 |
else event->root_y = second->rect.y; |
b/src/commands.c
108 |
@@ -618,79 +618,50 @@ static void cmd_resize_floating(I3_CMD, char *way, char *direction, Con *floatin |
109 |
|
110 |
static bool cmd_resize_tiling_direction(I3_CMD, Con *current, char *way, char *direction, int ppt) { |
111 |
LOG("tiling resize\n"); |
112 |
- /* get the appropriate current container (skip stacked/tabbed cons) */ |
113 |
- Con *other = NULL; |
114 |
- double percentage = 0; |
115 |
- while (current->parent->layout == L_STACKED || |
116 |
- current->parent->layout == L_TABBED) |
117 |
- current = current->parent; |
118 |
- |
119 |
- /* Then further go up until we find one with the matching orientation. */ |
120 |
- orientation_t search_orientation = |
121 |
- (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0 ? HORIZ : VERT); |
122 |
- |
123 |
- do { |
124 |
- if (con_orientation(current->parent) != search_orientation) { |
125 |
- current = current->parent; |
126 |
- continue; |
127 |
- } |
128 |
- |
129 |
- /* get the default percentage */ |
130 |
- int children = con_num_children(current->parent); |
131 |
- LOG("ins. %d children\n", children); |
132 |
- percentage = 1.0 / children; |
133 |
- LOG("default percentage = %f\n", percentage); |
134 |
- |
135 |
- orientation_t orientation = con_orientation(current->parent); |
136 |
- |
137 |
- if ((orientation == HORIZ && |
138 |
- (strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0)) || |
139 |
- (orientation == VERT && |
140 |
- (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0))) { |
141 |
- LOG("You cannot resize in that direction. Your focus is in a %s split container currently.\n", |
142 |
- (orientation == HORIZ ? "horizontal" : "vertical")); |
143 |
- ysuccess(false); |
144 |
- return false; |
145 |
- } |
146 |
- |
147 |
- if (strcmp(direction, "up") == 0 || strcmp(direction, "left") == 0) { |
148 |
- other = TAILQ_PREV(current, nodes_head, nodes); |
149 |
- } else { |
150 |
- other = TAILQ_NEXT(current, nodes); |
151 |
- } |
152 |
- if (other == TAILQ_END(workspaces)) { |
153 |
- LOG("No other container in this direction found, trying to look further up in the tree...\n"); |
154 |
- current = current->parent; |
155 |
- continue; |
156 |
- } |
157 |
- break; |
158 |
- } while (current->type != CT_WORKSPACE && |
159 |
- current->type != CT_FLOATING_CON); |
160 |
+ Con *second = NULL; |
161 |
+ Con *first = current; |
162 |
+ direction_t search_direction; |
163 |
+ if (!strcmp(direction, "left")) |
164 |
+ search_direction = D_LEFT; |
165 |
+ else if (!strcmp(direction, "right")) |
166 |
+ search_direction = D_RIGHT; |
167 |
+ else if (!strcmp(direction, "up")) |
168 |
+ search_direction = D_UP; |
169 |
+ else |
170 |
+ search_direction = D_DOWN; |
171 |
|
172 |
- if (other == NULL) { |
173 |
- LOG("No other container in this direction found, trying to look further up in the tree...\n"); |
174 |
+ bool res = resize_find_tiling_participants(&first, &second, search_direction); |
175 |
+ if (!res) { |
176 |
+ LOG("No second container in this direction found.\n"); |
177 |
ysuccess(false); |
178 |
return false; |
179 |
} |
180 |
|
181 |
- LOG("other->percent = %f\n", other->percent); |
182 |
- LOG("current->percent before = %f\n", current->percent); |
183 |
- if (current->percent == 0.0) |
184 |
- current->percent = percentage; |
185 |
- if (other->percent == 0.0) |
186 |
- other->percent = percentage; |
187 |
- double new_current_percent = current->percent + ((double)ppt / 100.0); |
188 |
- double new_other_percent = other->percent - ((double)ppt / 100.0); |
189 |
- LOG("new_current_percent = %f\n", new_current_percent); |
190 |
- LOG("new_other_percent = %f\n", new_other_percent); |
191 |
+ /* get the default percentage */ |
192 |
+ int children = con_num_children(first->parent); |
193 |
+ LOG("ins. %d children\n", children); |
194 |
+ double percentage = 1.0 / children; |
195 |
+ LOG("default percentage = %f\n", percentage); |
196 |
+ |
197 |
+ /* resize */ |
198 |
+ LOG("second->percent = %f\n", second->percent); |
199 |
+ LOG("first->percent before = %f\n", first->percent); |
200 |
+ if (first->percent == 0.0) |
201 |
+ first->percent = percentage; |
202 |
+ if (second->percent == 0.0) |
203 |
+ second->percent = percentage; |
204 |
+ double new_first_percent = first->percent + ((double)ppt / 100.0); |
205 |
+ double new_second_percent = second->percent - ((double)ppt / 100.0); |
206 |
+ LOG("new_first_percent = %f\n", new_first_percent); |
207 |
+ LOG("new_second_percent = %f\n", new_second_percent); |
208 |
/* Ensure that the new percentages are positive and greater than |
209 |
* 0.05 to have a reasonable minimum size. */ |
210 |
- if (definitelyGreaterThan(new_current_percent, 0.05, DBL_EPSILON) && |
211 |
- definitelyGreaterThan(new_other_percent, 0.05, DBL_EPSILON)) { |
212 |
- current->percent += ((double)ppt / 100.0); |
213 |
- other->percent -= ((double)ppt / 100.0); |
214 |
- LOG("current->percent after = %f\n", current->percent); |
215 |
- LOG("other->percent after = %f\n", other->percent); |
216 |
+ if (definitelyGreaterThan(new_first_percent, 0.05, DBL_EPSILON) && |
217 |
+ definitelyGreaterThan(new_second_percent, 0.05, DBL_EPSILON)) { |
218 |
+ first->percent += ((double)ppt / 100.0); |
219 |
+ second->percent -= ((double)ppt / 100.0); |
220 |
+ LOG("first->percent after = %f\n", first->percent); |
221 |
+ LOG("second->percent after = %f\n", second->percent); |
222 |
} else { |
223 |
LOG("Not resizing, already at minimum size\n"); |
224 |
} |
b/src/resize.c
229 |
@@ -51,6 +51,54 @@ DRAGGING_CB(resize_callback) { |
230 |
xcb_flush(conn); |
231 |
} |
232 |
|
233 |
+bool resize_find_tiling_participants(Con **current, Con **other, direction_t direction) { |
234 |
+ DLOG("Find two participants for resizing container=%p in direction=%i\n", other, direction); |
235 |
+ Con *first = *current; |
236 |
+ Con *second = NULL; |
237 |
+ if (first == NULL) { |
238 |
+ DLOG("Current container is NULL, aborting.\n"); |
239 |
+ return false; |
240 |
+ } |
241 |
+ |
242 |
+ /* Go up in the tree and search for a container to resize */ |
243 |
+ const orientation_t search_orientation = ((direction == D_LEFT || direction == D_RIGHT) ? HORIZ : VERT); |
244 |
+ const bool dir_backwards = (direction == D_UP || direction == D_LEFT); |
245 |
+ while (first->type != CT_WORKSPACE && |
246 |
+ first->type != CT_FLOATING_CON && |
247 |
+ second == NULL) { |
248 |
+ /* get the appropriate first container with the matching |
249 |
+ * orientation (skip stacked/tabbed cons) */ |
250 |
+ if ((con_orientation(first->parent) != search_orientation) || |
251 |
+ (first->parent->layout == L_STACKED) || |
252 |
+ (first->parent->layout == L_TABBED)) { |
253 |
+ first = first->parent; |
254 |
+ continue; |
255 |
+ } |
256 |
+ |
257 |
+ /* get the counterpart for this resizement */ |
258 |
+ if (dir_backwards) { |
259 |
+ second = TAILQ_PREV(first, nodes_head, nodes); |
260 |
+ } else { |
261 |
+ second = TAILQ_NEXT(first, nodes); |
262 |
+ } |
263 |
+ |
264 |
+ if (second == NULL) { |
265 |
+ DLOG("No second container in this direction found, trying to look further up in the tree...\n"); |
266 |
+ first = first->parent; |
267 |
+ } |
268 |
+ } |
269 |
+ |
270 |
+ DLOG("Found participants: first=%p and second=%p.", first, second); |
271 |
+ *current = first; |
272 |
+ *other = second; |
273 |
+ if (first == NULL || second == NULL) { |
274 |
+ DLOG("Could not find two participants for this resize request.\n"); |
275 |
+ return false; |
276 |
+ } |
277 |
+ |
278 |
+ return true; |
279 |
+} |
280 |
+ |
281 |
int resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event) { |
282 |
DLOG("resize handler\n"); |
283 |
|