Bugfix: Store width_factor/height_factor per workspace, not per container

This is a relatively big change, however all cases should be handled by
now.

Because the function to do graphical resizing got rather large, I’ve created
a new file src/resize.c for it.

This fixes ticket #35.
This commit is contained in:
Michael Stapelberg 2009-05-09 17:48:35 +02:00
parent 18da0a3017
commit 5b4f10eaca
9 changed files with 325 additions and 235 deletions

View File

@ -125,6 +125,9 @@ Renders your layout (screens, workspaces, containers)
src/mainx.c:: src/mainx.c::
Initializes the window manager Initializes the window manager
src/resize.c::
Contains the functions to resize columns/rows in the table.
src/table.c:: src/table.c::
Manages the most important internal data structure, the design table. Manages the most important internal data structure, the design table.

View File

@ -8,11 +8,11 @@
* See file LICENSE for license information. * See file LICENSE for license information.
* *
*/ */
#include <xcb/xcb.h>
#ifndef _COMMANDS_H #ifndef _COMMANDS_H
#define _COMMANDS_H #define _COMMANDS_H
#include <xcb/xcb.h>
bool focus_window_in_container(xcb_connection_t *conn, Container *container, direction_t direction); bool focus_window_in_container(xcb_connection_t *conn, Container *container, direction_t direction);
/** Switches to the given workspace */ /** Switches to the given workspace */

View File

@ -174,6 +174,12 @@ struct Workspace {
/* This is a two-dimensional dynamic array of Container-pointers. Ive always wanted /* This is a two-dimensional dynamic array of Container-pointers. Ive always wanted
* to be a three-star programmer :) */ * to be a three-star programmer :) */
Container ***table; Container ***table;
/* width_factor and height_factor contain the amount of space (percentage) a column/row
has of all the space which is available for resized windows. This ensures that
non-resized windows (newly opened, for example) have the same size as always */
float *width_factor;
float *height_factor;
}; };
/* /*
@ -312,11 +318,6 @@ struct Container {
/* Width/Height of the container. Changeable by the user */ /* Width/Height of the container. Changeable by the user */
int width; int width;
int height; int height;
/* width_factor and height_factor contain the amount of space (percentage) a window
has of all the space which is available for resized windows. This ensures that
non-resized windows (newly opened, for example) have the same size as always */
float width_factor;
float height_factor;
/* When in stacking mode, we draw the titlebars of each client onto a separate window */ /* When in stacking mode, we draw the titlebars of each client onto a separate window */
struct Stack_Window stack_win; struct Stack_Window stack_win;

View File

@ -15,11 +15,11 @@
/** /**
* Gets the unoccupied space (= space which is available for windows which were resized by the user) * Gets the unoccupied space (= space which is available for windows which were resized by the user)
* for the given row. This is necessary to render both, customly resized windows and never touched * This is necessary to render both, customly resized windows and never touched
* windows correctly, meaning that the aspect ratio will be maintained when opening new windows. * windows correctly, meaning that the aspect ratio will be maintained when opening new windows.
* *
*/ */
int get_unoccupied_x(Workspace *workspace, int row); int get_unoccupied_x(Workspace *workspace);
/** /**
* (Re-)draws window decorations for a given Client onto the given drawable/graphic context. * (Re-)draws window decorations for a given Client onto the given drawable/graphic context.

27
include/resize.h Normal file
View File

@ -0,0 +1,27 @@
/*
* vim:ts=8:expandtab
*
* i3 - an improved dynamic tiling window manager
*
* (c) 2009 Michael Stapelberg and contributors
*
* See file LICENSE for license information.
*
*/
#ifndef _RESIZE_H
#define _RESIZE_H
#include <xcb/xcb.h>
typedef enum { O_HORIZONTAL, O_VERTICAL } resize_orientation_t;
/**
* Renders the resize window between the first/second container and resizes
* the table column/row.
*
*/
int resize_graphical_handler(xcb_connection_t *conn, Container *first, Container *second,
resize_orientation_t orientation, xcb_button_press_event_t *event);
#endif

View File

