Implement horizontal resizing

next
Michael Stapelberg 2009-02-16 03:28:07 +01:00
parent 7216738778
commit 6b1069cd47
7 changed files with 158 additions and 71 deletions

View File

@ -169,6 +169,8 @@ struct Container {
/* Width/Height of the container. Changeable by the user */
int width;
int height;
float width_factor;
float height_factor;
/* Backpointer to the workspace this container is in */
Workspace *workspace;

View File

@ -13,6 +13,7 @@
#ifndef _LAYOUT_H
#define _LAYOUT_H
Rect get_unoccupied_space(Workspace *workspace);
void decorate_window(xcb_connection_t *conn, Client *client);
void render_layout(xcb_connection_t *conn);

View File

@ -24,5 +24,6 @@ enum { _NET_SUPPORTED = 0,
};
uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex);
xcb_window_t create_window(xcb_connection_t *conn, Rect r, uint16_t window_class, uint32_t mask, uint32_t *values);
#endif

View File

@ -128,8 +128,11 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
printf("button press!\n");
/* This was either a focus for a clients parent (= titlebar)… */
Client *client = table_get(byChild, event->event);
if (client == NULL)
bool border_click = false;
if (client == NULL) {
client = table_get(byParent, event->event);
border_click = true;
}
if (client == NULL)
return 1;
@ -140,56 +143,57 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
set_focus(conn, client);
/* Lets see if this was on the borders (= resize). If not, were done */
i3Font *font = load_font(conn, pattern);
printf("press button on x=%d, y=%d\n", event->event_x, event->event_y);
if (event->event_y <= (font->height + 2))
return 1;
printf("that was resize\n");
Container *con = client->container,
*first = NULL,
*second = NULL;
printf("event->event_x = %d, client->rect.width = %d\n", event->event_x, client->rect.width);
if (!border_click) {
printf("client. done.\n");
return 1;
}
if (event->event_y < 2) {
/* This was a press on the top border */
if (con->row == 0)
return 1;
return 0; /* TODO: impl */
//neighbor_con = this_con->workspace->table[this_con->col][this_con->row-1];
} else if (event->event_y >= (client->rect.height - 2)) {
/* …bottom border */
if (con->row == (con->workspace->rows-1))
return 1;
return 0; /* TODO; impl */
//neighbor_con = this_con->workspace->table[this_con->col][this_con->row+1];
} else if (event->event_x < 2) {
/* …left border */
if (con->col == 0)
return 1;
first = con->workspace->table[con->col-1][con->row];
second = con;
} else if (event->event_x > 2) {
/* …right border */
if (con->col == (con->workspace->cols-1))
return 1;
first = con;
second = con->workspace->table[con->col+1][con->row];
}
/* 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, 0, NULL);
Rect helprect = {event->root_x, 0, 2, root_screen->height_in_pixels /* this has to be the cells height */};
xcb_window_t helpwin = create_window(conn, helprect, XCB_WINDOW_CLASS_INPUT_OUTPUT, 0, NULL);
/* TODO: the whole logic is missing. this is just a proof of concept */
xcb_window_t grabwin = xcb_generate_id(conn);
uint32_t values[1] = {get_colorpixel(conn, helpwin, "#4c7899")};
xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(conn, helpwin, XCB_CW_BACK_PIXEL, values);
check_error(conn, cookie, "Could not change window attributes (background color)");
uint32_t mask = 0;
uint32_t values[3];
xcb_create_window(conn,
0,
grabwin,
root,
0, /* x */
0, /* y */
root_screen->width_in_pixels, /* width */
root_screen->height_in_pixels, /* height */
/* border_width */ 0,
XCB_WINDOW_CLASS_INPUT_ONLY,
root_screen->root_visual,
0,
values);
/* Map the window on the screen (= make it visible) */
xcb_map_window(conn, grabwin);
xcb_window_t helpwin = xcb_generate_id(conn);
mask = XCB_CW_BACK_PIXEL;
values[0] = root_screen->white_pixel;
xcb_create_window(conn, root_screen->root_depth, helpwin, root,
event->root_x,
0,
5,
root_screen->height_in_pixels,
/* bordor */ 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
root_screen->root_visual,
mask,
values);
xcb_map_window(conn, helpwin);
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,
@ -203,7 +207,9 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
/* 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);
@ -237,6 +243,21 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
xcb_destroy_window(conn, grabwin);
xcb_flush(conn);
Workspace *ws = con->workspace;
printf("Resize was from X = %d to X = %d\n", event->root_x, values[0]);
/* Convert 0 (for default width_factor) to actual numbers */
if (first->width_factor == 0)
first->width_factor = ((float)ws->rect.width / ws->cols) / ws->rect.width;
if (second->width_factor == 0)
second->width_factor = ((float)ws->rect.width / ws->cols) / ws->rect.width;
first->width_factor *= (float)(first->width + (values[0] - event->root_x)) / first->width;
second->width_factor *= (float)(second->width - (values[0] - event->root_x)) / second->width;
render_layout(conn);
return 1;
}

