Merge pull request #3372 from orestisf1993/direction

Resize tile px
This commit is contained in:
Ingo Bürk 2018-08-24 09:43:20 +02:00 committed by GitHub
commit 9a53d65e18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 459 additions and 224 deletions

View File

@ -2330,16 +2330,15 @@ resize set [width] <width> [px | ppt] [height] <height> [px | ppt]
------------------------------------------------------- -------------------------------------------------------
Direction can either be one of +up+, +down+, +left+ or +right+. Or you can be Direction can either be one of +up+, +down+, +left+ or +right+. Or you can be
less specific and use +width+ or +height+, in which case i3 will take/give less specific and use +width+ or +height+, in which case i3 will take/give space
space from all the other containers. The optional pixel argument specifies by from all the other containers. The optional pixel argument specifies by how many
how many pixels a *floating container* should be grown or shrunk (the default pixels a container should be grown or shrunk (the default is 10 pixels). The
is 10 pixels). The ppt argument means percentage points and specifies by how optional ppt argument means "percentage points", and if specified it indicates
many percentage points a *tiling container* should be grown or shrunk (the that a *tiling container* should be grown or shrunk by that many points, instead
default is 10 percentage points). of by the +px+ value.
Notes about +resize set+: a value of 0 for <width> or <height> means "do Note about +resize set+: a value of 0 for <width> or <height> means "do not
not resize in this direction", and resizing a tiling container by +px+ is not resize in this direction".
implemented.
It is recommended to define bindings for resizing in a dedicated binding mode. It is recommended to define bindings for resizing in a dedicated binding mode.
See <<binding_modes>> and the example in the i3 See <<binding_modes>> and the example in the i3

View File

@ -216,7 +216,7 @@ void cmd_sticky(I3_CMD, const char *action);
* Implementation of 'move <direction> [<pixels> [px]]'. * Implementation of 'move <direction> [<pixels> [px]]'.
* *
*/ */
void cmd_move_direction(I3_CMD, const char *direction, long move_px); void cmd_move_direction(I3_CMD, const char *direction_str, long move_px);
/** /**
* Implementation of 'layout default|stacked|stacking|tabbed|splitv|splith'. * Implementation of 'layout default|stacked|stacking|tabbed|splitv|splith'.

View File

@ -13,4 +13,20 @@
bool resize_find_tiling_participants(Con **current, Con **other, direction_t direction, bool both_sides); bool resize_find_tiling_participants(Con **current, Con **other, direction_t direction, bool both_sides);
int resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event); void resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event);
/**
* Resize the two given containers using the given amount of pixels or
* percentage points. One of the two needs to be 0. A positive amount means
* growing the first container while a negative means shrinking it.
* Returns false when the resize would result in one of the two containers
* having less than 1 pixel of size.
*
*/
bool resize_neighboring_cons(Con *first, Con *second, int px, int ppt);
/**
* Calculate the given container's new percent given a change in pixels.
*
*/
double px_resize_to_percent(Con *con, int px_diff);

View File

@ -174,3 +174,9 @@ bool parse_long(const char *str, long *out, int base);
* *
*/ */
ssize_t slurp(const char *path, char **buf); ssize_t slurp(const char *path, char **buf);
/**
* Convert a direction to its corresponding orientation.
*
*/
orientation_t orientation_from_direction(direction_t direction);

View File

@ -243,7 +243,7 @@ state RESIZE_TILING:
'or' 'or'
-> RESIZE_TILING_OR -> RESIZE_TILING_OR
end end
-> call cmd_resize($way, $direction, &resize_px, 10) -> call cmd_resize($way, $direction, &resize_px, 0)
state RESIZE_TILING_OR: state RESIZE_TILING_OR:
resize_ppt = number resize_ppt = number

View File

