From dbec5eb90585bc22752331f51d8a6bc90d21889c Mon Sep 17 00:00:00 2001 From: jj Date: Tue, 24 Sep 2013 15:46:58 +0200 Subject: [PATCH] Fix keyboard and mouse resize in nested containers fixes #1084 fixes #1085 --- include/resize.h | 2 + src/click.c | 56 +++++++++++++------------- src/commands.c | 103 +++++++++++++++++------------------------------ src/resize.c | 48 ++++++++++++++++++++++ 4 files changed, 114 insertions(+), 95 deletions(-) diff --git a/include/resize.h b/include/resize.h index fa0216c8..ae26ee99 100644 --- a/include/resize.h +++ b/include/resize.h @@ -10,6 +10,8 @@ #ifndef I3_RESIZE_H #define I3_RESIZE_H +bool resize_find_tiling_participants(Con **current, Con **other, direction_t direction); + int resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event); #endif diff --git a/src/click.c b/src/click.c index 3022c248..340c8414 100644 --- a/src/click.c +++ b/src/click.c @@ -28,45 +28,43 @@ typedef enum { CLICK_BORDER = 0, CLICK_DECORATION = 1, CLICK_INSIDE = 2 } click_ */ static bool tiling_resize_for_border(Con *con, border_t border, xcb_button_press_event_t *event) { DLOG("border = %d, con = %p\n", border, con); - char way = (border == BORDER_TOP || border == BORDER_LEFT ? 'p' : 'n'); - orientation_t orientation = (border == BORDER_TOP || border == BORDER_BOTTOM ? VERT : HORIZ); - - /* look for a parent container with the right orientation */ - Con *first = NULL, *second = NULL; - Con *resize_con = con; - while (resize_con->type != CT_WORKSPACE && - resize_con->type != CT_FLOATING_CON && - con_orientation(resize_con->parent) != orientation) - resize_con = resize_con->parent; - - DLOG("resize_con = %p\n", resize_con); - if (resize_con->type != CT_WORKSPACE && - resize_con->type != CT_FLOATING_CON && - con_orientation(resize_con->parent) == orientation) { - first = resize_con; - second = (way == 'n') ? TAILQ_NEXT(first, nodes) : TAILQ_PREV(first, nodes_head, nodes); - if (second == TAILQ_END(&(first->nodes_head))) { - second = NULL; - } - else if (way == 'p') { - Con *tmp = first; - first = second; - second = tmp; - } - DLOG("first = %p, second = %p, resize_con = %p\n", - first, second, resize_con); + Con *second = NULL; + Con *first = con; + direction_t search_direction; + switch (border) { + case BORDER_LEFT: + search_direction = D_LEFT; + break; + case BORDER_RIGHT: + search_direction = D_RIGHT; + break; + case BORDER_TOP: + search_direction = D_UP; + break; + case BORDER_BOTTOM: + search_direction = D_DOWN; + break; } - if (first == NULL || second == NULL) { - DLOG("Resize not possible\n"); + bool res = resize_find_tiling_participants(&first, &second, search_direction); + if (!res) { + LOG("No second container in this direction found.\n"); return false; } assert(first != second); assert(first->parent == second->parent); + /* The first container should always be in front of the second container */ + if (search_direction == D_UP || search_direction == D_LEFT) { + Con *tmp = first; + first = second; + second = tmp; + } + /* We modify the X/Y position in the event so that the divider line is at * the actual position of the border, not at the position of the click. */ + const orientation_t orientation = ((border == BORDER_LEFT || border == BORDER_RIGHT) ? HORIZ : VERT); if (orientation == HORIZ) event->root_x = second->rect.x; else event->root_y = second->rect.y; diff --git a/src/commands.c b/src/commands.c index 8f355795..9631923d 100644 --- a/src/commands.c +++ b/src/commands.c @@ -616,79 +616,50 @@ static void cmd_resize_floating(I3_CMD, char *way, char *direction, Con *floatin static bool cmd_resize_tiling_direction(I3_CMD, Con *current, char *way, char *direction, int ppt) { LOG("tiling resize\n"); - /* get the appropriate current container (skip stacked/tabbed cons) */ - Con *other = NULL; - double percentage = 0; - while (current->parent->layout == L_STACKED || - current->parent->layout == L_TABBED) - current = current->parent; - - /* Then further go up until we find one with the matching orientation. */ - orientation_t search_orientation = - (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0 ? HORIZ : VERT); - - do { - if (con_orientation(current->parent) != search_orientation) { - current = current->parent; - continue; - } - - /* get the default percentage */ - int children = con_num_children(current->parent); - LOG("ins. %d children\n", children); - percentage = 1.0 / children; - LOG("default percentage = %f\n", percentage); - - orientation_t orientation = con_orientation(current->parent); - - if ((orientation == HORIZ && - (strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0)) || - (orientation == VERT && - (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0))) { - LOG("You cannot resize in that direction. Your focus is in a %s split container currently.\n", - (orientation == HORIZ ? "horizontal" : "vertical")); - ysuccess(false); - return false; - } - - if (strcmp(direction, "up") == 0 || strcmp(direction, "left") == 0) { - other = TAILQ_PREV(current, nodes_head, nodes); - } else { - other = TAILQ_NEXT(current, nodes); - } - if (other == TAILQ_END(workspaces)) { - LOG("No other container in this direction found, trying to look further up in the tree...\n"); - current = current->parent; - continue; - } - break; - } while (current->type != CT_WORKSPACE && - current->type != CT_FLOATING_CON); + Con *second = NULL; + Con *first = current; + direction_t search_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; - if (other == NULL) { - LOG("No other container in this direction found, trying to look further up in the tree...\n"); + bool res = resize_find_tiling_participants(&first, &second, search_direction); + if (!res) { + LOG("No second container in this direction found.\n"); ysuccess(false); return false; } - LOG("other->percent = %f\n", other->percent); - LOG("current->percent before = %f\n", current->percent); - if (current->percent == 0.0) - current->percent = percentage; - if (other->percent == 0.0) - other->percent = percentage; - double new_current_percent = current->percent + ((double)ppt / 100.0); - double new_other_percent = other->percent - ((double)ppt / 100.0); - LOG("new_current_percent = %f\n", new_current_percent); - LOG("new_other_percent = %f\n", new_other_percent); + /* get the default percentage */ + int children = con_num_children(first->parent); + LOG("ins. %d children\n", children); + double percentage = 1.0 / children; + LOG("default percentage = %f\n", percentage); + + /* resize */ + LOG("second->percent = %f\n", second->percent); + LOG("first->percent before = %f\n", first->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 and greater than * 0.05 to have a reasonable minimum size. */ - if (definitelyGreaterThan(new_current_percent, 0.05, DBL_EPSILON) && - definitelyGreaterThan(new_other_percent, 0.05, DBL_EPSILON)) { - current->percent += ((double)ppt / 100.0); - other->percent -= ((double)ppt / 100.0); - LOG("current->percent after = %f\n", current->percent); - LOG("other->percent after = %f\n", other->percent); + if (definitelyGreaterThan(new_first_percent, 0.05, DBL_EPSILON) && + definitelyGreaterThan(new_second_percent, 0.05, DBL_EPSILON)) { + first->percent += ((double)ppt / 100.0); + second->percent -= ((double)ppt / 100.0); + 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"); } diff --git a/src/resize.c b/src/resize.c index 268dc3fb..f65ce88e 100644 --- a/src/resize.c +++ b/src/resize.c @@ -51,6 +51,54 @@ DRAGGING_CB(resize_callback) { xcb_flush(conn); } +bool resize_find_tiling_participants(Con **current, Con **other, direction_t direction) { + DLOG("Find two participants for resizing container=%p in direction=%i\n", other, direction); + Con *first = *current; + Con *second = NULL; + if (first == NULL) { + DLOG("Current container is NULL, aborting.\n"); + return false; + } + + /* 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 bool dir_backwards = (direction == D_UP || direction == D_LEFT); + while (first->type != CT_WORKSPACE && + first->type != CT_FLOATING_CON && + second == NULL) { + /* get the appropriate first container with the matching + * orientation (skip stacked/tabbed cons) */ + if ((con_orientation(first->parent) != search_orientation) || + (first->parent->layout == L_STACKED) || + (first->parent->layout == L_TABBED)) { + first = first->parent; + continue; + } + + /* get the counterpart for this resizement */ + if (dir_backwards) { + second = TAILQ_PREV(first, nodes_head, nodes); + } else { + second = TAILQ_NEXT(first, nodes); + } + + if (second == NULL) { + DLOG("No second container in this direction found, trying to look further up in the tree...\n"); + first = first->parent; + } + } + + DLOG("Found participants: first=%p and second=%p.", first, second); + *current = first; + *other = second; + if (first == NULL || second == NULL) { + DLOG("Could not find two participants for this resize request.\n"); + return false; + } + + return true; +} + int resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event) { DLOG("resize handler\n"); -- 2.39.5