/* 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;
#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);
};
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
printf("button press!\n");
/* This was either a focus for a client’s 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;
set_focus(conn, client);
/* 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);
- if (event->event_y <= (font->height + 2))
+
+ 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;
+ }
- printf("that was resize\n");
+ 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 cell’s height */};
+ xcb_window_t helpwin = create_window(conn, helprect, XCB_WINDOW_CLASS_INPUT_OUTPUT, 0, NULL);
+ 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)");
- /* TODO: the whole logic is missing. this is just a proof of concept */
- xcb_window_t grabwin = xcb_generate_id(conn);
-
- 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,
/* 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);
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;
}
*
* See file LICENSE for license information.
*
+ * layout.c: Functions handling layout/drawing of window decorations
+ *
*/
#define _GNU_SOURCE
#include <stdio.h>
#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
/* 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 */
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));
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 what’s 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;
}
}
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 font’s 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 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);
+ 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);
/* 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 */
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;
+}