@ -31,6 +31,7 @@
#include "xinerama.h" #include "xinerama.h"
#include "config.h" #include "config.h"
#include "queue.h" #include "queue.h"
#include "resize.h"
/* After mapping/unmapping windows, a notify event is generated. However, we dont want it, /* After mapping/unmapping windows, a notify event is generated. However, we dont want it,
since itd trigger an infinite loop of switching between the different windows when since itd trigger an infinite loop of switching between the different windows when
@ -297,20 +298,15 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
return 1; return 1;
} }
xcb_window_t root = xcb_setup_roots_iterator(xcb_get_setup(conn)).data->root;
xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
/* Set focus in any case */ /* Set focus in any case */
set_focus(conn, client, true); set_focus(conn, client, true);
/* Lets see if this was on the borders (= resize). If not, were done */ /* Lets see if this was on the borders (= resize). If not, were done */
LOG("press button on x=%d, y=%d\n", event->event_x, event->event_y); LOG("press button on x=%d, y=%d\n", event->event_x, event->event_y);
resize_orientation_t orientation = O_VERTICAL;
Container *con = client->container, Container *con = client->container,
*first = NULL, *first = NULL,
*second = NULL; *second = NULL;
enum { O_HORIZONTAL, O_VERTICAL } orientation = O_VERTICAL;
int new_position;
if (con == NULL) { if (con == NULL) {
LOG("dock. done.\n"); LOG("dock. done.\n");
@ -363,187 +359,7 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
second = con->workspace->table[con->col+1][con->row]; second = con->workspace->table[con->col+1][con->row];
} }
/* FIXME: horizontal resizing causes empty spaces to exist */ return resize_graphical_handler(conn, first, second, orientation, event);
if (orientation == O_HORIZONTAL) {
LOG("Sorry, horizontal resizing is not yet activated due to creating layout bugs."
"If you are brave, enable the code for yourself and try fixing it.\n");
return 1;
}
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. */
Rect grabrect = {0, 0, root_screen->width_in_pixels, root_screen->height_in_pixels};
xcb_window_t grabwin = create_window(conn, grabrect, XCB_WINDOW_CLASS_INPUT_ONLY, -1, mask, values);
Rect helprect;
if (orientation == O_VERTICAL) {
helprect.x = event->root_x;
helprect.y = 0;
helprect.width = 2;
helprect.height = root_screen->height_in_pixels; /* this has to be the cells height */
new_position = event->root_x;
} else {
helprect.x = 0;
helprect.y = event->root_y;
helprect.width = root_screen->width_in_pixels; /* this has to be the cells width */
helprect.height = 2;
new_position = event->root_y;
}
mask = XCB_CW_BACK_PIXEL;
values[0] = get_colorpixel(conn, "#4c7899");
mask |= XCB_CW_OVERRIDE_REDIRECT;
values[1] = 1;
xcb_window_t helpwin = create_window(conn, helprect, XCB_WINDOW_CLASS_INPUT_OUTPUT,
(orientation == O_VERTICAL ?
XCB_CURSOR_SB_V_DOUBLE_ARROW :
XCB_CURSOR_SB_H_DOUBLE_ARROW), mask, values);
xcb_circulate_window(conn, XCB_CIRCULATE_RAISE_LOWEST, helpwin);
xcb_grab_pointer(conn, false, root, XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, grabwin, XCB_NONE, XCB_CURRENT_TIME);
xcb_flush(conn);
xcb_generic_event_t *inside_event;
/* Ive always wanted to have my own eventhandler… */
while ((inside_event = xcb_wait_for_event(conn))) {
/* Same as get_event_handler in xcb */
int nr = inside_event->response_type;
if (nr == 0) {
/* An error occured */
handle_event(NULL, conn, inside_event);
free(inside_event);
continue;
}
assert(nr < 256);
nr &= XCB_EVENT_RESPONSE_TYPE_MASK;
assert(nr >= 2);
/* Check if we need to escape this loop */
if (nr == XCB_BUTTON_RELEASE)
break;
switch (nr) {
case XCB_MOTION_NOTIFY:
if (orientation == O_VERTICAL) {
values[0] = new_position = ((xcb_motion_notify_event_t*)inside_event)->root_x;
xcb_configure_window(conn, helpwin, XCB_CONFIG_WINDOW_X, values);
} else {
values[0] = new_position = ((xcb_motion_notify_event_t*)inside_event)->root_y;
xcb_configure_window(conn, helpwin, XCB_CONFIG_WINDOW_Y, values);
}
xcb_flush(conn);
break;
default:
LOG("Passing to original handler\n");
/* Use original handler */
xcb_event_handle(&evenths, inside_event);
break;
}
free(inside_event);
}
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
xcb_destroy_window(conn, helpwin);
xcb_destroy_window(conn, grabwin);
xcb_flush(conn);
Workspace *ws = con->workspace;
if (orientation == O_VERTICAL) {
LOG("Resize was from X = %d to X = %d\n", event->root_x, new_position);
if (event->root_x == new_position) {
LOG("Nothing changed, not updating anything\n");
return 1;
}
/* Save the old unoccupied space to re-evaluate the other containers (not first or second) later */
int old_unoccupied_x = get_unoccupied_x(ws, first->row);
/* Convert 0 (for default width_factor) to actual numbers */
LOG("\n\n\n");
LOG("old_unoccupied_x = %d\n", old_unoccupied_x);
LOG("Updating first\n");
/* Set the new width factor on all clients in the column of the first container */
for (int row = 0; row < ws->rows; row++) {
Container *con = ws->table[first->col][row];
if (con->width_factor == 0)
con->width_factor = ((float)ws->rect.width / ws->cols) / ws->rect.width;
else con->width_factor = ((con->width_factor * old_unoccupied_x) / ws->rect.width);
LOG("Old con(%d,%d)->width_factor = %f\n", first->col, row, con->width_factor);
con->width_factor *= (float)(con->width + (new_position - event->root_x)) / con->width;
LOG("New con(%d,%d)->width_factor = %f\n", first->col, row, con->width_factor);
}
LOG("Updating second\n");
/* Set the new width factor on all clients in the column of the second container */
for (int row = 0; row < ws->rows; row++) {
Container *con = ws->table[second->col][row];
if (con->width_factor == 0)
con->width_factor = ((float)ws->rect.width / ws->cols) / ws->rect.width;
else con->width_factor = ((con->width_factor * old_unoccupied_x) / ws->rect.width);
LOG("Old con(%d,%d)->width_factor = %f\n", second->col, row, con->width_factor);
con->width_factor *= (float)(con->width - (new_position - event->root_x)) / con->width;
LOG("New con(%d,%d)->width_factor = %f\n", second->col, row, con->width_factor);
}
LOG("new unoccupied_x = %d\n", get_unoccupied_x(ws, first->row));
LOG("old_unoccupied_x = %d\n", old_unoccupied_x);
for (int col = 0; col < ws->cols; col++) {
Container *con = ws->table[col][first->row];
if (con == first || con == second)
continue;
LOG("Updating other container (current width_factor = %f)\n", con->width_factor);
con->width_factor = ((con->width_factor * old_unoccupied_x) / get_unoccupied_x(ws, first->row));
LOG("to %f\n", con->width_factor);
}
LOG("New first->width_factor = %f\n", first->width_factor);
LOG("New second->width_factor = %f\n", second->width_factor);
LOG("\n\n\n");
} else {
LOG("Resize was from Y = %d to Y = %d\n", event->root_y, new_position);
if (event->root_y == new_position) {
LOG("Nothing changed, not updating anything\n");
return 1;
}
/* Convert 0 (for default height_factor) to actual numbers */
if (first->height_factor == 0)
first->height_factor = ((float)ws->rect.height / ws->rows) / ws->rect.height;
if (second->height_factor == 0)
second->height_factor = ((float)ws->rect.height / ws->rows) / ws->rect.height;
first->height_factor *= (float)(first->height + (new_position - event->root_y)) / first->height;
second->height_factor *= (float)(second->height - (new_position - event->root_y)) / second->height;
}
render_layout(conn);
return 1;
} }
/* /*

View File

@ -31,7 +31,7 @@
* *
*/ */
static bool update_if_necessary(uint32_t *destination, const uint32_t new_value) { static bool update_if_necessary(uint32_t *destination, const uint32_t new_value) {
int old_value = *destination; uint32_t old_value = *destination;
return ((*destination = new_value) != old_value); return ((*destination = new_value) != old_value);
} }
@ -42,20 +42,17 @@ static bool update_if_necessary(uint32_t *destination, const uint32_t new_value)
* windows correctly, meaning that the aspect ratio will be maintained when opening new windows. * windows correctly, meaning that the aspect ratio will be maintained when opening new windows.
* *
*/ */
int get_unoccupied_x(Workspace *workspace, int row) { int get_unoccupied_x(Workspace *workspace) {
int unoccupied = workspace->rect.width; int unoccupied = workspace->rect.width;
float default_factor = ((float)workspace->rect.width / workspace->cols) / workspace->rect.width; float default_factor = ((float)workspace->rect.width / workspace->cols) / workspace->rect.width;
LOG("get_unoccupied_x(), starting with %d, default_factor = %f\n", unoccupied, default_factor); LOG("get_unoccupied_x(), starting with %d, default_factor = %f\n", unoccupied, default_factor);
for (int cols = 0; cols < workspace->cols;) { for (int cols = 0; cols < workspace->cols; cols++) {
Container *con = workspace->table[cols][row]; LOG("width_factor[%d] = %f\n", cols, workspace->width_factor[cols]);
LOG("width_factor[%d][%d] = %f, colspan = %d\n", cols, row, con->width_factor, con->colspan);
if (con->width_factor == 0) { if (workspace->width_factor[cols] == 0)
LOG("- %d * %f * %d = %f\n", workspace->rect.width, default_factor, con->colspan, workspace->rect.width * default_factor * con->colspan); unoccupied -= workspace->rect.width * default_factor;
unoccupied -= workspace->rect.width * default_factor * con->colspan;
}
cols += con->colspan;
} }
LOG("unoccupied space: %d\n", unoccupied); LOG("unoccupied space: %d\n", unoccupied);
@ -69,12 +66,10 @@ int get_unoccupied_y(Workspace *workspace, int col) {
LOG("get_unoccupied_y(), starting with %d, default_factor = %f\n", unoccupied, default_factor); LOG("get_unoccupied_y(), starting with %d, default_factor = %f\n", unoccupied, default_factor);
for (int rows = 0; rows < workspace->rows;) { for (int rows = 0; rows < workspace->rows; rows++) {
Container *con = workspace->table[col][rows]; LOG("height_factor[%d] = %f\n", rows, workspace->height_factor[rows]);
LOG("height_factor[%d][%d] = %f, rowspan %d\n", col, rows, con->height_factor, con->rowspan); if (workspace->height_factor[rows] == 0)
if (con->height_factor == 0) unoccupied -= workspace->rect.height * default_factor;
unoccupied -= workspace->rect.height * default_factor * con->rowspan;
rows += con->rowspan;
} }
LOG("unoccupied space: %d\n", unoccupied); LOG("unoccupied space: %d\n", unoccupied);
@ -526,15 +521,15 @@ void render_workspace(xcb_connection_t *conn, i3Screen *screen, Workspace *r_ws)
container->x = xoffset[rows]; container->x = xoffset[rows];
container->y = yoffset[cols]; container->y = yoffset[cols];
if (container->width_factor == 0) if (r_ws->width_factor[cols] == 0)
container->width = (width / r_ws->cols); container->width = (width / r_ws->cols);
else container->width = get_unoccupied_x(r_ws, rows) * container->width_factor; else container->width = get_unoccupied_x(r_ws) * r_ws->width_factor[cols];
single_width = container->width; single_width = container->width;
container->width *= container->colspan; container->width *= container->colspan;
if (container->height_factor == 0) //if (container->height_factor == 0)
container->height = (height / r_ws->rows); container->height = (height / r_ws->rows);
else container->height = get_unoccupied_y(r_ws, cols) * container->height_factor; //else container->height = get_unoccupied_y(r_ws, cols) * container->height_factor;
single_height = container->height; single_height = container->height;
container->height *= container->rowspan; container->height *= container->rowspan;

220
src/resize.c Normal file
View File

@ -0,0 +1,220 @@
/*
* vim:ts=8:expandtab
*
* i3 - an improved dynamic tiling window manager
*
* © 2009 Michael Stapelberg and contributors
*
* See file LICENSE for license information.
*
* This file contains the functions for resizing table columns/rows because
* its actually lots of work, compared to the other handlers.
*
*/
#include <stdlib.h>
#include <assert.h>
#include <xcb/xcb.h>
#include <xcb/xcb_event.h>
#include "i3.h"
#include "data.h"
#include "resize.h"
#include "util.h"
#include "xcb.h"
#include "debug.h"
#include "layout.h"
/*
* Renders the resize window between the first/second container and resizes
* the table column/row.
*
*/
int resize_graphical_handler(xcb_connection_t *conn, Container *first, Container *second,
resize_orientation_t orientation, xcb_button_press_event_t *event) {
int new_position;
xcb_window_t root = xcb_setup_roots_iterator(xcb_get_setup(conn)).data->root;
xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
/* FIXME: horizontal resizing causes empty spaces to exist */
if (orientation == O_HORIZONTAL) {
LOG("Sorry, horizontal resizing is not yet activated due to creating layout bugs."
"If you are brave, enable the code for yourself and try fixing it.\n");
return 1;
}
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. */
Rect grabrect = {0, 0, root_screen->width_in_pixels, root_screen->height_in_pixels};
xcb_window_t grabwin = create_window(conn, grabrect, XCB_WINDOW_CLASS_INPUT_ONLY, -1, mask, values);
Rect helprect;
if (orientation == O_VERTICAL) {
helprect.x = event->root_x;
helprect.y = 0;
helprect.width = 2;
helprect.height = root_screen->height_in_pixels;
new_position = event->root_x;
} else {
helprect.x = 0;
helprect.y = event->root_y;
helprect.width = root_screen->width_in_pixels;
helprect.height = 2;
new_position = event->root_y;
}
mask = XCB_CW_BACK_PIXEL;
values[0] = get_colorpixel(conn, "#4c7899");
mask |= XCB_CW_OVERRIDE_REDIRECT;
values[1] = 1;
xcb_window_t helpwin = create_window(conn, helprect, XCB_WINDOW_CLASS_INPUT_OUTPUT,
(orientation == O_VERTICAL ?
XCB_CURSOR_SB_V_DOUBLE_ARROW :
XCB_CURSOR_SB_H_DOUBLE_ARROW), mask, values);
xcb_circulate_window(conn, XCB_CIRCULATE_RAISE_LOWEST, helpwin);
xcb_grab_pointer(conn, false, root, XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, grabwin, XCB_NONE, XCB_CURRENT_TIME);
xcb_flush(conn);
xcb_generic_event_t *inside_event;
/* Ive always wanted to have my own eventhandler… */
while ((inside_event = xcb_wait_for_event(conn))) {
/* Same as get_event_handler in xcb */
int nr = inside_event->response_type;
if (nr == 0) {
/* An error occured */
handle_event(NULL, conn, inside_event);
free(inside_event);
continue;
}
assert(nr < 256);
nr &= XCB_EVENT_RESPONSE_TYPE_MASK;
assert(nr >= 2);
/* Check if we need to escape this loop */
if (nr == XCB_BUTTON_RELEASE)
break;
switch (nr) {
case XCB_MOTION_NOTIFY:
if (orientation == O_VERTICAL) {
values[0] = new_position = ((xcb_motion_notify_event_t*)inside_event)->root_x;
xcb_configure_window(conn, helpwin, XCB_CONFIG_WINDOW_X, values);
} else {
values[0] = new_position = ((xcb_motion_notify_event_t*)inside_event)->root_y;
xcb_configure_window(conn, helpwin, XCB_CONFIG_WINDOW_Y, values);
}
xcb_flush(conn);
break;
default:
LOG("Passing to original handler\n");
/* Use original handler */
xcb_event_handle(&evenths, inside_event);
break;
}
free(inside_event);
}
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
xcb_destroy_window(conn, helpwin);
xcb_destroy_window(conn, grabwin);
xcb_flush(conn);
Workspace *ws = first->workspace;
if (orientation == O_VERTICAL) {
LOG("Resize was from X = %d to X = %d\n", event->root_x, new_position);
if (event->root_x == new_position) {
LOG("Nothing changed, not updating anything\n");
return 1;
}
int default_width = ws->rect.width / ws->cols;
int old_unoccupied_x = get_unoccupied_x(ws);
/* We pre-calculate the unoccupied space to see if we need to adapt sizes before
* doing the resize */
int new_unoccupied_x = old_unoccupied_x;
if (old_unoccupied_x == 0)
old_unoccupied_x = ws->rect.width;
if (ws->width_factor[first->col] == 0)
new_unoccupied_x += default_width;
if (ws->width_factor[second->col] == 0)
new_unoccupied_x += default_width;
LOG("\n\n\n");
LOG("old = %d, new = %d\n", old_unoccupied_x, new_unoccupied_x);
/* If the space used for customly resized columns has changed we need to adapt the
* other customly resized columns, if any */
if (new_unoccupied_x != old_unoccupied_x)
for (int col = 0; col < ws->cols; col++) {
if (ws->width_factor[col] == 0)
continue;
LOG("Updating other column (%d) (current width_factor = %f)\n", col, ws->width_factor[col]);
ws->width_factor[col] = (ws->width_factor[col] * old_unoccupied_x) / new_unoccupied_x;
LOG("to %f\n", ws->width_factor[col]);
}
LOG("old_unoccupied_x = %d\n", old_unoccupied_x);
LOG("Updating first (before = %f)\n", ws->width_factor[first->col]);
/* Convert 0 (for default width_factor) to actual numbers */
if (ws->width_factor[first->col] == 0)
ws->width_factor[first->col] = ((float)ws->rect.width / ws->cols) / new_unoccupied_x;
LOG("middle = %f\n", ws->width_factor[first->col]);
LOG("first->width = %d, new_position = %d, event->root_x = %d\n", first->width, new_position, event->root_x);
ws->width_factor[first->col] *= (float)(first->width + (new_position - event->root_x)) / first->width;
LOG("-> %f\n", ws->width_factor[first->col]);
LOG("Updating second (before = %f)\n", ws->width_factor[second->col]);
if (ws->width_factor[second->col] == 0)
ws->width_factor[second->col] = ((float)ws->rect.width / ws->cols) / new_unoccupied_x;
LOG("middle = %f\n", ws->width_factor[second->col]);
LOG("second->width = %d, new_position = %d, event->root_x = %d\n", second->width, new_position, event->root_x);
ws->width_factor[second->col] *= (float)(second->width - (new_position - event->root_x)) / second->width;
LOG("-> %f\n", ws->width_factor[second->col]);
LOG("new unoccupied_x = %d\n", get_unoccupied_x(ws));
LOG("\n\n\n");
} else {
#if 0
LOG("Resize was from Y = %d to Y = %d\n", event->root_y, new_position);
if (event->root_y == new_position) {
LOG("Nothing changed, not updating anything\n");
return 1;
}
/* Convert 0 (for default height_factor) to actual numbers */
if (first->height_factor == 0)
first->height_factor = ((float)ws->rect.height / ws->rows) / ws->rect.height;
if (second->height_factor == 0)
second->height_factor = ((float)ws->rect.height / ws->rows) / ws->rect.height;
first->height_factor *= (float)(first->height + (new_position - event->root_y)) / first->height;
second->height_factor *= (float)(second->height - (new_position - event->root_y)) / second->height;
#endif
}
render_layout(conn);
return 1;
}

View File

@ -24,6 +24,7 @@
#include "table.h" #include "table.h"
#include "util.h" #include "util.h"
#include "i3.h" #include "i3.h"
#include "layout.h"
int current_workspace = 0; int current_workspace = 0;
Workspace workspaces[10]; Workspace workspaces[10];
@ -65,6 +66,9 @@ static void new_container(Workspace *workspace, Container **container, int col,
void expand_table_rows(Workspace *workspace) { void expand_table_rows(Workspace *workspace) {
workspace->rows++; workspace->rows++;
workspace->height_factor = realloc(workspace->height_factor, sizeof(float) * workspace->rows);
workspace->height_factor[workspace->rows-1] = 0;
for (int c = 0; c < workspace->cols; c++) { for (int c = 0; c < workspace->cols; c++) {
workspace->table[c] = realloc(workspace->table[c], sizeof(Container*) * workspace->rows); workspace->table[c] = realloc(workspace->table[c], sizeof(Container*) * workspace->rows);
new_container(workspace, &(workspace->table[c][workspace->rows-1]), c, workspace->rows-1); new_container(workspace, &(workspace->table[c][workspace->rows-1]), c, workspace->rows-1);
@ -78,6 +82,16 @@ void expand_table_rows(Workspace *workspace) {
void expand_table_rows_at_head(Workspace *workspace) { void expand_table_rows_at_head(Workspace *workspace) {
workspace->rows++; workspace->rows++;
workspace->height_factor = realloc(workspace->height_factor, sizeof(float) * workspace->rows);
LOG("rows = %d\n", workspace->rows);
for (int rows = (workspace->rows - 1); rows >= 1; rows--) {
LOG("Moving height_factor %d (%f) to %d\n", rows-1, workspace->height_factor[rows-1], rows);
workspace->height_factor[rows] = workspace->height_factor[rows-1];
}
workspace->height_factor[0] = 0;
for (int cols = 0; cols < workspace->cols; cols++) for (int cols = 0; cols < workspace->cols; cols++)
workspace->table[cols] = realloc(workspace->table[cols], sizeof(Container*) * workspace->rows); workspace->table[cols] = realloc(workspace->table[cols], sizeof(Container*) * workspace->rows);
@ -88,6 +102,7 @@ void expand_table_rows_at_head(Workspace *workspace) {
workspace->table[cols][rows] = workspace->table[cols][rows-1]; workspace->table[cols][rows] = workspace->table[cols][rows-1];
workspace->table[cols][rows]->row = rows; workspace->table[cols][rows]->row = rows;
} }
for (int cols = 0; cols < workspace->cols; cols++) for (int cols = 0; cols < workspace->cols; cols++)
new_container(workspace, &(workspace->table[cols][0]), cols, 0); new_container(workspace, &(workspace->table[cols][0]), cols, 0);
} }
@ -99,6 +114,9 @@ void expand_table_rows_at_head(Workspace *workspace) {
void expand_table_cols(Workspace *workspace) { void expand_table_cols(Workspace *workspace) {
workspace->cols++; workspace->cols++;
workspace->width_factor = realloc(workspace->width_factor, sizeof(float) * workspace->cols);
workspace->width_factor[workspace->cols-1] = 0;
workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols); workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols);
workspace->table[workspace->cols-1] = calloc(sizeof(Container*) * workspace->rows, 1); workspace->table[workspace->cols-1] = calloc(sizeof(Container*) * workspace->rows, 1);
for (int c = 0; c < workspace->rows; c++) for (int c = 0; c < workspace->rows; c++)
@ -112,6 +130,16 @@ void expand_table_cols(Workspace *workspace) {
void expand_table_cols_at_head(Workspace *workspace) { void expand_table_cols_at_head(Workspace *workspace) {
workspace->cols++; workspace->cols++;
workspace->width_factor = realloc(workspace->width_factor, sizeof(float) * workspace->cols);
LOG("cols = %d\n", workspace->cols);
for (int cols = (workspace->cols - 1); cols >= 1; cols--) {
LOG("Moving width_factor %d (%f) to %d\n", cols-1, workspace->width_factor[cols-1], cols);
workspace->width_factor[cols] = workspace->width_factor[cols-1];
}
workspace->width_factor[0] = 0;
workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols); workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols);
workspace->table[workspace->cols-1] = calloc(sizeof(Container*) * workspace->rows, 1); workspace->table[workspace->cols-1] = calloc(sizeof(Container*) * workspace->rows, 1);
@ -136,13 +164,32 @@ void expand_table_cols_at_head(Workspace *workspace) {
* *
*/ */
static void shrink_table_cols(Workspace *workspace) { static void shrink_table_cols(Workspace *workspace) {
float free_space = workspace->width_factor[workspace->cols-1];
workspace->cols--; workspace->cols--;
/* Shrink the width_factor array */
workspace->width_factor = realloc(workspace->width_factor, sizeof(float) * workspace->cols);
/* Free the container-pointers */ /* Free the container-pointers */
free(workspace->table[workspace->cols]); free(workspace->table[workspace->cols]);
/* Re-allocate the table */ /* Re-allocate the table */
workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols); workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols);
/* Distribute the free space */
if (free_space == 0)
return;
for (int cols = (workspace->cols-1); cols >= 0; cols--) {
if (workspace->width_factor[cols] == 0)
continue;
LOG("Added free space (%f) to %d (had %f)\n", free_space, cols,
workspace->width_factor[cols]);
workspace->width_factor[cols] += free_space;
break;
}
} }
/* /*
@ -171,25 +218,6 @@ static void free_container(xcb_connection_t *conn, Workspace *workspace, int col
if (old_container->mode == MODE_STACK) if (old_container->mode == MODE_STACK)
leave_stack_mode(conn, old_container); leave_stack_mode(conn, old_container);
/* We need to distribute the space which will now be freed to other containers */
if (old_container->width_factor > 0) {
Container *dest_container = NULL;
/* Check if we got a container to the left… */
if (col > 0)
dest_container = workspace->table[col-1][row];
/* …or to the right */
else if ((col+1) < workspace->cols)
dest_container = workspace->table[col+1][row];
if (dest_container != NULL) {
if (dest_container->width_factor == 0)
dest_container->width_factor = ((float)workspace->rect.width / workspace->cols) / workspace->rect.width;
LOG("dest_container->width_factor = %f\n", dest_container->width_factor);
dest_container->width_factor += old_container->width_factor;
LOG("afterwards it's %f\n", dest_container->width_factor);
}
}
free(old_container); free(old_container);
} }