/* * This function detaches 'con' from its parent and inserts it either before or * after 'target'. * */ static void insert_con_into(Con *con, Con *target, position_t position) { Con *parent = target->parent; /* We need to preserve the old con->parent. While it might still be used to * insert the entry before/after it, we call the on_remove_child callback * afterwards which might then close the con if it is empty. */ Con *old_parent = con->parent; con_detach(con); con_fix_percent(con->parent); /* When moving to a workspace, we respect the user’s configured * workspace_layout */ if (parent->type == CT_WORKSPACE) { Con *split = workspace_attach_to(parent); if (split != parent) { DLOG("Got a new split con, using that one instead\n"); con->parent = split; con_attach(con, split, false); DLOG("attached\n"); con->percent = 0.0; con_fix_percent(split); con = split; DLOG("ok, continuing with con %p instead\n", con); con_detach(con); } } con->parent = parent; if (position == BEFORE) { TAILQ_INSERT_BEFORE(target, con, nodes); TAILQ_INSERT_HEAD(&(parent->focus_head), con, focused); } else if (position == AFTER) { TAILQ_INSERT_AFTER(&(parent->nodes_head), target, con, nodes); TAILQ_INSERT_HEAD(&(parent->focus_head), con, focused); } /* Pretend the con was just opened with regards to size percent values. * Since the con is moved to a completely different con, the old value * does not make sense anyways. */ con->percent = 0.0; con_fix_percent(parent); CALL(old_parent, on_remove_child); }
/* * This function detaches 'con' from its parent and puts it in the given * workspace. Position is determined by the direction of movement into the * workspace container. * */ static void attach_to_workspace(Con *con, Con *ws, direction_t direction) { con_detach(con); con_fix_percent(con->parent); CALL(con->parent, on_remove_child); con->parent = ws; if (direction == D_RIGHT || direction == D_DOWN) { TAILQ_INSERT_HEAD(&(ws->nodes_head), con, nodes); TAILQ_INSERT_HEAD(&(ws->focus_head), con, focused); } else { TAILQ_INSERT_TAIL(&(ws->nodes_head), con, nodes); TAILQ_INSERT_TAIL(&(ws->focus_head), con, focused); } /* Pretend the con was just opened with regards to size percent values. * Since the con is moved to a completely different con, the old value * does not make sense anyways. */ con->percent = 0.0; con_fix_percent(ws); }
int resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event) { DLOG("resize handler\n"); /* TODO: previously, we were getting a rect containing all screens. why? */ Con *output = con_get_output(first); DLOG("x = %d, width = %d\n", output->rect.x, output->rect.width); x_mask_event_mask(~XCB_EVENT_MASK_ENTER_WINDOW); xcb_flush(conn); uint32_t mask = 0; uint32_t values[2]; mask = XCB_CW_OVERRIDE_REDIRECT; values[0] = 1; /* Open a new window, the resizebar. Grab the pointer and move the window 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_CLASS_INPUT_ONLY, XCURSOR_CURSOR_POINTER, true, mask, values); /* Keep track of the coordinate orthogonal to motion so we can determine * the length of the resize afterward. */ uint32_t initial_position, new_position; /* Configure the resizebar and snap the pointer. The resizebar runs along * the rect of the second con and follows the motion of the pointer. */ Rect helprect; if (orientation == HORIZ) { helprect.x = second->rect.x; helprect.y = second->rect.y; helprect.width = logical_px(2); helprect.height = second->rect.height; initial_position = second->rect.x; xcb_warp_pointer(conn, XCB_NONE, event->root, 0, 0, 0, 0, second->rect.x, event->root_y); } else { helprect.x = second->rect.x; helprect.y = second->rect.y; helprect.width = second->rect.width; helprect.height = logical_px(2); initial_position = second->rect.y; xcb_warp_pointer(conn, XCB_NONE, event->root, 0, 0, 0, 0, event->root_x, second->rect.y); } mask = XCB_CW_BACK_PIXEL; values[0] = config.client.focused.border; mask |= XCB_CW_OVERRIDE_REDIRECT; values[1] = 1; xcb_window_t helpwin = create_window(conn, helprect, XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT, XCB_WINDOW_CLASS_INPUT_OUTPUT, (orientation == HORIZ ? XCURSOR_CURSOR_RESIZE_HORIZONTAL : XCURSOR_CURSOR_RESIZE_VERTICAL), true, mask, values); xcb_circulate_window(conn, XCB_CIRCULATE_RAISE_LOWEST, helpwin); xcb_flush(conn); /* `new_position' will be updated by the `resize_callback'. */ new_position = initial_position; const struct callback_params params = {orientation, output, helpwin, &new_position}; /* `drag_pointer' blocks until the drag is completed. */ drag_result_t drag_result = drag_pointer(NULL, event, grabwin, BORDER_TOP, 0, resize_callback, ¶ms); xcb_destroy_window(conn, helpwin); xcb_destroy_window(conn, grabwin); xcb_flush(conn); /* User cancelled the drag so no action should be taken. */ if (drag_result == DRAG_REVERT) return 0; int pixels = (new_position - initial_position); DLOG("Done, pixels = %d\n", pixels); // if we got thus far, the containers must have // percentages associated with them assert(first->percent > 0.0); assert(second->percent > 0.0); // calculate the new percentage for the first container double new_percent, difference; 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; }