View File

@ -7,6 +7,8 @@
*
* See file LICENSE for license information.
*
* layout.c: Functions handling layout/drawing of window decorations
*
*/
#define _GNU_SOURCE
#include <stdio.h>
@ -21,7 +23,42 @@
#include "util.h"
#include "xinerama.h"
/* All functions handling layout/drawing of window decorations */
/*
* For resizing containers (= cells), we need to know the space which is unoccupied by "default"
* windows. The resized containers will be rendered relatively to this space, meaning that newly
* created columns/rows after a container was resized will start with their normal size.
*
*/
Rect get_unoccupied_space(Workspace *workspace) {
printf("getting unoccupied space\n");
float default_factor_w = ((float)workspace->rect.width / (float)workspace->cols) / (float)workspace->rect.width;
float default_factor_h = (workspace->rect.height / workspace->rows) / workspace->rect.height;
Rect result = {0, 0, workspace->rect.width, workspace->rect.height};
printf("default factor is %f and %f\n", default_factor_w, default_factor_h);
printf("start w = %d, h = %d\n", result.width, result.height);
/* TODO: colspan/rowspan*/
for (int cols = 0; cols < workspace->cols; cols++)
for (int rows = 0; rows < workspace->rows; rows++) {
printf("oh hai. wf[%d][%d] = %f\n", cols, rows, workspace->table[cols][rows]->width_factor);
if (workspace->table[cols][rows]->width_factor == 0)
result.width -= workspace->rect.width * default_factor_w;
if (workspace->table[cols][rows]->height_factor == 0)
result.height -= workspace->rect.height * default_factor_h;
}
/* If every container is using the default factor, we have the whole space available */
if (result.width == 0)
result.width = workspace->rect.width;
if (result.height == 0)
result.height = workspace->rect.height;
printf("unoccupied x = %d, unoccupied y = %d\n", result.width, result.height);
return result;
}
/*
* (Re-)draws window decorations for a given Client
@ -112,9 +149,9 @@ static void render_container(xcb_connection_t *connection, Container *container)
/* Check if we changed client->x or client->y by updating it…
* Note the bitwise OR instead of logical OR to force evaluation of both statements */
if (client->force_reconfigure |
(client->rect.x != (client->rect.x = container->x + (container->col * container->width))) |
(client->rect.y != (client->rect.y = container->y + (container->row * container->height +
(container->height / num_clients) * current_client)))) {
(client->rect.x != (client->rect.x = container->x)) |
(client->rect.y != (client->rect.y = container->y +
(container->height / num_clients) * current_client))) {
printf("frame needs to be pushed to %dx%d\n", client->rect.x, client->rect.y);
/* Note: We can use a pointer to client->x like an array of uint32_ts
because it is followed by client->y by definition */
@ -126,6 +163,7 @@ static void render_container(xcb_connection_t *connection, Container *container)
if (client->force_reconfigure |
(client->rect.width != (client->rect.width = container->width)) |
(client->rect.height != (client->rect.height = container->height / num_clients))) {
printf("resizing client to %d x %d\n", client->rect.width, client->rect.height);
xcb_configure_window(connection, client->frame,
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
&(client->rect.width));
@ -171,27 +209,37 @@ void render_layout(xcb_connection_t *connection) {
continue;
int width = r_ws->rect.width;
int height = r_ws->rect.height;
int x = r_ws->rect.x;
int y = r_ws->rect.y;
printf("got %d rows and %d cols\n", r_ws->rows, r_ws->cols);
printf("each of them therefore is %d px width and %d px height\n",
width / r_ws->cols, height / r_ws->rows);
Rect space = get_unoccupied_space(r_ws);
printf("got %d / %d unoc space\n", space.width, space.height);
/* Go through the whole table and render whats necessary */
for (int cols = 0; cols < r_ws->cols; cols++)
for (int rows = 0; rows < r_ws->rows; rows++) {
Container *container = r_ws->table[cols][rows];
printf("container has %d colspan, %d rowspan\n",
container->colspan, container->rowspan);
printf("container at %d, %d\n", x, y);
/* Update position of the container */
container->row = rows;
container->col = cols;
container->x = r_ws->rect.x;
container->y = r_ws->rect.y;
container->width = (width / r_ws->cols) * container->colspan;
container->x = x;
container->y = y;
if (container->width_factor == 0)
container->width = (width / r_ws->cols) * container->colspan;
else container->width = space.width * container->width_factor;
container->height = (height / r_ws->rows) * container->rowspan;
/* Render it */
render_container(connection, container);
x += container->width;
}
}

View File

@ -162,30 +162,18 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
printf("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
i3Font *font = load_font(conn, pattern);
height = min(height, c_ws->rect.y + c_ws->rect.height);
width = min(width, c_ws->rect.x + c_ws->rect.width);
height = min(height, c_ws->rect.y + c_ws->rect.height);
Rect framerect = {x, y,
width + 2 + 2, /* 2 px border at each side */
height + 2 + 2 + font->height}; /* 2 px border plus fonts height */
/* Yo dawg, I heard you like windows, so I create a window around your window… */
xcb_void_cookie_t cookie = xcb_create_window_checked(conn,
depth,
new->frame,
root,
x,
y,
width + 2 + 2, /* 2 px border at each side */
height + 2 + 2 + font->height, /* 2 px border plus fonts height */
0, /* border_width = 0, we draw our own borders */
XCB_WINDOW_CLASS_INPUT_OUTPUT,
XCB_WINDOW_CLASS_COPY_FROM_PARENT,
mask,
values);
printf("x = %d, y = %d, width = %d, height = %d\n", x, y, width, height);
check_error(conn, cookie, "Could not create frame");
xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child);
new->frame = create_window(conn, framerect, XCB_WINDOW_CLASS_INPUT_OUTPUT, mask, values);
/* Map the window on the screen (= make it visible) */
xcb_map_window(conn, new->frame);
/* TODO: document */
xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child);
/* Generate a graphics context for the titlebar */
new->titlegc = xcb_generate_id(conn);
@ -197,7 +185,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
/* Moves the original window into the new frame we've created for it */
new->awaiting_useless_unmap = true;
cookie = xcb_reparent_window_checked(conn, child, new->frame, 0, font->height);
xcb_void_cookie_t cookie = xcb_reparent_window_checked(conn, child, new->frame, 0, font->height);
check_error(conn, cookie, "Could not reparent window");
/* We are interested in property changes */

View File

@ -56,3 +56,29 @@ uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex)
xcb_free_colormap(conn, colormap_id);
return pixel;
}
xcb_window_t create_window(xcb_connection_t *conn, Rect dims, uint16_t window_class, uint32_t mask, uint32_t *values) {
xcb_window_t root = xcb_setup_roots_iterator(xcb_get_setup(conn)).data->root;
xcb_window_t result = xcb_generate_id(conn);
xcb_void_cookie_t cookie;
/* If the window class is XCB_WINDOW_CLASS_INPUT_ONLY, depth has to be 0 */
uint16_t depth = (window_class == XCB_WINDOW_CLASS_INPUT_ONLY ? 0 : XCB_COPY_FROM_PARENT);
cookie = xcb_create_window_checked(conn,
depth,
result, /* the window id */
root, /* parent == root */
dims.x, dims.y, dims.width, dims.height, /* dimensions */
0, /* border = 0, we draw our own */
window_class,
XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */
mask,
values);
check_error(conn, cookie, "Could not create window");
/* Map the window (= make it visible) */
xcb_map_window(conn, result);
return result;
}