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