]> git.sur5r.net Git - i3/i3/commitdiff
Implement horizontal resizing
authorMichael Stapelberg <michael+git@stapelberg.de>
Mon, 16 Feb 2009 02:28:07 +0000 (03:28 +0100)
committerMichael Stapelberg <michael+git@stapelberg.de>
Mon, 16 Feb 2009 02:28:07 +0000 (03:28 +0100)
include/data.h
include/layout.h
include/xcb.h
src/handlers.c
src/layout.c
src/mainx.c
src/xcb.c

index b4dcd178f66f6a371c95b8871cef7bd8ed0da897..c1e10613ec43105acb227f4624f2cbfe9dca141d 100644 (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;
index 41d52a3f93da2bb12ecfc42ba034d45472358802..4d7f0d9ce0a94b87e4a0ab16ee61a56059dc87b1 100644 (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);
 
index 5a7a9a51b6eaec7347a0fda7f7f1263940d493e0..d234ac204c9ea091695d0ee1b638244091646e6a 100644 (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
index b8ae19d411fea6992c11a90da6225cef98daa9dc..f1a247ee32e8a8069053226aed0282230b8cf854 100644 (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 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;
 
@@ -140,56 +143,57 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
         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,
@@ -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;
 }
 
index 7145aacf121fdbcc1dac9ad8195eb4bc883948bf..a3b87f176ef15ad695c0cbc92b7d0f578d917b99 100644 (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>
 #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 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;
                         }
         }
 
index 9bdd3ae314290526ec8111aa9b713e3bf98871d8..70a0f8197ddfb86d72a776bd0c09951c943ed70f 100644 (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 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);
@@ -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 */
index f1563afbf8fc34730ad89462f4e71cab5c0ae2da..176f26925c60f09330e9245dba45b262a890a0fa 100644 (file)
--- a/src/xcb.c
+++ b/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);
         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;
+}