@ -419,110 +419,104 @@ void cmd_move_con_to_workspace_number(I3_CMD, const char *which, const char *_no
ysuccess(true); ysuccess(true);
} }
static void cmd_resize_floating(I3_CMD, const char *way, const char *direction, Con *floating_con, int px) { /*
LOG("floating resize\n"); * Convert a string direction ("left", "right", etc.) to a direction_t. Assumes
* valid direction string.
*/
static direction_t parse_direction(const char *str) {
if (strcmp(str, "left") == 0) {
return D_LEFT;
} else if (strcmp(str, "right") == 0) {
return D_RIGHT;
} else if (strcmp(str, "up") == 0) {
return D_UP;
} else if (strcmp(str, "down") == 0) {
return D_DOWN;
} else {
ELOG("Invalid direction. This is a parser bug.\n");
assert(false);
}
}
static void cmd_resize_floating(I3_CMD, const char *way, const char *direction_str, Con *floating_con, int px) {
Rect old_rect = floating_con->rect; Rect old_rect = floating_con->rect;
Con *focused_con = con_descend_focused(floating_con); Con *focused_con = con_descend_focused(floating_con);
direction_t direction;
if (strcmp(direction_str, "height") == 0) {
direction = D_DOWN;
} else if (strcmp(direction_str, "width") == 0) {
direction = D_RIGHT;
} else {
direction = parse_direction(direction_str);
}
orientation_t orientation = orientation_from_direction(direction);
/* ensure that resize will take place even if pixel increment is smaller than /* ensure that resize will take place even if pixel increment is smaller than
* height increment or width increment. * height increment or width increment.
* fixes #1011 */ * fixes #1011 */
const i3Window *window = focused_con->window; const i3Window *window = focused_con->window;
if (window != NULL) { if (window != NULL) {
if (strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0 || if (orientation == VERT) {
strcmp(direction, "height") == 0) { if (px < 0) {
if (px < 0)
px = (-px < window->height_increment) ? -window->height_increment : px; px = (-px < window->height_increment) ? -window->height_increment : px;
else } else {
px = (px < window->height_increment) ? window->height_increment : px; px = (px < window->height_increment) ? window->height_increment : px;
} else if (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0) { }
if (px < 0) } else {
if (px < 0) {
px = (-px < window->width_increment) ? -window->width_increment : px; px = (-px < window->width_increment) ? -window->width_increment : px;
else } else {
px = (px < window->width_increment) ? window->width_increment : px; px = (px < window->width_increment) ? window->width_increment : px;
}
} }
} }
if (strcmp(direction, "up") == 0) { if (orientation == VERT) {
floating_con->rect.height += px; floating_con->rect.height += px;
} else if (strcmp(direction, "down") == 0 || strcmp(direction, "height") == 0) {
floating_con->rect.height += px;
} else if (strcmp(direction, "left") == 0) {
floating_con->rect.width += px;
} else { } else {
floating_con->rect.width += px; floating_con->rect.width += px;
} }
floating_check_size(floating_con); floating_check_size(floating_con);
/* Did we actually resize anything or did the size constraints prevent us? /* Did we actually resize anything or did the size constraints prevent us?
* If we could not resize, exit now to not move the window. */ * If we could not resize, exit now to not move the window. */
if (memcmp(&old_rect, &(floating_con->rect), sizeof(Rect)) == 0) if (memcmp(&old_rect, &(floating_con->rect), sizeof(Rect)) == 0) {
return; return;
}
if (strcmp(direction, "up") == 0) { if (direction == D_UP) {
floating_con->rect.y -= (floating_con->rect.height - old_rect.height); floating_con->rect.y -= (floating_con->rect.height - old_rect.height);
} else if (strcmp(direction, "left") == 0) { } else if (direction == D_LEFT) {
floating_con->rect.x -= (floating_con->rect.width - old_rect.width); floating_con->rect.x -= (floating_con->rect.width - old_rect.width);
} }
/* If this is a scratchpad window, don't auto center it from now on. */ /* If this is a scratchpad window, don't auto center it from now on. */
if (floating_con->scratchpad_state == SCRATCHPAD_FRESH) if (floating_con->scratchpad_state == SCRATCHPAD_FRESH) {
floating_con->scratchpad_state = SCRATCHPAD_CHANGED; floating_con->scratchpad_state = SCRATCHPAD_CHANGED;
}
} }
static bool cmd_resize_tiling_direction(I3_CMD, Con *current, const char *way, const char *direction, int ppt) { static bool cmd_resize_tiling_direction(I3_CMD, Con *current, const char *direction, int px, int ppt) {
LOG("tiling resize\n");
Con *second = NULL; Con *second = NULL;
Con *first = current; Con *first = current;
direction_t search_direction; direction_t search_direction = parse_direction(direction);
if (!strcmp(direction, "left"))
search_direction = D_LEFT;
else if (!strcmp(direction, "right"))
search_direction = D_RIGHT;
else if (!strcmp(direction, "up"))
search_direction = D_UP;
else
search_direction = D_DOWN;
bool res = resize_find_tiling_participants(&first, &second, search_direction, false); bool res = resize_find_tiling_participants(&first, &second, search_direction, false);
if (!res) { if (!res) {
LOG("No second container in this direction found.\n"); yerror("No second container found in this direction.\n");
ysuccess(false);
return false; return false;
} }
/* get the default percentage */ if (ppt) {
int children = con_num_children(first->parent); /* For backwards compatibility, 'X px or Y ppt' means that ppt is
LOG("ins. %d children\n", children); * preferred. */
double percentage = 1.0 / children; px = 0;
LOG("default percentage = %f\n", percentage);
/* resize */
LOG("first->percent before = %f\n", first->percent);
LOG("second->percent before = %f\n", second->percent);
if (first->percent == 0.0)
first->percent = percentage;
if (second->percent == 0.0)
second->percent = percentage;
double new_first_percent = first->percent + ((double)ppt / 100.0);
double new_second_percent = second->percent - ((double)ppt / 100.0);
LOG("new_first_percent = %f\n", new_first_percent);
LOG("new_second_percent = %f\n", new_second_percent);
/* Ensure that the new percentages are positive. */
if (new_first_percent > 0.0 && new_second_percent > 0.0) {
first->percent = new_first_percent;
second->percent = new_second_percent;
LOG("first->percent after = %f\n", first->percent);
LOG("second->percent after = %f\n", second->percent);
} else {
LOG("Not resizing, already at minimum size\n");
} }
return resize_neighboring_cons(first, second, px, ppt);
return true;
} }
static bool cmd_resize_tiling_width_height(I3_CMD, Con *current, const char *way, const char *direction, int ppt) { static bool cmd_resize_tiling_width_height(I3_CMD, Con *current, const char *direction, int px, double ppt) {
LOG("width/height resize\n"); LOG("width/height resize\n");
/* get the appropriate current container (skip stacked/tabbed cons) */ /* get the appropriate current container (skip stacked/tabbed cons) */
@ -548,8 +542,16 @@ static bool cmd_resize_tiling_width_height(I3_CMD, Con *current, const char *way
child->percent = percentage; child->percent = percentage;
} }
double new_current_percent = current->percent + ((double)ppt / 100.0); double new_current_percent;
double subtract_percent = ((double)ppt / 100.0) / (children - 1); double subtract_percent;
if (ppt != 0.0) {
new_current_percent = current->percent + ppt;
} else {
new_current_percent = px_resize_to_percent(current, px);
ppt = new_current_percent - current->percent;
}
subtract_percent = ppt / (children - 1);
LOG("new_current_percent = %f\n", new_current_percent); LOG("new_current_percent = %f\n", new_current_percent);
LOG("subtract_percent = %f\n", subtract_percent); LOG("subtract_percent = %f\n", subtract_percent);
/* Ensure that the new percentages are positive. */ /* Ensure that the new percentages are positive. */
@ -608,12 +610,15 @@ void cmd_resize(I3_CMD, const char *way, const char *direction, long resize_px,
} else { } else {
if (strcmp(direction, "width") == 0 || if (strcmp(direction, "width") == 0 ||
strcmp(direction, "height") == 0) { strcmp(direction, "height") == 0) {
const double ppt = (double)resize_ppt / 100.0;
if (!cmd_resize_tiling_width_height(current_match, cmd_output, if (!cmd_resize_tiling_width_height(current_match, cmd_output,
current->con, way, direction, resize_ppt)) current->con, direction,
resize_px, ppt))
return; return;
} else { } else {
if (!cmd_resize_tiling_direction(current_match, cmd_output, if (!cmd_resize_tiling_direction(current_match, cmd_output,
current->con, way, direction, resize_ppt)) current->con, direction,
resize_px, resize_ppt))
return; return;
} }
} }
@ -624,6 +629,35 @@ void cmd_resize(I3_CMD, const char *way, const char *direction, long resize_px,
ysuccess(true); ysuccess(true);
} }
static bool resize_set_tiling(I3_CMD, Con *target, orientation_t resize_orientation, bool is_ppt, long target_size) {
direction_t search_direction;
char *mode;
if (resize_orientation == HORIZ) {
search_direction = D_LEFT;
mode = "width";
} else {
search_direction = D_DOWN;
mode = "height";
}
/* Get the appropriate current container (skip stacked/tabbed cons) */
Con *dummy;
resize_find_tiling_participants(&target, &dummy, search_direction, true);
/* Calculate new size for the target container */
double ppt = 0.0;
int px = 0;
if (is_ppt) {
ppt = (double)target_size / 100.0 - target->percent;
} else {
px = target_size - (resize_orientation == HORIZ ? target->rect.width : target->rect.height);
}
/* Perform resizing and report failure if not possible */
return cmd_resize_tiling_width_height(current_match, cmd_output,
target, mode, px, ppt);
}
/* /*
* Implementation of 'resize set <width> [px | ppt] <height> [px | ppt]'. * Implementation of 'resize set <width> [px | ppt] <height> [px | ppt]'.
* *
@ -660,56 +694,13 @@ void cmd_resize_set(I3_CMD, long cwidth, const char *mode_width, long cheight, c
continue; continue;
} }
if (cwidth > 0 && mode_width && strcmp(mode_width, "ppt") == 0) { if (cwidth > 0 && mode_width) {
/* get the appropriate current container (skip stacked/tabbed cons) */ success &= resize_set_tiling(current_match, cmd_output, current->con,
Con *target = current->con; HORIZ, strcmp(mode_width, "ppt") == 0, cwidth);
Con *dummy;
resize_find_tiling_participants(&target, &dummy, D_LEFT, true);
/* Calculate new size for the target container */
double current_percent = target->percent;
char *action_string;
long adjustment;
if (current_percent > cwidth) {
action_string = "shrink";
adjustment = (int)(current_percent * 100) - cwidth;
} else {
action_string = "grow";
adjustment = cwidth - (int)(current_percent * 100);
}
/* perform resizing and report failure if not possible */
if (!cmd_resize_tiling_width_height(current_match, cmd_output,
target, action_string, "width", adjustment)) {
success = false;
}
} }
if (cheight > 0 && mode_height) {
if (cheight > 0 && mode_height && strcmp(mode_height, "ppt") == 0) { success &= resize_set_tiling(current_match, cmd_output, current->con,
/* get the appropriate current container (skip stacked/tabbed cons) */ VERT, strcmp(mode_height, "ppt") == 0, cheight);
Con *target = current->con;
Con *dummy;
resize_find_tiling_participants(&target, &dummy, D_DOWN, true);
/* Calculate new size for the target container */
double current_percent = target->percent;
char *action_string;
long adjustment;
if (current_percent > cheight) {
action_string = "shrink";
adjustment = (int)(current_percent * 100) - cheight;
} else {
action_string = "grow";
adjustment = cheight - (int)(current_percent * 100);
}
/* perform resizing and report failure if not possible */
if (!cmd_resize_tiling_width_height(current_match, cmd_output,
target, action_string, "height", adjustment)) {
success = false;
}
} }
} }
} }
@ -1254,20 +1245,19 @@ void cmd_exec(I3_CMD, const char *nosn, const char *command) {
* *
*/ */
void cmd_focus_direction(I3_CMD, const char *direction) { void cmd_focus_direction(I3_CMD, const char *direction) {
DLOG("direction = *%s*\n", direction); switch (parse_direction(direction)) {
case D_LEFT:
if (strcmp(direction, "left") == 0) tree_next('p', HORIZ);
tree_next('p', HORIZ); break;
else if (strcmp(direction, "right") == 0) case D_RIGHT:
tree_next('n', HORIZ); tree_next('n', HORIZ);
else if (strcmp(direction, "up") == 0) break;
tree_next('p', VERT); case D_UP:
else if (strcmp(direction, "down") == 0) tree_next('p', VERT);
tree_next('n', VERT); break;
else { case D_DOWN:
ELOG("Invalid focus direction (%s)\n", direction); tree_next('n', VERT);
ysuccess(false); break;
return;
} }
cmd_output->needs_tree_render = true; cmd_output->needs_tree_render = true;
@ -1492,29 +1482,37 @@ void cmd_sticky(I3_CMD, const char *action) {
* Implementation of 'move <direction> [<pixels> [px]]'. * Implementation of 'move <direction> [<pixels> [px]]'.
* *
*/ */
void cmd_move_direction(I3_CMD, const char *direction, long move_px) { void cmd_move_direction(I3_CMD, const char *direction_str, long move_px) {
owindow *current; owindow *current;
HANDLE_EMPTY_MATCH; HANDLE_EMPTY_MATCH;
Con *initially_focused = focused; Con *initially_focused = focused;
direction_t direction = parse_direction(direction_str);
TAILQ_FOREACH(current, &owindows, owindows) { TAILQ_FOREACH(current, &owindows, owindows) {
DLOG("moving in direction %s, px %ld\n", direction, move_px); DLOG("moving in direction %s, px %ld\n", direction_str, move_px);
if (con_is_floating(current->con)) { if (con_is_floating(current->con)) {
DLOG("floating move with %ld pixels\n", move_px); DLOG("floating move with %ld pixels\n", move_px);
Rect newrect = current->con->parent->rect; Rect newrect = current->con->parent->rect;
if (strcmp(direction, "left") == 0) {
newrect.x -= move_px; switch (direction) {
} else if (strcmp(direction, "right") == 0) { case D_LEFT:
newrect.x += move_px; newrect.x -= move_px;
} else if (strcmp(direction, "up") == 0) { break;
newrect.y -= move_px; case D_RIGHT:
} else if (strcmp(direction, "down") == 0) { newrect.x += move_px;
newrect.y += move_px; break;
case D_UP:
newrect.y -= move_px;
break;
case D_DOWN:
newrect.y += move_px;
break;
} }
floating_reposition(current->con->parent, newrect); floating_reposition(current->con->parent, newrect);
} else { } else {
tree_move(current->con, (strcmp(direction, "right") == 0 ? D_RIGHT : (strcmp(direction, "left") == 0 ? D_LEFT : (strcmp(direction, "up") == 0 ? D_UP : D_DOWN)))); tree_move(current->con, direction);
cmd_output->needs_tree_render = true; cmd_output->needs_tree_render = true;
} }
} }

View File

@ -265,7 +265,7 @@ void tree_move(Con *con, int direction) {
return; return;
} }
orientation_t o = (direction == D_LEFT || direction == D_RIGHT ? HORIZ : VERT); orientation_t o = orientation_from_direction(direction);
Con *same_orientation = con_parent_with_orientation(con, o); Con *same_orientation = con_parent_with_orientation(con, o);
/* The do {} while is used to 'restart' at this point with a different /* The do {} while is used to 'restart' at this point with a different

View File

@ -183,26 +183,28 @@ free_params:
} }
static int *precalculate_sizes(Con *con, render_params *p) { static int *precalculate_sizes(Con *con, render_params *p) {
int *sizes = smalloc(p->children * sizeof(int)); if ((con->layout != L_SPLITH && con->layout != L_SPLITV) || p->children <= 0) {
if ((con->layout == L_SPLITH || con->layout == L_SPLITV) && p->children > 0) { return NULL;
assert(!TAILQ_EMPTY(&con->nodes_head)); }
Con *child; int *sizes = smalloc(p->children * sizeof(int));
int i = 0, assigned = 0; assert(!TAILQ_EMPTY(&con->nodes_head));
int total = con_orientation(con) == HORIZ ? p->rect.width : p->rect.height;
TAILQ_FOREACH(child, &(con->nodes_head), nodes) { Con *child;
double percentage = child->percent > 0.0 ? child->percent : 1.0 / p->children; int i = 0, assigned = 0;
assigned += sizes[i++] = percentage * total; int total = con_orientation(con) == HORIZ ? p->rect.width : p->rect.height;
} TAILQ_FOREACH(child, &(con->nodes_head), nodes) {
assert(assigned == total || double percentage = child->percent > 0.0 ? child->percent : 1.0 / p->children;
(assigned > total && assigned - total <= p->children * 2) || assigned += sizes[i++] = lround(percentage * total);
(assigned < total && total - assigned <= p->children * 2)); }
int signal = assigned < total ? 1 : -1; assert(assigned == total ||
while (assigned != total) { (assigned > total && assigned - total <= p->children * 2) ||
for (i = 0; i < p->children && assigned != total; ++i) { (assigned < total && total - assigned <= p->children * 2));
sizes[i] += signal; int signal = assigned < total ? 1 : -1;
assigned += signal; while (assigned != total) {
} for (i = 0; i < p->children && assigned != total; ++i) {
sizes[i] += signal;
assigned += signal;
} }
} }

View File

@ -57,7 +57,7 @@ bool resize_find_tiling_participants(Con **current, Con **other, direction_t dir
} }
/* Go up in the tree and search for a container to resize */ /* Go up in the tree and search for a container to resize */
const orientation_t search_orientation = ((direction == D_LEFT || direction == D_RIGHT) ? HORIZ : VERT); const orientation_t search_orientation = orientation_from_direction(direction);
const bool dir_backwards = (direction == D_UP || direction == D_LEFT); const bool dir_backwards = (direction == D_UP || direction == D_LEFT);
while (first->type != CT_WORKSPACE && while (first->type != CT_WORKSPACE &&
first->type != CT_FLOATING_CON && first->type != CT_FLOATING_CON &&
@ -101,10 +101,55 @@ bool resize_find_tiling_participants(Con **current, Con **other, direction_t dir
return true; return true;
} }
int resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event) { /*
DLOG("resize handler\n"); * Calculate the given container's new percent given a change in pixels.
*
*/
double px_resize_to_percent(Con *con, int px_diff) {
Con *parent = con->parent;
const orientation_t o = con_orientation(parent);
const int total = (o == HORIZ ? parent->rect.width : parent->rect.height);
/* deco_rect.height is subtracted from each child in render_con_split */
const int target = px_diff + (o == HORIZ ? con->rect.width : con->rect.height + con->deco_rect.height);
return ((double)target / (double)total);
}
/* TODO: previously, we were getting a rect containing all screens. why? */ /*
* Resize the two given containers using the given amount of pixels or
* percentage points. One of the two needs to be 0. A positive amount means
* growing the first container while a negative means shrinking it.
* Returns false when the resize would result in one of the two containers
* having less than 1 pixel of size.
*
*/
bool resize_neighboring_cons(Con *first, Con *second, int px, int ppt) {
assert(px * ppt == 0);
Con *parent = first->parent;
orientation_t orientation = con_orientation(parent);
const int total = (orientation == HORIZ ? parent->rect.width : parent->rect.height);
double new_first_percent;
double new_second_percent;
if (ppt) {
new_first_percent = first->percent + ((double)ppt / 100.0);
new_second_percent = second->percent - ((double)ppt / 100.0);
} else {
new_first_percent = px_resize_to_percent(first, px);
new_second_percent = second->percent + first->percent - new_first_percent;
}
/* Ensure that no container will be less than 1 pixel in the resizing
* direction. */
if (lround(new_first_percent * total) <= 0 || lround(new_second_percent * total) <= 0) {
return false;
}
first->percent = new_first_percent;
second->percent = new_second_percent;
con_fix_percent(parent);
return true;
}
void resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event) {
Con *output = con_get_output(first); Con *output = con_get_output(first);
DLOG("x = %d, width = %d\n", output->rect.x, output->rect.width); DLOG("x = %d, width = %d\n", output->rect.x, output->rect.width);
@ -117,29 +162,27 @@ int resize_graphical_handler(Con *first, Con *second, orientation_t orientation,
mask = XCB_CW_OVERRIDE_REDIRECT; mask = XCB_CW_OVERRIDE_REDIRECT;
values[0] = 1; values[0] = 1;
/* Open a new window, the resizebar. Grab the pointer and move the window around /* Open a new window, the resizebar. Grab the pointer and move the window
as the user moves the pointer. */ * around as the user moves the pointer. */
xcb_window_t grabwin = create_window(conn, output->rect, XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT, xcb_window_t grabwin = create_window(conn, output->rect, XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT,
XCB_WINDOW_CLASS_INPUT_ONLY, XCURSOR_CURSOR_POINTER, true, mask, values); XCB_WINDOW_CLASS_INPUT_ONLY, XCURSOR_CURSOR_POINTER, true, mask, values);
/* Keep track of the coordinate orthogonal to motion so we can determine /* Keep track of the coordinate orthogonal to motion so we can determine the
* the length of the resize afterward. */ * length of the resize afterward. */
uint32_t initial_position, new_position; uint32_t initial_position, new_position;
/* Configure the resizebar and snap the pointer. The resizebar runs along /* Configure the resizebar and snap the pointer. The resizebar runs along
* the rect of the second con and follows the motion of the pointer. */ * the rect of the second con and follows the motion of the pointer. */
Rect helprect; Rect helprect;
helprect.x = second->rect.x;
helprect.y = second->rect.y;
if (orientation == HORIZ) { if (orientation == HORIZ) {
helprect.x = second->rect.x;
helprect.y = second->rect.y;
helprect.width = logical_px(2); helprect.width = logical_px(2);
helprect.height = second->rect.height; helprect.height = second->rect.height;
initial_position = second->rect.x; initial_position = second->rect.x;
xcb_warp_pointer(conn, XCB_NONE, event->root, 0, 0, 0, 0, xcb_warp_pointer(conn, XCB_NONE, event->root, 0, 0, 0, 0,
second->rect.x, event->root_y); second->rect.x, event->root_y);
} else { } else {
helprect.x = second->rect.x;
helprect.y = second->rect.y;
helprect.width = second->rect.width; helprect.width = second->rect.width;
helprect.height = logical_px(2); helprect.height = logical_px(2);
initial_position = second->rect.y; initial_position = second->rect.y;
@ -173,37 +216,17 @@ int resize_graphical_handler(Con *first, Con *second, orientation_t orientation,
xcb_flush(conn); xcb_flush(conn);
/* User cancelled the drag so no action should be taken. */ /* User cancelled the drag so no action should be taken. */
if (drag_result == DRAG_REVERT) if (drag_result == DRAG_REVERT) {
return 0; return;
}
int pixels = (new_position - initial_position); int pixels = (new_position - initial_position);
DLOG("Done, pixels = %d\n", pixels); DLOG("Done, pixels = %d\n", pixels);
// if we got thus far, the containers must have /* if we got thus far, the containers must have valid percentages. */
// percentages associated with them
assert(first->percent > 0.0); assert(first->percent > 0.0);
assert(second->percent > 0.0); assert(second->percent > 0.0);
const bool result = resize_neighboring_cons(first, second, pixels, 0);
// calculate the new percentage for the first container DLOG("Graphical resize %s: first->percent = %f, second->percent = %f.\n",
double new_percent, difference; result ? "successful" : "failed", first->percent, second->percent);
double percent = first->percent;
DLOG("percent = %f\n", percent);
int original = (orientation == HORIZ ? first->rect.width : first->rect.height);
DLOG("original = %d\n", original);
new_percent = (original + pixels) * (percent / original);
difference = percent - new_percent;
DLOG("difference = %f\n", difference);
DLOG("new percent = %f\n", new_percent);
first->percent = new_percent;
// calculate the new percentage for the second container
double s_percent = second->percent;
second->percent = s_percent + difference;
DLOG("second->percent = %f\n", second->percent);
// now we must make sure that the sum of the percentages remain 1.0
con_fix_percent(first->parent);
return 0;
} }

View File

@ -507,3 +507,11 @@ ssize_t slurp(const char *path, char **buf) {
} }
return (ssize_t)n; return (ssize_t)n;
} }
/*
* Convert a direction to its corresponding orientation.
*
*/
orientation_t orientation_from_direction(direction_t direction) {
return (direction == D_LEFT || direction == D_RIGHT) ? HORIZ : VERT;
}

View File

@ -141,6 +141,147 @@ cmp_float($nodes->[1]->{percent}, 0.166666666666667, 'second window got 16%');
cmp_float($nodes->[2]->{percent}, 0.166666666666667, 'third window got 16%'); cmp_float($nodes->[2]->{percent}, 0.166666666666667, 'third window got 16%');
cmp_float($nodes->[3]->{percent}, 0.50, 'fourth window got 50%'); cmp_float($nodes->[3]->{percent}, 0.50, 'fourth window got 50%');
################################################################################
# Same but using pixels instead of ppt.
################################################################################
# Use two windows
$tmp = fresh_workspace;
$left = open_window;
$right = open_window;
($nodes, $focus) = get_ws_content($tmp);
my @widths = ($nodes->[0]->{rect}->{width}, $nodes->[1]->{rect}->{width});
cmd 'resize grow width 10 px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{rect}->{width}, $widths[0] - 10, 'left window is 10px smaller');
cmp_float($nodes->[1]->{rect}->{width}, $widths[1] + 10, 'right window is 10px larger');
# Now test it with four windows
$tmp = fresh_workspace;
open_window for (1..4);
($nodes, $focus) = get_ws_content($tmp);
my $width = $nodes->[0]->{rect}->{width};
cmd 'resize grow width 10 px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[3]->{rect}->{width}, $width + 10, 'last window is 10px larger');
################################################################################
# Same but for height
################################################################################
# Use two windows
$tmp = fresh_workspace;
cmd 'split v';
$left = open_window;
$right = open_window;
($nodes, $focus) = get_ws_content($tmp);
my @heights = ($nodes->[0]->{rect}->{height}, $nodes->[1]->{rect}->{height});
cmd 'resize grow height 10 px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{rect}->{height}, $heights[0] - 10, 'left window is 10px smaller');
cmp_float($nodes->[1]->{rect}->{height}, $heights[1] + 10, 'right window is 10px larger');
# Now test it with four windows
$tmp = fresh_workspace;
cmd 'split v';
open_window for (1..4);
($nodes, $focus) = get_ws_content($tmp);
my $height = $nodes->[0]->{rect}->{height};
cmd 'resize grow height 10 px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[3]->{rect}->{height}, $height + 10, 'last window is 10px larger');
################################################################################
# Check that we can grow tiled windows by pixels
################################################################################
$tmp = fresh_workspace;
$left = open_window;
$right = open_window;
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{rect}->{width}, 640, 'left window is 640px');
cmp_float($nodes->[1]->{rect}->{width}, 640, 'right window is 640px');
cmd 'resize grow left 10px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{rect}->{width}, 630, 'left window is 630px');
cmp_float($nodes->[1]->{rect}->{width}, 650, 'right window is 650px');
################################################################################
# Check that we can shrink tiled windows by pixels
################################################################################
$tmp = fresh_workspace;
$left = open_window;
$right = open_window;
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{rect}->{width}, 640, 'left window is 640px');
cmp_float($nodes->[1]->{rect}->{width}, 640, 'right window is 640px');
cmd 'resize shrink left 10px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{rect}->{width}, 650, 'left window is 650px');
cmp_float($nodes->[1]->{rect}->{width}, 630, 'right window is 630px');
################################################################################
# Check that we can shrink vertical tiled windows by pixels
################################################################################
$tmp = fresh_workspace;
cmd 'split v';
$top = open_window;
$bottom = open_window;
($nodes, $focus) = get_ws_content($tmp);
my @heights = ($nodes->[0]->{rect}->{height}, $nodes->[1]->{rect}->{height});
cmd 'resize grow up 10px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{rect}->{height}, $heights[0] - 10, 'top window is 10px larger');
cmp_float($nodes->[1]->{rect}->{height}, $heights[1] + 10, 'bottom window is 10px smaller');
################################################################################
# Check that we can shrink vertical tiled windows by pixels
################################################################################
$tmp = fresh_workspace;
cmd 'split v';
$top = open_window;
$bottom = open_window;
($nodes, $focus) = get_ws_content($tmp);
my @heights = ($nodes->[0]->{rect}->{height}, $nodes->[1]->{rect}->{height});
cmd 'resize shrink up 10px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{rect}->{height}, $heights[0] + 10, 'top window is 10px smaller');
cmp_float($nodes->[1]->{rect}->{height}, $heights[1] - 10, 'bottom window is 10px larger');
################################################################################ ################################################################################
# Check that the resize grow/shrink width/height syntax works if a nested split # Check that the resize grow/shrink width/height syntax works if a nested split
# was set on the container, but no sibling has been opened yet. See #2015. # was set on the container, but no sibling has been opened yet. See #2015.

View File

@ -86,9 +86,9 @@ is(parser_calls(
'resize shrink left 25 px or 33 ppt; ' . 'resize shrink left 25 px or 33 ppt; ' .
'resize shrink left 25'), 'resize shrink left 25'),
"cmd_resize(shrink, left, 10, 10)\n" . "cmd_resize(shrink, left, 10, 10)\n" .
"cmd_resize(shrink, left, 25, 10)\n" . "cmd_resize(shrink, left, 25, 0)\n" .
"cmd_resize(shrink, left, 25, 33)\n" . "cmd_resize(shrink, left, 25, 33)\n" .
"cmd_resize(shrink, left, 25, 10)", "cmd_resize(shrink, left, 25, 0)",
'simple resize ok'); 'simple resize ok');
is(parser_calls('resize shrink left 25 px or 33 ppt,'), is(parser_calls('resize shrink left 25 px or 33 ppt,'),

View File

@ -47,11 +47,18 @@ cmd 'resize set width 80 ppt';
cmp_float($nodes->[0]->{percent}, 0.20, 'left window got 20%'); cmp_float($nodes->[0]->{percent}, 0.20, 'left window got 20%');
cmp_float($nodes->[1]->{percent}, 0.80, 'right window got 80%'); cmp_float($nodes->[1]->{percent}, 0.80, 'right window got 80%');
# Same but with px.
cmd 'resize set width 200 px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[1]->{rect}->{width}, 200, 'right window got 200 px');
############################################################ ############################################################
# resize vertically # resize vertically
############################################################ ############################################################
my $tmp = fresh_workspace; $tmp = fresh_workspace;
cmd 'split v'; cmd 'split v';
@ -64,7 +71,7 @@ is($x->input_focus, $bottom->id, 'Bottom window focused');
cmd 'resize set 0 ppt 75 ppt'; cmd 'resize set 0 ppt 75 ppt';
my ($nodes, $focus) = get_ws_content($tmp); ($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{percent}, 0.25, 'top window got only 25%'); cmp_float($nodes->[0]->{percent}, 0.25, 'top window got only 25%');
cmp_float($nodes->[1]->{percent}, 0.75, 'bottom window got 75%'); cmp_float($nodes->[1]->{percent}, 0.75, 'bottom window got 75%');
@ -77,14 +84,21 @@ cmd 'resize set height 80 ppt';
cmp_float($nodes->[0]->{percent}, 0.20, 'top window got 20%'); cmp_float($nodes->[0]->{percent}, 0.20, 'top window got 20%');
cmp_float($nodes->[1]->{percent}, 0.80, 'bottom window got 80%'); cmp_float($nodes->[1]->{percent}, 0.80, 'bottom window got 80%');
# Same but with px.
cmd 'resize set height 200 px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[1]->{rect}->{height}, 200, 'bottom window got 200 px');
############################################################ ############################################################
# resize horizontally and vertically # resize horizontally and vertically
############################################################ ############################################################
my $tmp = fresh_workspace; $tmp = fresh_workspace;
cmd 'split h'; cmd 'split h';
my $left = open_window; $left = open_window;
my $top_right = open_window; my $top_right = open_window;
cmd 'split v'; cmd 'split v';
my $bottom_right = open_window; my $bottom_right = open_window;
@ -95,23 +109,39 @@ is($x->input_focus, $bottom_right->id, 'Bottom-right window focused');
cmd 'resize set 75 ppt 75 ppt'; cmd 'resize set 75 ppt 75 ppt';
my ($nodes, $focus) = get_ws_content($tmp); ($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{percent}, 0.25, 'left container got 25%'); cmp_float($nodes->[0]->{percent}, 0.25, 'left container got 25%');
cmp_float($nodes->[1]->{percent}, 0.75, 'right container got 75%'); cmp_float($nodes->[1]->{percent}, 0.75, 'right container got 75%');
cmp_float($nodes->[1]->{nodes}->[0]->{percent}, 0.25, 'top-right window got 25%'); cmp_float($nodes->[1]->{nodes}->[0]->{percent}, 0.25, 'top-right window got 25%');
cmp_float($nodes->[1]->{nodes}->[1]->{percent}, 0.75, 'bottom-right window got 75%'); cmp_float($nodes->[1]->{nodes}->[1]->{percent}, 0.75, 'bottom-right window got 75%');
# Same but with px.
cmd 'resize set 155 px 135 px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[1]->{nodes}->[1]->{rect}->{width}, 155, 'bottom-right window got 155 px width');
cmp_float($nodes->[1]->{nodes}->[1]->{rect}->{height}, 135, 'bottom-right window got 135 px height');
# Mix ppt and px
cmd 'resize set 75 ppt 200 px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{percent}, 0.25, 'left container got 25%');
cmp_float($nodes->[1]->{percent}, 0.75, 'right container got 75%');
cmp_float($nodes->[1]->{nodes}->[1]->{rect}->{height}, 200, 'bottom-right window got 200 px height');
############################################################ ############################################################
# resize from inside a tabbed container # resize from inside a tabbed container
############################################################ ############################################################
my $tmp = fresh_workspace; $tmp = fresh_workspace;
cmd 'split h'; cmd 'split h';
my $left = open_window; $left = open_window;
my $right1 = open_window; my $right1 = open_window;
cmd 'split h'; cmd 'split h';
@ -125,27 +155,33 @@ is($x->input_focus, $right2->id, '2nd right window focused');
cmd 'resize set 75 ppt 0 ppt'; cmd 'resize set 75 ppt 0 ppt';
my ($nodes, $focus) = get_ws_content($tmp); ($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{percent}, 0.25, 'left container got 25%'); cmp_float($nodes->[0]->{percent}, 0.25, 'left container got 25%');
cmp_float($nodes->[1]->{percent}, 0.75, 'right container got 75%'); cmp_float($nodes->[1]->{percent}, 0.75, 'right container got 75%');
# Same but with px.
cmd 'resize set 155 px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[1]->{rect}->{width}, 155, 'right container got 155 px');
############################################################ ############################################################
# resize from inside a stacked container # resize from inside a stacked container
############################################################ ############################################################
my $tmp = fresh_workspace; $tmp = fresh_workspace;
cmd 'split h'; cmd 'split h';
my $left = open_window; $left = open_window;
my $right1 = open_window; $right1 = open_window;
cmd 'split h'; cmd 'split h';
cmd 'layout stacked'; cmd 'layout stacked';
my $right2 = open_window; $right2 = open_window;
diag("left = " . $left->id . ", right1 = " . $right1->id . ", right2 = " . $right2->id); diag("left = " . $left->id . ", right1 = " . $right1->id . ", right2 = " . $right2->id);
@ -153,10 +189,16 @@ is($x->input_focus, $right2->id, '2nd right window focused');
cmd 'resize set 75 ppt 0 ppt'; cmd 'resize set 75 ppt 0 ppt';
my ($nodes, $focus) = get_ws_content($tmp); ($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{percent}, 0.25, 'left container got 25%'); cmp_float($nodes->[0]->{percent}, 0.25, 'left container got 25%');
cmp_float($nodes->[1]->{percent}, 0.75, 'right container got 75%'); cmp_float($nodes->[1]->{percent}, 0.75, 'right container got 75%');
# Same but with px.
cmd 'resize set 130 px';
($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[1]->{rect}->{width}, 130, 'right container got 130 px');
done_testing; done_testing;