Implement horizontal resizing
This commit is contained in:
parent
7216738778
commit
6b1069cd47
|
@ -169,6 +169,8 @@ 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;
|
||||||
|
float width_factor;
|
||||||
|
float height_factor;
|
||||||
|
|
||||||
/* Backpointer to the workspace this container is in */
|
/* Backpointer to the workspace this container is in */
|
||||||
Workspace *workspace;
|
Workspace *workspace;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#ifndef _LAYOUT_H
|
#ifndef _LAYOUT_H
|
||||||
#define _LAYOUT_H
|
#define _LAYOUT_H
|
||||||
|
|
||||||
|
Rect get_unoccupied_space(Workspace *workspace);
|
||||||
void decorate_window(xcb_connection_t *conn, Client *client);
|
void decorate_window(xcb_connection_t *conn, Client *client);
|
||||||
void render_layout(xcb_connection_t *conn);
|
void render_layout(xcb_connection_t *conn);
|
||||||
|
|
||||||
|
|
|
@ -24,5 +24,6 @@ enum { _NET_SUPPORTED = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex);
|
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
|
#endif
|
||||||
|
|
107
src/handlers.c
107
src/handlers.c
|
@ -128,8 +128,11 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
|
||||||
printf("button press!\n");
|
printf("button press!\n");
|
||||||
/* This was either a focus for a client’s parent (= titlebar)… */
|
/* This was either a focus for a client’s parent (= titlebar)… */
|
||||||
Client *client = table_get(byChild, event->event);
|
Client *client = table_get(byChild, event->event);
|
||||||
if (client == NULL)
|
bool border_click = false;
|
||||||
|
if (client == NULL) {
|
||||||
client = table_get(byParent, event->event);
|
client = table_get(byParent, event->event);
|
||||||
|
border_click = true;
|
||||||
|
}
|
||||||
if (client == NULL)
|
if (client == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -140,56 +143,57 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
|
||||||
set_focus(conn, client);
|
set_focus(conn, client);
|
||||||
|
|
||||||
/* Let’s see if this was on the borders (= resize). If not, we’re done */
|
/* Let’s see if this was on the borders (= resize). If not, we’re done */
|
||||||
i3Font *font = load_font(conn, pattern);
|
|
||||||
printf("press button on x=%d, y=%d\n", event->event_x, event->event_y);
|
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
|
/* Open a new window, the resizebar. Grab the pointer and move the window around
|
||||||
as the user moves the pointer. */
|
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 cell’s 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 */
|
uint32_t values[1] = {get_colorpixel(conn, helpwin, "#4c7899")};
|
||||||
xcb_window_t grabwin = xcb_generate_id(conn);
|
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_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_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 */
|
/* Same as get_event_handler in xcb */
|
||||||
int nr = inside_event->response_type;
|
int nr = inside_event->response_type;
|
||||||
if (nr == 0) {
|
if (nr == 0) {
|
||||||
|
/* An error occured */
|
||||||
handle_event(NULL, conn, inside_event);
|
handle_event(NULL, conn, inside_event);
|
||||||
|
free(inside_event);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
assert(nr < 256);
|
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_destroy_window(conn, grabwin);
|
||||||
xcb_flush(conn);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
62
src/layout.c
62
src/layout.c
|
@ -7,6 +7,8 @@
|
||||||
*
|
*
|
||||||
* See file LICENSE for license information.
|
* See file LICENSE for license information.
|
||||||
*
|
*
|
||||||
|
* layout.c: Functions handling layout/drawing of window decorations
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -21,7 +23,42 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "xinerama.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
|
* (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…
|
/* 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 */
|
* Note the bitwise OR instead of logical OR to force evaluation of both statements */
|
||||||
if (client->force_reconfigure |
|
if (client->force_reconfigure |
|
||||||
(client->rect.x != (client->rect.x = container->x + (container->col * container->width))) |
|
(client->rect.x != (client->rect.x = container->x)) |
|
||||||
(client->rect.y != (client->rect.y = container->y + (container->row * container->height +
|
(client->rect.y != (client->rect.y = container->y +
|
||||||
(container->height / num_clients) * current_client)))) {
|
(container->height / num_clients) * current_client))) {
|
||||||
printf("frame needs to be pushed to %dx%d\n", client->rect.x, client->rect.y);
|
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
|
/* Note: We can use a pointer to client->x like an array of uint32_ts
|
||||||
because it is followed by client->y by definition */
|
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 |
|
if (client->force_reconfigure |
|
||||||
(client->rect.width != (client->rect.width = container->width)) |
|
(client->rect.width != (client->rect.width = container->width)) |
|
||||||
(client->rect.height != (client->rect.height = container->height / num_clients))) {
|
(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_configure_window(connection, client->frame,
|
||||||
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
|
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
|
||||||
&(client->rect.width));
|
&(client->rect.width));
|
||||||
|
@ -171,27 +209,37 @@ void render_layout(xcb_connection_t *connection) {
|
||||||
continue;
|
continue;
|
||||||
int width = r_ws->rect.width;
|
int width = r_ws->rect.width;
|
||||||
int height = r_ws->rect.height;
|
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("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",
|
printf("each of them therefore is %d px width and %d px height\n",
|
||||||
width / r_ws->cols, height / r_ws->rows);
|
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 what’s necessary */
|
/* Go through the whole table and render what’s necessary */
|
||||||
for (int cols = 0; cols < r_ws->cols; cols++)
|
for (int cols = 0; cols < r_ws->cols; cols++)
|
||||||
for (int rows = 0; rows < r_ws->rows; rows++) {
|
for (int rows = 0; rows < r_ws->rows; rows++) {
|
||||||
Container *container = r_ws->table[cols][rows];
|
Container *container = r_ws->table[cols][rows];
|
||||||
printf("container has %d colspan, %d rowspan\n",
|
printf("container has %d colspan, %d rowspan\n",
|
||||||
container->colspan, container->rowspan);
|
container->colspan, container->rowspan);
|
||||||
|
printf("container at %d, %d\n", x, y);
|
||||||
/* Update position of the container */
|
/* Update position of the container */
|
||||||
container->row = rows;
|
container->row = rows;
|
||||||
container->col = cols;
|
container->col = cols;
|
||||||
container->x = r_ws->rect.x;
|
container->x = x;
|
||||||
container->y = r_ws->rect.y;
|
container->y = y;
|
||||||
container->width = (width / r_ws->cols) * container->colspan;
|
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;
|
container->height = (height / r_ws->rows) * container->rowspan;
|
||||||
|
|
||||||
/* Render it */
|
/* Render it */
|
||||||
render_container(connection, container);
|
render_container(connection, container);
|
||||||
|
|
||||||
|
x += container->width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
30
src/mainx.c
30
src/mainx.c
|
@ -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);
|
printf("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
|
||||||
|
|
||||||
i3Font *font = load_font(conn, pattern);
|
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);
|
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 font’s height */
|
||||||
|
|
||||||
/* Yo dawg, I heard you like windows, so I create a window around your window… */
|
/* 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,
|
new->frame = create_window(conn, framerect, XCB_WINDOW_CLASS_INPUT_OUTPUT, mask, values);
|
||||||
depth,
|
|
||||||
new->frame,
|
|
||||||
root,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width + 2 + 2, /* 2 px border at each side */
|
|
||||||
height + 2 + 2 + font->height, /* 2 px border plus font’s 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);
|
|
||||||
|
|
||||||
/* Map the window on the screen (= make it visible) */
|
/* TODO: document */
|
||||||
xcb_map_window(conn, new->frame);
|
xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child);
|
||||||
|
|
||||||
/* Generate a graphics context for the titlebar */
|
/* Generate a graphics context for the titlebar */
|
||||||
new->titlegc = xcb_generate_id(conn);
|
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 */
|
/* Moves the original window into the new frame we've created for it */
|
||||||
new->awaiting_useless_unmap = true;
|
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");
|
check_error(conn, cookie, "Could not reparent window");
|
||||||
|
|
||||||
/* We are interested in property changes */
|
/* We are interested in property changes */
|
||||||
|
|
26
src/xcb.c
26
src/xcb.c
|
@ -56,3 +56,29 @@ uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex)
|
||||||
xcb_free_colormap(conn, colormap_id);
|
xcb_free_colormap(conn, colormap_id);
|
||||||
return pixel;
|
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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue