From fb4c851e2a72ea29f290dc9dbeda723707a2961c Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 14 Feb 2009 02:33:31 +0100 Subject: [PATCH] Add vim hints, copyright notice to each file, add LICENSE, retab! everything --- LICENSE | 27 ++ include/commands.h | 10 + include/data.h | 168 +++++++------ include/debug.h | 10 + include/font.h | 10 + include/handlers.h | 16 +- include/i3.h | 10 + include/layout.h | 10 + include/table.h | 10 + include/util.h | 10 + include/xcb.h | 10 + src/commands.c | 596 +++++++++++++++++++++++---------------------- src/debug.c | 10 + src/font.c | 52 ++-- src/handlers.c | 500 ++++++++++++++++++------------------- src/layout.c | 264 ++++++++++---------- src/mainx.c | 588 ++++++++++++++++++++++---------------------- src/table.c | 60 +++-- src/util.c | 52 ++-- src/xcb.c | 44 ++-- 20 files changed, 1335 insertions(+), 1122 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..5771597b --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009, Michael Stapelberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Michael Stapelberg nor the + names of contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY Michael Stapelberg ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Michael Stapelberg BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/include/commands.h b/include/commands.h index 148f56fa..412c9b07 100644 --- a/include/commands.h +++ b/include/commands.h @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #include #ifndef _COMMANDS_H diff --git a/include/data.h b/include/data.h index 1fd856b3..74268c79 100644 --- a/include/data.h +++ b/include/data.h @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #include #ifndef _DATA_H @@ -20,36 +30,36 @@ typedef struct Workspace Workspace; typedef enum { D_LEFT, D_RIGHT, D_UP, D_DOWN } direction_t; enum { - BIND_NONE = 0, - BIND_MOD_1 = XCB_MOD_MASK_1, - BIND_MOD_2 = XCB_MOD_MASK_2, - BIND_MOD_3 = XCB_MOD_MASK_3, - BIND_MOD_4 = XCB_MOD_MASK_4, - BIND_MOD_5 = XCB_MOD_MASK_5, - BIND_SHIFT = XCB_MOD_MASK_SHIFT, - BIND_CONTROL = XCB_MOD_MASK_CONTROL, - BIND_MODE_SWITCH = (1 << 8) + BIND_NONE = 0, + BIND_MOD_1 = XCB_MOD_MASK_1, + BIND_MOD_2 = XCB_MOD_MASK_2, + BIND_MOD_3 = XCB_MOD_MASK_3, + BIND_MOD_4 = XCB_MOD_MASK_4, + BIND_MOD_5 = XCB_MOD_MASK_5, + BIND_SHIFT = XCB_MOD_MASK_SHIFT, + BIND_CONTROL = XCB_MOD_MASK_CONTROL, + BIND_MODE_SWITCH = (1 << 8) }; struct Workspace { - int x; - int y; - int width; - int height; - int screen_num; - int num; - - /* table dimensions */ - int cols; - int rows; - - /* These are stored here just while this workspace is _not_ shown (see show_workspace()) */ - int current_row; - int current_col; - - /* This is a two-dimensional dynamic array of Container-pointers. I’ve always wanted - * to be a three-star programmer :) */ - Container ***table; + int x; + int y; + int width; + int height; + int screen_num; + int num; + + /* table dimensions */ + int cols; + int rows; + + /* These are stored here just while this workspace is _not_ shown (see show_workspace()) */ + int current_row; + int current_col; + + /* This is a two-dimensional dynamic array of Container-pointers. I’ve always wanted + * to be a three-star programmer :) */ + Container ***table; }; /* @@ -57,19 +67,19 @@ struct Workspace { * */ struct Cell { - int row; - int column; + int row; + int column; }; struct Binding { - /* Keycode to bind */ - uint32_t keycode; - /* Bitmask consisting of BIND_MOD_1, BIND_MODE_SWITCH, … */ - uint32_t mods; - /* Command, like in command mode */ - char *command; - - TAILQ_ENTRY(Binding) bindings; + /* Keycode to bind */ + uint32_t keycode; + /* Bitmask consisting of BIND_MOD_1, BIND_MODE_SWITCH, … */ + uint32_t mods; + /* Command, like in command mode */ + char *command; + + TAILQ_ENTRY(Binding) bindings; }; /* @@ -79,14 +89,14 @@ struct Binding { * */ struct Font { - /* The name of the font, that is what the pattern resolves to */ - char *name; - /* A copy of the pattern to build a cache */ - char *pattern; - /* The height of the font, built from font_ascent + font_descent */ - int height; - /* The xcb-id for the font */ - xcb_font_t id; + /* The name of the font, that is what the pattern resolves to */ + char *name; + /* A copy of the pattern to build a cache */ + char *pattern; + /* The height of the font, built from font_ascent + font_descent */ + int height; + /* The xcb-id for the font */ + xcb_font_t id; }; /* @@ -94,27 +104,27 @@ struct Font { * */ struct Client { - /* TODO: this is NOT final */ - Cell old_position; /* if you set a client to floating and set it back to managed, - it does remember its old position and *tries* to get back there */ + /* TODO: this is NOT final */ + Cell old_position; /* if you set a client to floating and set it back to managed, + it does remember its old position and *tries* to get back there */ - /* Backpointer. A client is inside a container */ - Container *container; + /* Backpointer. A client is inside a container */ + Container *container; - uint32_t x, y; - uint32_t width, height; + uint32_t x, y; + uint32_t width, height; - /* Name */ - char *name; - int name_len; + /* Name */ + char *name; + int name_len; - /* XCB contexts */ - xcb_window_t frame; /* Our window: The frame around the client */ - xcb_gcontext_t titlegc; /* The titlebar’s graphic context inside the frame */ - xcb_window_t child; /* The client’s window */ + /* XCB contexts */ + xcb_window_t frame; /* Our window: The frame around the client */ + xcb_gcontext_t titlegc; /* The titlebar’s graphic context inside the frame */ + xcb_window_t child; /* The client’s window */ - /* The following entry provides the necessary list pointers to use Client with LIST_* macros */ - CIRCLEQ_ENTRY(Client) clients; + /* The following entry provides the necessary list pointers to use Client with LIST_* macros */ + CIRCLEQ_ENTRY(Client) clients; }; /* @@ -122,24 +132,24 @@ struct Client { * */ struct Container { - /* Those are speaking for themselves: */ - Client *currently_focused; - int colspan; - int rowspan; - - /* Position of the container inside our table */ - int row; - int col; - /* Xinerama: X/Y of the container */ - int x; - int y; - /* Width/Height of the container. Changeable by the user */ - int width; - int height; - - /* Ensure MODE_DEFAULT maps to 0 because we use calloc for initialization later */ - enum { MODE_DEFAULT = 0, MODE_STACK = 1 } mode; - CIRCLEQ_HEAD(client_head, Client) clients; + /* Those are speaking for themselves: */ + Client *currently_focused; + int colspan; + int rowspan; + + /* Position of the container inside our table */ + int row; + int col; + /* Xinerama: X/Y of the container */ + int x; + int y; + /* Width/Height of the container. Changeable by the user */ + int width; + int height; + + /* Ensure MODE_DEFAULT maps to 0 because we use calloc for initialization later */ + enum { MODE_DEFAULT = 0, MODE_STACK = 1 } mode; + CIRCLEQ_HEAD(client_head, Client) clients; }; #endif diff --git a/include/debug.h b/include/debug.h index 3d9cf3e7..3d722120 100644 --- a/include/debug.h +++ b/include/debug.h @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #ifndef _DEBUG_H #define _DEBUG_H diff --git a/include/font.h b/include/font.h index 732c369e..3e9d0a1a 100644 --- a/include/font.h +++ b/include/font.h @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #include #include "data.h" diff --git a/include/handlers.h b/include/handlers.h index 7c82ca46..15236b31 100644 --- a/include/handlers.h +++ b/include/handlers.h @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #ifndef _HANDLERS_H #define _HANDLERS_H @@ -7,11 +17,7 @@ int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_event_t *event); int handle_map_notify_event(void *prophs, xcb_connection_t *conn, xcb_map_notify_event_t *event); int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state, - xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop); + xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop); int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t *event); - - - - #endif diff --git a/include/i3.h b/include/i3.h index c9fc80ed..0ac30514 100644 --- a/include/i3.h +++ b/include/i3.h @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #include #include diff --git a/include/layout.h b/include/layout.h index aecb2b4d..41d52a3f 100644 --- a/include/layout.h +++ b/include/layout.h @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #include #ifndef _LAYOUT_H diff --git a/include/table.h b/include/table.h index 1d6ca8f7..a0b79f6a 100644 --- a/include/table.h +++ b/include/table.h @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #include #include "data.h" diff --git a/include/util.h b/include/util.h index 05e05f2e..479e0ced 100644 --- a/include/util.h +++ b/include/util.h @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #ifndef _UTIL_H #define _UTIL_H diff --git a/include/xcb.h b/include/xcb.h index c8224ef9..979a9621 100644 --- a/include/xcb.h +++ b/include/xcb.h @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #ifndef _XCB_H #define _XCB_H diff --git a/src/commands.c b/src/commands.c index 23b188ab..95475dfb 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #include #include #include @@ -14,59 +24,59 @@ #include "i3.h" static bool focus_window_in_container(xcb_connection_t *connection, Container *container, - direction_t direction) { - /* If this container is empty, we’re done */ - if (container->currently_focused == NULL) - return false; - - Client *candidad; - if (direction == D_UP) - candidad = CIRCLEQ_PREV(container->currently_focused, clients); - else if (direction == D_DOWN) - candidad = CIRCLEQ_NEXT(container->currently_focused, clients); - - /* If we don’t have anything to select, we’re done */ - if (candidad == CIRCLEQ_END(&(container->clients))) - return false; - - /* Set focus if we could successfully move */ - container->currently_focused = candidad; - xcb_set_input_focus(connection, XCB_INPUT_FOCUS_NONE, candidad->child, XCB_CURRENT_TIME); - render_layout(connection); - - return true; + direction_t direction) { + /* If this container is empty, we’re done */ + if (container->currently_focused == NULL) + return false; + + Client *candidad; + if (direction == D_UP) + candidad = CIRCLEQ_PREV(container->currently_focused, clients); + else if (direction == D_DOWN) + candidad = CIRCLEQ_NEXT(container->currently_focused, clients); + + /* If we don’t have anything to select, we’re done */ + if (candidad == CIRCLEQ_END(&(container->clients))) + return false; + + /* Set focus if we could successfully move */ + container->currently_focused = candidad; + xcb_set_input_focus(connection, XCB_INPUT_FOCUS_NONE, candidad->child, XCB_CURRENT_TIME); + render_layout(connection); + + return true; } static void focus_window(xcb_connection_t *connection, direction_t direction) { - printf("focusing direction %d\n", direction); - /* TODO: for horizontal default layout, this has to be expanded to LEFT/RIGHT */ - if (direction == D_UP || direction == D_DOWN) { - /* Let’s see if we can perform up/down focus in the current container */ - Container *container = CUR_CELL; - - /* There always is a container. If not, current_col or current_row is wrong */ - assert(container != NULL); - - if (focus_window_in_container(connection, container, direction)) - return; - } else if (direction == D_LEFT || direction == D_RIGHT) { - if (direction == D_RIGHT && cell_exists(current_col+1, current_row)) - current_col++; - else if (direction == D_LEFT && cell_exists(current_col-1, current_row)) - current_col--; - else { - printf("nah, not possible\n"); - return; - } - if (CUR_CELL->currently_focused != NULL) { - xcb_set_input_focus(connection, XCB_INPUT_FOCUS_NONE, - CUR_CELL->currently_focused->child, XCB_CURRENT_TIME); - render_layout(connection); - } - - } else { - printf("direction unhandled\n"); - } + printf("focusing direction %d\n", direction); + /* TODO: for horizontal default layout, this has to be expanded to LEFT/RIGHT */ + if (direction == D_UP || direction == D_DOWN) { + /* Let’s see if we can perform up/down focus in the current container */ + Container *container = CUR_CELL; + + /* There always is a container. If not, current_col or current_row is wrong */ + assert(container != NULL); + + if (focus_window_in_container(connection, container, direction)) + return; + } else if (direction == D_LEFT || direction == D_RIGHT) { + if (direction == D_RIGHT && cell_exists(current_col+1, current_row)) + current_col++; + else if (direction == D_LEFT && cell_exists(current_col-1, current_row)) + current_col--; + else { + printf("nah, not possible\n"); + return; + } + if (CUR_CELL->currently_focused != NULL) { + xcb_set_input_focus(connection, XCB_INPUT_FOCUS_NONE, + CUR_CELL->currently_focused->child, XCB_CURRENT_TIME); + render_layout(connection); + } + + } else { + printf("direction unhandled\n"); + } } /* @@ -76,21 +86,21 @@ static void focus_window(xcb_connection_t *connection, direction_t direction) { * */ static bool move_current_window_in_container(xcb_connection_t *connection, Client *client, - direction_t direction) { - Client *other = (direction == D_UP ? CIRCLEQ_PREV(client, clients) : - CIRCLEQ_NEXT(client, clients)); - - if (other == CIRCLEQ_END(&(client->container->clients))) - return false; - - printf("i can do that\n"); - /* We can move the client inside its current container */ - CIRCLEQ_REMOVE(&(client->container->clients), client, clients); - if (direction == D_UP) - CIRCLEQ_INSERT_BEFORE(&(client->container->clients), other, client, clients); - else CIRCLEQ_INSERT_AFTER(&(client->container->clients), other, client, clients); - render_layout(connection); - return true; + direction_t direction) { + Client *other = (direction == D_UP ? CIRCLEQ_PREV(client, clients) : + CIRCLEQ_NEXT(client, clients)); + + if (other == CIRCLEQ_END(&(client->container->clients))) + return false; + + printf("i can do that\n"); + /* We can move the client inside its current container */ + CIRCLEQ_REMOVE(&(client->container->clients), client, clients); + if (direction == D_UP) + CIRCLEQ_INSERT_BEFORE(&(client->container->clients), other, client, clients); + else CIRCLEQ_INSERT_AFTER(&(client->container->clients), other, client, clients); + render_layout(connection); + return true; } /* @@ -99,69 +109,69 @@ static bool move_current_window_in_container(xcb_connection_t *connection, Clien * */ static void move_current_window(xcb_connection_t *connection, direction_t direction) { - printf("moving window to direction %d\n", direction); - /* Get current window */ - Container *container = CUR_CELL, - *new; - - /* There has to be a container, see focus_window() */ - assert(container != NULL); - - /* If there is no window, we’re done */ - if (container->currently_focused == NULL) - return; - - /* As soon as the client is moved away, the next client in the old - * container needs to get focus, if any. Therefore, we save it here. */ - Client *current_client = container->currently_focused; - Client *to_focus = CIRCLEQ_NEXT(current_client, clients); - if (to_focus == CIRCLEQ_END(&(container->clients))) - to_focus = NULL; - - switch (direction) { - case D_LEFT: - if (current_col == 0) - return; - - new = CUR_TABLE[--current_col][current_row]; - break; - case D_RIGHT: - if (current_col == (c_ws->cols-1)) - expand_table_cols(c_ws); - - new = CUR_TABLE[++current_col][current_row]; - break; - case D_UP: - /* TODO: if we’re at the up-most position, move the rest of the table down */ - if (move_current_window_in_container(connection, current_client, D_UP) || - current_row == 0) - return; - - new = CUR_TABLE[current_col][--current_row]; - break; - case D_DOWN: - if (move_current_window_in_container(connection, current_client, D_DOWN)) - return; - - if (current_row == (c_ws->rows-1)) - expand_table_rows(c_ws); - - new = CUR_TABLE[current_col][++current_row]; - break; - } - - /* Remove it from the old container and put it into the new one */ - CIRCLEQ_REMOVE(&(container->clients), current_client, clients); - CIRCLEQ_INSERT_TAIL(&(new->clients), current_client, clients); - - /* Update data structures */ - current_client->container = new; - container->currently_focused = to_focus; - new->currently_focused = current_client; - - /* TODO: delete all empty columns/rows */ - - render_layout(connection); + printf("moving window to direction %d\n", direction); + /* Get current window */ + Container *container = CUR_CELL, + *new; + + /* There has to be a container, see focus_window() */ + assert(container != NULL); + + /* If there is no window, we’re done */ + if (container->currently_focused == NULL) + return; + + /* As soon as the client is moved away, the next client in the old + * container needs to get focus, if any. Therefore, we save it here. */ + Client *current_client = container->currently_focused; + Client *to_focus = CIRCLEQ_NEXT(current_client, clients); + if (to_focus == CIRCLEQ_END(&(container->clients))) + to_focus = NULL; + + switch (direction) { + case D_LEFT: + if (current_col == 0) + return; + + new = CUR_TABLE[--current_col][current_row]; + break; + case D_RIGHT: + if (current_col == (c_ws->cols-1)) + expand_table_cols(c_ws); + + new = CUR_TABLE[++current_col][current_row]; + break; + case D_UP: + /* TODO: if we’re at the up-most position, move the rest of the table down */ + if (move_current_window_in_container(connection, current_client, D_UP) || + current_row == 0) + return; + + new = CUR_TABLE[current_col][--current_row]; + break; + case D_DOWN: + if (move_current_window_in_container(connection, current_client, D_DOWN)) + return; + + if (current_row == (c_ws->rows-1)) + expand_table_rows(c_ws); + + new = CUR_TABLE[current_col][++current_row]; + break; + } + + /* Remove it from the old container and put it into the new one */ + CIRCLEQ_REMOVE(&(container->clients), current_client, clients); + CIRCLEQ_INSERT_TAIL(&(new->clients), current_client, clients); + + /* Update data structures */ + current_client->container = new; + container->currently_focused = to_focus; + new->currently_focused = current_client; + + /* TODO: delete all empty columns/rows */ + + render_layout(connection); } /* @@ -170,108 +180,108 @@ static void move_current_window(xcb_connection_t *connection, direction_t direct * */ static void snap_current_container(xcb_connection_t *connection, direction_t direction) { - printf("snapping container to direction %d\n", direction); - - Container *container = CUR_CELL; - int i; - - assert(container != NULL); - - switch (direction) { - case D_LEFT: - /* Snap to the left is actually a move to the left and then a snap right */ - move_current_window(connection, D_LEFT); - snap_current_container(connection, D_RIGHT); - return; - case D_RIGHT: - /* Check if the cell is used */ - if (!cell_exists(container->col + 1, container->row) || - CUR_TABLE[container->col+1][container->row]->currently_focused != NULL) { - printf("cannot snap to right - the cell is already used\n"); - return; - } - - /* Check if there are other cells with rowspan, which are in our way. - * If so, reduce their rowspan. */ - for (i = container->row-1; i >= 0; i--) { - printf("we got cell %d, %d with rowspan %d\n", - container->col+1, i, CUR_TABLE[container->col+1][i]->rowspan); - while ((CUR_TABLE[container->col+1][i]->rowspan-1) >= (container->row - i)) - CUR_TABLE[container->col+1][i]->rowspan--; - printf("new rowspan = %d\n", CUR_TABLE[container->col+1][i]->rowspan); - } - - container->colspan++; - break; - case D_UP: - move_current_window(connection, D_UP); - snap_current_container(connection, D_DOWN); - return; - case D_DOWN: - printf("snapping down\n"); - if (!cell_exists(container->col, container->row+1) || - CUR_TABLE[container->col][container->row+1]->currently_focused != NULL) { - printf("cannot snap down - the cell is already used\n"); - return; - } - - for (i = container->col-1; i >= 0; i--) { - printf("we got cell %d, %d with colspan %d\n", - i, container->row+1, CUR_TABLE[i][container->row+1]->colspan); - while ((CUR_TABLE[i][container->row+1]->colspan-1) >= (container->col - i)) - CUR_TABLE[i][container->row+1]->colspan--; - printf("new colspan = %d\n", CUR_TABLE[i][container->row+1]->colspan); - - } - - container->rowspan++; - break; - } - - render_layout(connection); + printf("snapping container to direction %d\n", direction); + + Container *container = CUR_CELL; + int i; + + assert(container != NULL); + + switch (direction) { + case D_LEFT: + /* Snap to the left is actually a move to the left and then a snap right */ + move_current_window(connection, D_LEFT); + snap_current_container(connection, D_RIGHT); + return; + case D_RIGHT: + /* Check if the cell is used */ + if (!cell_exists(container->col + 1, container->row) || + CUR_TABLE[container->col+1][container->row]->currently_focused != NULL) { + printf("cannot snap to right - the cell is already used\n"); + return; + } + + /* Check if there are other cells with rowspan, which are in our way. + * If so, reduce their rowspan. */ + for (i = container->row-1; i >= 0; i--) { + printf("we got cell %d, %d with rowspan %d\n", + container->col+1, i, CUR_TABLE[container->col+1][i]->rowspan); + while ((CUR_TABLE[container->col+1][i]->rowspan-1) >= (container->row - i)) + CUR_TABLE[container->col+1][i]->rowspan--; + printf("new rowspan = %d\n", CUR_TABLE[container->col+1][i]->rowspan); + } + + container->colspan++; + break; + case D_UP: + move_current_window(connection, D_UP); + snap_current_container(connection, D_DOWN); + return; + case D_DOWN: + printf("snapping down\n"); + if (!cell_exists(container->col, container->row+1) || + CUR_TABLE[container->col][container->row+1]->currently_focused != NULL) { + printf("cannot snap down - the cell is already used\n"); + return; + } + + for (i = container->col-1; i >= 0; i--) { + printf("we got cell %d, %d with colspan %d\n", + i, container->row+1, CUR_TABLE[i][container->row+1]->colspan); + while ((CUR_TABLE[i][container->row+1]->colspan-1) >= (container->col - i)) + CUR_TABLE[i][container->row+1]->colspan--; + printf("new colspan = %d\n", CUR_TABLE[i][container->row+1]->colspan); + + } + + container->rowspan++; + break; + } + + render_layout(connection); } static void show_workspace(xcb_connection_t *conn, int workspace) { - int cols, rows; - Client *client; - printf("show_workspace(%d)\n", workspace); - - xcb_window_t root = xcb_setup_roots_iterator(xcb_get_setup(conn)).data->root; - - /* Store current_row/current_col */ - c_ws->current_row = current_row; - c_ws->current_col = current_col; - - /* TODO: does grabbing the server actually bring us any (speed)advantages? */ - //xcb_grab_server(conn); - - /* Unmap all clients */ - for (cols = 0; cols < c_ws->cols; cols++) - for (rows = 0; rows < c_ws->rows; rows++) { - CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients) - xcb_unmap_window(conn, client->frame); - } - - c_ws = &workspaces[workspace-1]; - current_row = c_ws->current_row; - current_col = c_ws->current_col; - printf("new current row = %d, current col = %d\n", current_row, current_col); - - /* Map all clients on the new workspace */ - for (cols = 0; cols < c_ws->cols; cols++) - for (rows = 0; rows < c_ws->rows; rows++) { - CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients) - xcb_map_window(conn, client->frame); - } - - /* Restore focus on the new workspace */ - if (CUR_CELL->currently_focused != NULL) - xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, CUR_CELL->currently_focused->child, XCB_CURRENT_TIME); - else xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, root, XCB_CURRENT_TIME); - - //xcb_ungrab_server(conn); - - render_layout(conn); + int cols, rows; + Client *client; + printf("show_workspace(%d)\n", workspace); + + xcb_window_t root = xcb_setup_roots_iterator(xcb_get_setup(conn)).data->root; + + /* Store current_row/current_col */ + c_ws->current_row = current_row; + c_ws->current_col = current_col; + + /* TODO: does grabbing the server actually bring us any (speed)advantages? */ + //xcb_grab_server(conn); + + /* Unmap all clients */ + for (cols = 0; cols < c_ws->cols; cols++) + for (rows = 0; rows < c_ws->rows; rows++) { + CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients) + xcb_unmap_window(conn, client->frame); + } + + c_ws = &workspaces[workspace-1]; + current_row = c_ws->current_row; + current_col = c_ws->current_col; + printf("new current row = %d, current col = %d\n", current_row, current_col); + + /* Map all clients on the new workspace */ + for (cols = 0; cols < c_ws->cols; cols++) + for (rows = 0; rows < c_ws->rows; rows++) { + CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients) + xcb_map_window(conn, client->frame); + } + + /* Restore focus on the new workspace */ + if (CUR_CELL->currently_focused != NULL) + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, CUR_CELL->currently_focused->child, XCB_CURRENT_TIME); + else xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, root, XCB_CURRENT_TIME); + + //xcb_ungrab_server(conn); + + render_layout(conn); } /* @@ -279,70 +289,70 @@ static void show_workspace(xcb_connection_t *conn, int workspace) { * */ void parse_command(xcb_connection_t *conn, const char *command) { - printf("--- parsing command \"%s\" ---\n", command); - /* Hmm, just to be sure */ - if (command[0] == '\0') - return; - - /* Is it an ? */ - if (strncmp(command, "exec ", strlen("exec ")) == 0) { - printf("starting \"%s\"\n", command + strlen("exec ")); - start_application(command+strlen("exec ")); - return; - } - - /* Is it a ? */ - if (command[0] == 'w') { - /* TODO: implement */ - printf("not yet implemented.\n"); - return; - } - - /* It's a normal */ - int times; - char *rest = NULL; - enum { ACTION_FOCUS, ACTION_MOVE, ACTION_SNAP } action = ACTION_FOCUS; - direction_t direction; - times = strtol(command, &rest, 10); - if (rest == NULL) { - printf("Invalid command: Consists only of a movement\n"); - return; - } - if (*rest == 'm' || *rest == 's') { - action = (*rest == 'm' ? ACTION_MOVE : ACTION_SNAP); - rest++; - } - - if (*rest == '\0') { - /* No rest? This was a tag number, not a times specification */ - show_workspace(conn, times); - return; - } - - /* Now perform action to */ - while (*rest != '\0') { - if (*rest == 'h') - direction = D_LEFT; - else if (*rest == 'j') - direction = D_DOWN; - else if (*rest == 'k') - direction = D_UP; - else if (*rest == 'l') - direction = D_RIGHT; - else { - printf("unknown direction: %c\n", *rest); - return; - } - - if (action == ACTION_FOCUS) - focus_window(conn, direction); - else if (action == ACTION_MOVE) - move_current_window(conn, direction); - else if (action == ACTION_SNAP) - snap_current_container(conn, direction); - - rest++; - } - - printf("--- done ---\n"); + printf("--- parsing command \"%s\" ---\n", command); + /* Hmm, just to be sure */ + if (command[0] == '\0') + return; + + /* Is it an ? */ + if (strncmp(command, "exec ", strlen("exec ")) == 0) { + printf("starting \"%s\"\n", command + strlen("exec ")); + start_application(command+strlen("exec ")); + return; + } + + /* Is it a ? */ + if (command[0] == 'w') { + /* TODO: implement */ + printf("not yet implemented.\n"); + return; + } + + /* It's a normal */ + int times; + char *rest = NULL; + enum { ACTION_FOCUS, ACTION_MOVE, ACTION_SNAP } action = ACTION_FOCUS; + direction_t direction; + times = strtol(command, &rest, 10); + if (rest == NULL) { + printf("Invalid command: Consists only of a movement\n"); + return; + } + if (*rest == 'm' || *rest == 's') { + action = (*rest == 'm' ? ACTION_MOVE : ACTION_SNAP); + rest++; + } + + if (*rest == '\0') { + /* No rest? This was a tag number, not a times specification */ + show_workspace(conn, times); + return; + } + + /* Now perform action to */ + while (*rest != '\0') { + if (*rest == 'h') + direction = D_LEFT; + else if (*rest == 'j') + direction = D_DOWN; + else if (*rest == 'k') + direction = D_UP; + else if (*rest == 'l') + direction = D_RIGHT; + else { + printf("unknown direction: %c\n", *rest); + return; + } + + if (action == ACTION_FOCUS) + focus_window(conn, direction); + else if (action == ACTION_MOVE) + move_current_window(conn, direction); + else if (action == ACTION_SNAP) + snap_current_container(conn, direction); + + rest++; + } + + printf("--- done ---\n"); } diff --git a/src/debug.c b/src/debug.c index cbdbd368..0d9066b3 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #include #include diff --git a/src/font.c b/src/font.c index 803ac0a6..6ab7110b 100644 --- a/src/font.c +++ b/src/font.c @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ /* * Handles font loading * @@ -11,29 +21,29 @@ #include "util.h" i3Font *load_font(xcb_connection_t *c, const char *pattern) { - /* TODO: this function should be caching */ - i3Font *new = malloc(sizeof(i3Font)); + /* TODO: this function should be caching */ + i3Font *new = malloc(sizeof(i3Font)); - xcb_list_fonts_with_info_cookie_t cookie = xcb_list_fonts_with_info(c, 1, strlen(pattern), pattern); - xcb_list_fonts_with_info_reply_t *reply = xcb_list_fonts_with_info_reply(c, cookie, NULL); - if (!reply) { - printf("Could not load font\n"); - exit(1); - } + xcb_list_fonts_with_info_cookie_t cookie = xcb_list_fonts_with_info(c, 1, strlen(pattern), pattern); + xcb_list_fonts_with_info_reply_t *reply = xcb_list_fonts_with_info_reply(c, cookie, NULL); + if (!reply) { + printf("Could not load font\n"); + exit(1); + } - /* Oh my, this is so ugly :-(. Why can’t they just return a null-terminated - * string? That’s what abstraction layers are for. */ - char buffer[xcb_list_fonts_with_info_name_length(reply)+1]; - memset(buffer, 0, sizeof(buffer)); - memcpy(buffer, xcb_list_fonts_with_info_name(reply), sizeof(buffer)-1); - new->name = strdup(buffer); - new->pattern = strdup(pattern); - new->height = reply->font_ascent + reply->font_descent; + /* Oh my, this is so ugly :-(. Why can’t they just return a null-terminated + * string? That’s what abstraction layers are for. */ + char buffer[xcb_list_fonts_with_info_name_length(reply)+1]; + memset(buffer, 0, sizeof(buffer)); + memcpy(buffer, xcb_list_fonts_with_info_name(reply), sizeof(buffer)-1); + new->name = strdup(buffer); + new->pattern = strdup(pattern); + new->height = reply->font_ascent + reply->font_descent; - /* Actually load the font */ - new->id = xcb_generate_id(c); - xcb_void_cookie_t font_cookie = xcb_open_font_checked(c, new->id, strlen(pattern), pattern); - check_error(c, font_cookie, "Could not open font"); + /* Actually load the font */ + new->id = xcb_generate_id(c); + xcb_void_cookie_t font_cookie = xcb_open_font_checked(c, new->id, strlen(pattern), pattern); + check_error(c, font_cookie, "Could not open font"); - return new; + return new; } diff --git a/src/handlers.c b/src/handlers.c index 58640368..f18993e7 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #include #include #include @@ -16,20 +26,20 @@ #include "font.h" static void set_focus(xcb_connection_t *conn, Client *client) { - /* Update container */ - Client *old_client = client->container->currently_focused; - client->container->currently_focused = client; - - current_col = client->container->col; - current_row = client->container->row; - - /* Set focus to the entered window, and flush xcb buffer immediately */ - xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, client->child, XCB_CURRENT_TIME); - /* Update last/current client’s titlebar */ - if (old_client != NULL) - decorate_window(conn, old_client); - decorate_window(conn, client); - xcb_flush(conn); + /* Update container */ + Client *old_client = client->container->currently_focused; + client->container->currently_focused = client; + + current_col = client->container->col; + current_row = client->container->row; + + /* Set focus to the entered window, and flush xcb buffer immediately */ + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, client->child, XCB_CURRENT_TIME); + /* Update last/current client’s titlebar */ + if (old_client != NULL) + decorate_window(conn, old_client); + decorate_window(conn, client); + xcb_flush(conn); } @@ -39,10 +49,10 @@ static void set_focus(xcb_connection_t *conn, Client *client) { * */ int handle_key_release(void *ignored, xcb_connection_t *conn, xcb_key_release_event_t *event) { - printf("got key release, just passing\n"); - xcb_allow_events(conn, XCB_ALLOW_REPLAY_KEYBOARD, event->time); - xcb_flush(conn); - return 1; + printf("got key release, just passing\n"); + xcb_allow_events(conn, XCB_ALLOW_REPLAY_KEYBOARD, event->time); + xcb_flush(conn); + return 1; } /* @@ -53,48 +63,48 @@ int handle_key_release(void *ignored, xcb_connection_t *conn, xcb_key_release_ev * */ int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_t *event) { - printf("Keypress %d\n", event->detail); - - /* We need to get the keysym group (There are group 1 to group 4, each holding - two keysyms (without shift and with shift) using Xkb because X fails to - provide them reliably (it works in Xephyr, it does not in real X) */ - XkbStateRec state; - if (XkbGetState(xkbdpy, XkbUseCoreKbd, &state) == Success && (state.group+1) == 2) - event->state |= 0x2; - - printf("state %d\n", event->state); - - /* Find the binding */ - /* TODO: event->state durch eine bitmask filtern und dann direkt vergleichen */ - Binding *bind, *best_match = TAILQ_END(&bindings); - TAILQ_FOREACH(bind, &bindings, bindings) { - if (bind->keycode == event->detail && - (bind->mods & event->state) == bind->mods) { - if (best_match == TAILQ_END(&bindings) || - bind->mods > best_match->mods) - best_match = bind; - } - } - - /* No match? Then it was an actively grabbed key, that is with Mode_switch, and - the user did not press Mode_switch, so just pass it… */ - if (best_match == TAILQ_END(&bindings)) { - xcb_allow_events(conn, ReplayKeyboard, event->time); - xcb_flush(conn); - return 1; - } - - if (event->state & 0x2) { - printf("that's mode_switch\n"); - parse_command(conn, best_match->command); - printf("ok, hiding this event.\n"); - xcb_allow_events(conn, SyncKeyboard, event->time); - xcb_flush(conn); - return 1; - } - - parse_command(conn, best_match->command); - return 1; + printf("Keypress %d\n", event->detail); + + /* We need to get the keysym group (There are group 1 to group 4, each holding + two keysyms (without shift and with shift) using Xkb because X fails to + provide them reliably (it works in Xephyr, it does not in real X) */ + XkbStateRec state; + if (XkbGetState(xkbdpy, XkbUseCoreKbd, &state) == Success && (state.group+1) == 2) + event->state |= 0x2; + + printf("state %d\n", event->state); + + /* Find the binding */ + /* TODO: event->state durch eine bitmask filtern und dann direkt vergleichen */ + Binding *bind, *best_match = TAILQ_END(&bindings); + TAILQ_FOREACH(bind, &bindings, bindings) { + if (bind->keycode == event->detail && + (bind->mods & event->state) == bind->mods) { + if (best_match == TAILQ_END(&bindings) || + bind->mods > best_match->mods) + best_match = bind; + } + } + + /* No match? Then it was an actively grabbed key, that is with Mode_switch, and + the user did not press Mode_switch, so just pass it… */ + if (best_match == TAILQ_END(&bindings)) { + xcb_allow_events(conn, ReplayKeyboard, event->time); + xcb_flush(conn); + return 1; + } + + if (event->state & 0x2) { + printf("that's mode_switch\n"); + parse_command(conn, best_match->command); + printf("ok, hiding this event.\n"); + xcb_allow_events(conn, SyncKeyboard, event->time); + xcb_flush(conn); + return 1; + } + + parse_command(conn, best_match->command); + return 1; } @@ -103,147 +113,147 @@ int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_ * */ int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_event_t *event) { - printf("enter_notify\n"); + printf("enter_notify\n"); - /* This was either a focus for a client’s parent (= titlebar)… */ - Client *client = table_get(byParent, event->event); - /* …or the client itself */ - if (client == NULL) - client = table_get(byChild, event->event); + /* This was either a focus for a client’s parent (= titlebar)… */ + Client *client = table_get(byParent, event->event); + /* …or the client itself */ + if (client == NULL) + client = table_get(byChild, event->event); - /* If not, then this event is not interesting. This should not happen */ - if (client == NULL) { - printf("DEBUG: Uninteresting enter_notify-event?\n"); - return 1; - } + /* If not, then this event is not interesting. This should not happen */ + if (client == NULL) { + printf("DEBUG: Uninteresting enter_notify-event?\n"); + return 1; + } - set_focus(conn, client); + set_focus(conn, client); - return 1; + return 1; } int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_event_t *event) { - 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) - client = table_get(byParent, event->event); - if (client == NULL) - 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(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)) - return 1; - - printf("that was resize\n"); - - /* Open a new window, the resizebar. Grab the pointer and move the window around - as the user moves the pointer. */ - - - /* 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, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, grabwin, XCB_NONE, XCB_CURRENT_TIME); - - xcb_flush(conn); - - xcb_generic_event_t *inside_event; - /* I’ve 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) { - handle_event(NULL, conn, 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: - values[0] = ((xcb_motion_notify_event_t*)inside_event)->root_x; - xcb_configure_window(conn, helpwin, XCB_CONFIG_WINDOW_X, values); - xcb_flush(conn); - break; - case XCB_EXPOSE: - /* Use original handler */ - xcb_event_handle(&evenths, inside_event); - break; - default: - printf("Ignoring event of type %d\n", nr); - break; - } - printf("---\n"); - free(inside_event); - } - - xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); - xcb_destroy_window(conn, helpwin); - xcb_destroy_window(conn, grabwin); - xcb_flush(conn); - - return 1; + 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) + client = table_get(byParent, event->event); + if (client == NULL) + 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(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)) + return 1; + + printf("that was resize\n"); + + /* Open a new window, the resizebar. Grab the pointer and move the window around + as the user moves the pointer. */ + + + /* 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, + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, grabwin, XCB_NONE, XCB_CURRENT_TIME); + + xcb_flush(conn); + + xcb_generic_event_t *inside_event; + /* I’ve 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) { + handle_event(NULL, conn, 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: + values[0] = ((xcb_motion_notify_event_t*)inside_event)->root_x; + xcb_configure_window(conn, helpwin, XCB_CONFIG_WINDOW_X, values); + xcb_flush(conn); + break; + case XCB_EXPOSE: + /* Use original handler */ + xcb_event_handle(&evenths, inside_event); + break; + default: + printf("Ignoring event of type %d\n", nr); + break; + } + printf("---\n"); + free(inside_event); + } + + xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); + xcb_destroy_window(conn, helpwin); + xcb_destroy_window(conn, grabwin); + xcb_flush(conn); + + return 1; } int handle_map_notify_event(void *prophs, xcb_connection_t *conn, xcb_map_notify_event_t *event) { - window_attributes_t wa = { TAG_VALUE }; - wa.u.override_redirect = event->override_redirect; - printf("MapNotify for 0x%08x.\n", event->window); - manage_window(prophs, conn, event->window, wa); - return 1; + window_attributes_t wa = { TAG_VALUE }; + wa.u.override_redirect = event->override_redirect; + printf("MapNotify for 0x%08x.\n", event->window); + manage_window(prophs, conn, event->window, wa); + return 1; } /* @@ -252,42 +262,42 @@ int handle_map_notify_event(void *prophs, xcb_connection_t *conn, xcb_map_notify * */ int handle_unmap_notify_event(void *data, xcb_connection_t *c, xcb_unmap_notify_event_t *e) { - Client *client = table_remove(byChild, e->event); - xcb_window_t root; - printf("UnmapNotify for 0x%08x (received from 0x%08x): ", e->window, e->event); - if(!client) - { - printf("not a managed window. Ignoring.\n"); - return 0; - } - - int rows, cols; - Client *con_client; - /* TODO: clear this up */ - for (cols = 0; cols < c_ws->cols; cols++) - for (rows = 0; rows < c_ws->rows; rows++) - CIRCLEQ_FOREACH(con_client, &(CUR_TABLE[cols][rows]->clients), clients) - if (con_client == client) { - printf("removing from container\n"); - if (client->container->currently_focused == client) - client->container->currently_focused = NULL; - CIRCLEQ_REMOVE(&(CUR_TABLE[cols][rows]->clients), con_client, clients); - break; - } - - - - root = xcb_setup_roots_iterator(xcb_get_setup(c)).data->root; - printf("child of 0x%08x.\n", client->frame); - xcb_reparent_window(c, client->child, root, 0, 0); - xcb_destroy_window(c, client->frame); - xcb_flush(c); - table_remove(byParent, client->frame); - free(client); - - render_layout(c); - - return 1; + Client *client = table_remove(byChild, e->event); + xcb_window_t root; + printf("UnmapNotify for 0x%08x (received from 0x%08x): ", e->window, e->event); + if(!client) + { + printf("not a managed window. Ignoring.\n"); + return 0; + } + + int rows, cols; + Client *con_client; + /* TODO: clear this up */ + for (cols = 0; cols < c_ws->cols; cols++) + for (rows = 0; rows < c_ws->rows; rows++) + CIRCLEQ_FOREACH(con_client, &(CUR_TABLE[cols][rows]->clients), clients) + if (con_client == client) { + printf("removing from container\n"); + if (client->container->currently_focused == client) + client->container->currently_focused = NULL; + CIRCLEQ_REMOVE(&(CUR_TABLE[cols][rows]->clients), con_client, clients); + break; + } + + + + root = xcb_setup_roots_iterator(xcb_get_setup(c)).data->root; + printf("child of 0x%08x.\n", client->frame); + xcb_reparent_window(c, client->child, root, 0, 0); + xcb_destroy_window(c, client->frame); + xcb_flush(c); + table_remove(byParent, client->frame); + free(client); + + render_layout(c); + + return 1; } /* @@ -295,21 +305,21 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *c, xcb_unmap_notify_ * */ int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state, - xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) { - printf("window's name changed.\n"); - Client *client = table_get(byChild, window); - if (client == NULL) - return 1; + xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) { + printf("window's name changed.\n"); + Client *client = table_get(byChild, window); + if (client == NULL) + return 1; - client->name_len = xcb_get_property_value_length(prop); - client->name = malloc(client->name_len); - strncpy(client->name, xcb_get_property_value(prop), client->name_len); - printf("rename to \"%.*s\".\n", client->name_len, client->name); + client->name_len = xcb_get_property_value_length(prop); + client->name = malloc(client->name_len); + strncpy(client->name, xcb_get_property_value(prop), client->name_len); + printf("rename to \"%.*s\".\n", client->name_len, client->name); - decorate_window(conn, client); - xcb_flush(conn); + decorate_window(conn, client); + xcb_flush(conn); - return 1; + return 1; } /* @@ -317,10 +327,10 @@ int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state, * */ int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t *e) { - printf("handle_expose_event()\n"); - Client *client = table_get(byParent, e->window); - if(!client || e->count != 0) - return 1; - decorate_window(conn, client); - return 1; + printf("handle_expose_event()\n"); + Client *client = table_get(byParent, e->window); + if(!client || e->count != 0) + return 1; + decorate_window(conn, client); + return 1; } diff --git a/src/layout.c b/src/layout.c index d98dc181..131515f5 100644 --- a/src/layout.c +++ b/src/layout.c @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #define _GNU_SOURCE #include #include @@ -17,109 +27,109 @@ * */ void decorate_window(xcb_connection_t *conn, Client *client) { - uint32_t mask = 0; - uint32_t values[3]; - i3Font *font = load_font(conn, pattern); - uint32_t background_color, - text_color, - border_color; - - if (client->container->currently_focused == client) { - background_color = get_colorpixel(conn, client->frame, "#285577"); - text_color = get_colorpixel(conn, client->frame, "#ffffff"); - border_color = get_colorpixel(conn, client->frame, "#4c7899"); - } else { - background_color = get_colorpixel(conn, client->frame, "#222222"); - text_color = get_colorpixel(conn, client->frame, "#888888"); - border_color = get_colorpixel(conn, client->frame, "#333333"); - } - - /* Our plan is the following: - - Draw a rect around the whole client in background_color - - Draw two lines in a lighter color - - Draw the window’s title - - Note that xcb_image_text apparently adds 1xp border around the font? Can anyone confirm this? - */ - - /* Draw a green rectangle around the window */ - mask = XCB_GC_FOREGROUND; - values[0] = background_color; - xcb_change_gc(conn, client->titlegc, mask, values); - - xcb_rectangle_t rect = {0, 0, client->width, client->height}; - xcb_poly_fill_rectangle(conn, client->frame, client->titlegc, 1, &rect); - - /* Draw the lines */ - /* TODO: this needs to be more beautiful somewhen. maybe stdarg + change_gc(gc, ...) ? */ + uint32_t mask = 0; + uint32_t values[3]; + i3Font *font = load_font(conn, pattern); + uint32_t background_color, + text_color, + border_color; + + if (client->container->currently_focused == client) { + background_color = get_colorpixel(conn, client->frame, "#285577"); + text_color = get_colorpixel(conn, client->frame, "#ffffff"); + border_color = get_colorpixel(conn, client->frame, "#4c7899"); + } else { + background_color = get_colorpixel(conn, client->frame, "#222222"); + text_color = get_colorpixel(conn, client->frame, "#888888"); + border_color = get_colorpixel(conn, client->frame, "#333333"); + } + + /* Our plan is the following: + - Draw a rect around the whole client in background_color + - Draw two lines in a lighter color + - Draw the window’s title + + Note that xcb_image_text apparently adds 1xp border around the font? Can anyone confirm this? + */ + + /* Draw a green rectangle around the window */ + mask = XCB_GC_FOREGROUND; + values[0] = background_color; + xcb_change_gc(conn, client->titlegc, mask, values); + + xcb_rectangle_t rect = {0, 0, client->width, client->height}; + xcb_poly_fill_rectangle(conn, client->frame, client->titlegc, 1, &rect); + + /* Draw the lines */ + /* TODO: this needs to be more beautiful somewhen. maybe stdarg + change_gc(gc, ...) ? */ #define DRAW_LINE(colorpixel, x, y, to_x, to_y) { \ - uint32_t draw_values[1]; \ - draw_values[0] = colorpixel; \ - xcb_change_gc(conn, client->titlegc, XCB_GC_FOREGROUND, draw_values); \ - xcb_point_t points[] = {{x, y}, {to_x, to_y}}; \ - xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, client->frame, client->titlegc, 2, points); \ - } + uint32_t draw_values[1]; \ + draw_values[0] = colorpixel; \ + xcb_change_gc(conn, client->titlegc, XCB_GC_FOREGROUND, draw_values); \ + xcb_point_t points[] = {{x, y}, {to_x, to_y}}; \ + xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, client->frame, client->titlegc, 2, points); \ + } - DRAW_LINE(border_color, 2, 0, client->width, 0); - DRAW_LINE(border_color, 2, font->height + 3, 2 + client->width, font->height + 3); + DRAW_LINE(border_color, 2, 0, client->width, 0); + DRAW_LINE(border_color, 2, font->height + 3, 2 + client->width, font->height + 3); - /* Draw the font */ - mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; + /* Draw the font */ + mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; - values[0] = text_color; - values[1] = background_color; - values[2] = font->id; + values[0] = text_color; + values[1] = background_color; + values[2] = font->id; - xcb_change_gc(conn, client->titlegc, mask, values); + xcb_change_gc(conn, client->titlegc, mask, values); - /* TODO: utf8? */ - char *label; - asprintf(&label, "(%08x) %.*s", client->frame, client->name_len, client->name); + /* TODO: utf8? */ + char *label; + asprintf(&label, "(%08x) %.*s", client->frame, client->name_len, client->name); xcb_void_cookie_t text_cookie = xcb_image_text_8_checked(conn, strlen(label), client->frame, - client->titlegc, 3 /* X */, font->height /* Y = baseline of font */, label); - check_error(conn, text_cookie, "Could not draw client's title"); - free(label); + client->titlegc, 3 /* X */, font->height /* Y = baseline of font */, label); + check_error(conn, text_cookie, "Could not draw client's title"); + free(label); } static void render_container(xcb_connection_t *connection, Container *container) { - Client *client; - i3Font *font = load_font(connection, pattern); - - if (container->mode == MODE_DEFAULT) { - int num_clients = 0; - CIRCLEQ_FOREACH(client, &(container->clients), clients) - num_clients++; - printf("got %d clients in this default container.\n", num_clients); - - int current_client = 0; - CIRCLEQ_FOREACH(client, &(container->clients), clients) { - /* TODO: at the moment, every column/row is screen / num_cols. This - * needs to be changed to "percentage of the screen" by - * default and adjustable by the user if necessary. - */ + Client *client; + i3Font *font = load_font(connection, pattern); + + if (container->mode == MODE_DEFAULT) { + int num_clients = 0; + CIRCLEQ_FOREACH(client, &(container->clients), clients) + num_clients++; + printf("got %d clients in this default container.\n", num_clients); + + int current_client = 0; + CIRCLEQ_FOREACH(client, &(container->clients), clients) { + /* TODO: at the moment, every column/row is screen / num_cols. This + * needs to be changed to "percentage of the screen" by + * default and adjustable by the user if necessary. + */ /* 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->x != (client->x = container->x + (container->col * container->width))) | + if ((client->x != (client->x = container->x + (container->col * container->width))) | (client->y != (client->y = container->y + (container->row * container->height + (container->height / num_clients) * current_client)))) { - printf("frame needs to be pushed to %dx%d\n", client->x, client->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 */ - xcb_configure_window(connection, client->frame, - XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, &(client->x)); - } - - /* TODO: vertical default layout */ - if ((client->width != (client->width = container->width)) | + printf("frame needs to be pushed to %dx%d\n", client->x, client->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 */ + xcb_configure_window(connection, client->frame, + XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, &(client->x)); + } + + /* TODO: vertical default layout */ + if ((client->width != (client->width = container->width)) | (client->height != (client->height = container->height / num_clients))) { - xcb_configure_window(connection, client->frame, - XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, + xcb_configure_window(connection, client->frame, + XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, &(client->width)); - /* Adjust the position of the child inside its frame. - * The coordinates of the child are relative to its frame, we - * add a border of 2 pixel to each value */ + /* Adjust the position of the child inside its frame. + * The coordinates of the child are relative to its frame, we + * add a border of 2 pixel to each value */ uint32_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | @@ -129,51 +139,51 @@ static void render_container(xcb_connection_t *connection, Container *container) client->width - (2 + 2), /* width */ client->height - ((font->height + 2 + 2) + 2)}; /* height */ - printf("child itself will be at %dx%d with size %dx%d\n", - values[0], values[1], values[2], values[3]); + printf("child itself will be at %dx%d with size %dx%d\n", + values[0], values[1], values[2], values[3]); - xcb_configure_window(connection, client->child, mask, values); - } + xcb_configure_window(connection, client->child, mask, values); + } - decorate_window(connection, client); - current_client++; - } - } else { - /* TODO: Implement stacking */ - } + decorate_window(connection, client); + current_client++; + } + } else { + /* TODO: Implement stacking */ + } } void render_layout(xcb_connection_t *conn) { - int cols, rows; - int screen; - for (screen = 0; screen < num_screens; screen++) { - printf("Rendering screen %d\n", screen); - /* TODO: get the workspace which is active on the screen */ - int width = workspaces[screen].width; - int height = workspaces[screen].height; - - printf("got %d rows and %d cols\n", c_ws->rows, c_ws->cols); - printf("each of them therefore is %d px width and %d px height\n", - width / c_ws->cols, height / c_ws->rows); - - /* Go through the whole table and render what’s necessary */ - for (cols = 0; cols < c_ws->cols; cols++) - for (rows = 0; rows < c_ws->rows; rows++) { - Container *con = CUR_TABLE[cols][rows]; - printf("container has %d colspan, %d rowspan\n", - con->colspan, con->rowspan); - /* Update position of the container */ - con->row = rows; - con->col = cols; - con->x = workspaces[screen].x; - con->y = workspaces[screen].y; - con->width = (width / c_ws->cols) * con->colspan; - con->height = (height / c_ws->rows) * con->rowspan; - - /* Render it */ - render_container(conn, CUR_TABLE[cols][rows]); - } - } - - xcb_flush(conn); + int cols, rows; + int screen; + for (screen = 0; screen < num_screens; screen++) { + printf("Rendering screen %d\n", screen); + /* TODO: get the workspace which is active on the screen */ + int width = workspaces[screen].width; + int height = workspaces[screen].height; + + printf("got %d rows and %d cols\n", c_ws->rows, c_ws->cols); + printf("each of them therefore is %d px width and %d px height\n", + width / c_ws->cols, height / c_ws->rows); + + /* Go through the whole table and render what’s necessary */ + for (cols = 0; cols < c_ws->cols; cols++) + for (rows = 0; rows < c_ws->rows; rows++) { + Container *con = CUR_TABLE[cols][rows]; + printf("container has %d colspan, %d rowspan\n", + con->colspan, con->rowspan); + /* Update position of the container */ + con->row = rows; + con->col = cols; + con->x = workspaces[screen].x; + con->y = workspaces[screen].y; + con->width = (width / c_ws->cols) * con->colspan; + con->height = (height / c_ws->rows) * con->rowspan; + + /* Render it */ + render_container(conn, CUR_TABLE[cols][rows]); + } + } + + xcb_flush(conn); } diff --git a/src/mainx.c b/src/mainx.c index 03be0a3d..a73ea6f9 100644 --- a/src/mainx.c +++ b/src/mainx.c @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #define _GNU_SOURCE #include #include @@ -52,52 +62,52 @@ int num_screens = 0; */ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *c, xcb_window_t window, window_attributes_t wa) { - printf("managing window.\n"); - xcb_drawable_t d = { window }; - xcb_get_geometry_cookie_t geomc; - xcb_get_geometry_reply_t *geom; - xcb_get_window_attributes_reply_t *attr = 0; - if(wa.tag == TAG_COOKIE) - { - attr = xcb_get_window_attributes_reply(c, wa.u.cookie, 0); - if(!attr) - return; - if(attr->map_state != XCB_MAP_STATE_VIEWABLE) - { - printf("Window 0x%08x is not mapped. Ignoring.\n", window); - free(attr); - return; - } - wa.tag = TAG_VALUE; - wa.u.override_redirect = attr->override_redirect; - } - if(!wa.u.override_redirect && table_get(byChild, window)) - { - printf("Window 0x%08x already managed. Ignoring.\n", window); - free(attr); - return; - } - if(wa.u.override_redirect) - { - printf("Window 0x%08x has override-redirect set. Ignoring.\n", window); - free(attr); - return; - } - geomc = xcb_get_geometry(c, d); - if(!attr) - { - wa.tag = TAG_COOKIE; - wa.u.cookie = xcb_get_window_attributes(c, window); - attr = xcb_get_window_attributes_reply(c, wa.u.cookie, 0); - } - geom = xcb_get_geometry_reply(c, geomc, 0); - if(attr && geom) - { - reparent_window(c, window, attr->visual, geom->root, geom->depth, geom->x, geom->y, geom->width, geom->height); - xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME); - } - free(attr); - free(geom); + printf("managing window.\n"); + xcb_drawable_t d = { window }; + xcb_get_geometry_cookie_t geomc; + xcb_get_geometry_reply_t *geom; + xcb_get_window_attributes_reply_t *attr = 0; + if(wa.tag == TAG_COOKIE) + { + attr = xcb_get_window_attributes_reply(c, wa.u.cookie, 0); + if(!attr) + return; + if(attr->map_state != XCB_MAP_STATE_VIEWABLE) + { + printf("Window 0x%08x is not mapped. Ignoring.\n", window); + free(attr); + return; + } + wa.tag = TAG_VALUE; + wa.u.override_redirect = attr->override_redirect; + } + if(!wa.u.override_redirect && table_get(byChild, window)) + { + printf("Window 0x%08x already managed. Ignoring.\n", window); + free(attr); + return; + } + if(wa.u.override_redirect) + { + printf("Window 0x%08x has override-redirect set. Ignoring.\n", window); + free(attr); + return; + } + geomc = xcb_get_geometry(c, d); + if(!attr) + { + wa.tag = TAG_COOKIE; + wa.u.cookie = xcb_get_window_attributes(c, window); + attr = xcb_get_window_attributes_reply(c, wa.u.cookie, 0); + } + geom = xcb_get_geometry_reply(c, geomc, 0); + if(attr && geom) + { + reparent_window(c, window, attr->visual, geom->root, geom->depth, geom->x, geom->y, geom->width, geom->height); + xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME); + } + free(attr); + free(geom); } /* @@ -108,299 +118,299 @@ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *c, xcb_win * */ void reparent_window(xcb_connection_t *conn, xcb_window_t child, - xcb_visualid_t visual, xcb_window_t root, uint8_t depth, - int16_t x, int16_t y, uint16_t width, uint16_t height) { - - Client *new = table_get(byChild, child); - if (new == NULL) { - /* TODO: When does this happen for existing clients? Is that a bug? */ - printf("oh, it's new\n"); - new = calloc(sizeof(Client), 1); - /* We initialize x and y with the invalid coordinates -1 so that they will - get updated at the next render_layout() at any case */ - new->x = -1; - new->y = -1; - } - uint32_t mask = 0; - uint32_t values[3]; - - /* Insert into the currently active container */ - CIRCLEQ_INSERT_TAIL(&(CUR_CELL->clients), new, clients); - - /* Update the data structures */ - CUR_CELL->currently_focused = new; - new->container = CUR_CELL; - - new->frame = xcb_generate_id(conn); - new->child = child; - new->width = width; - new->height = height; - - /* Don’t generate events for our new window, it should *not* be managed */ - mask |= XCB_CW_OVERRIDE_REDIRECT; - values[0] = 1; - - /* We want to know when… */ - mask |= XCB_CW_EVENT_MASK; - values[1] = XCB_EVENT_MASK_BUTTON_PRESS | /* …mouse is pressed/released */ - XCB_EVENT_MASK_BUTTON_RELEASE | - XCB_EVENT_MASK_EXPOSURE | /* …our window needs to be redrawn */ - XCB_EVENT_MASK_ENTER_WINDOW; /* …user moves cursor inside our window */ - - printf("Reparenting 0x%08x under 0x%08x.\n", child, new->frame); - - i3Font *font = load_font(conn, pattern); - - /* Yo dawg, I heard you like windows, so I create a window around your window… */ - xcb_create_window(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, - visual, - mask, - values); - xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child); - - /* Map the window on the screen (= make it visible) */ - xcb_map_window(conn, new->frame); - - /* Generate a graphics context for the titlebar */ - new->titlegc = xcb_generate_id(conn); - xcb_create_gc(conn, new->titlegc, new->frame, 0, 0); - - /* Put our data structure (Client) into the table */ - table_put(byParent, new->frame, new); - table_put(byChild, child, new); - - /* Moves the original window into the new frame we've created for it */ - xcb_reparent_window(conn, child, new->frame, 0, font->height); - - /* We are interested in property changes */ - mask = XCB_CW_EVENT_MASK; - values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE | - XCB_EVENT_MASK_STRUCTURE_NOTIFY | - XCB_EVENT_MASK_ENTER_WINDOW | - XCB_EVENT_MASK_BUTTON_PRESS; - xcb_change_window_attributes(conn, child, mask, values); - - /* We need to grab the mouse buttons for click to focus */ - xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE, - 1 /* left mouse button */, - XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */); - - /* Focus the new window */ - xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, new->child, XCB_CURRENT_TIME); - - render_layout(conn); + xcb_visualid_t visual, xcb_window_t root, uint8_t depth, + int16_t x, int16_t y, uint16_t width, uint16_t height) { + + Client *new = table_get(byChild, child); + if (new == NULL) { + /* TODO: When does this happen for existing clients? Is that a bug? */ + printf("oh, it's new\n"); + new = calloc(sizeof(Client), 1); + /* We initialize x and y with the invalid coordinates -1 so that they will + get updated at the next render_layout() at any case */ + new->x = -1; + new->y = -1; + } + uint32_t mask = 0; + uint32_t values[3]; + + /* Insert into the currently active container */ + CIRCLEQ_INSERT_TAIL(&(CUR_CELL->clients), new, clients); + + /* Update the data structures */ + CUR_CELL->currently_focused = new; + new->container = CUR_CELL; + + new->frame = xcb_generate_id(conn); + new->child = child; + new->width = width; + new->height = height; + + /* Don’t generate events for our new window, it should *not* be managed */ + mask |= XCB_CW_OVERRIDE_REDIRECT; + values[0] = 1; + + /* We want to know when… */ + mask |= XCB_CW_EVENT_MASK; + values[1] = XCB_EVENT_MASK_BUTTON_PRESS | /* …mouse is pressed/released */ + XCB_EVENT_MASK_BUTTON_RELEASE | + XCB_EVENT_MASK_EXPOSURE | /* …our window needs to be redrawn */ + XCB_EVENT_MASK_ENTER_WINDOW; /* …user moves cursor inside our window */ + + printf("Reparenting 0x%08x under 0x%08x.\n", child, new->frame); + + i3Font *font = load_font(conn, pattern); + + /* Yo dawg, I heard you like windows, so I create a window around your window… */ + xcb_create_window(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, + visual, + mask, + values); + xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child); + + /* Map the window on the screen (= make it visible) */ + xcb_map_window(conn, new->frame); + + /* Generate a graphics context for the titlebar */ + new->titlegc = xcb_generate_id(conn); + xcb_create_gc(conn, new->titlegc, new->frame, 0, 0); + + /* Put our data structure (Client) into the table */ + table_put(byParent, new->frame, new); + table_put(byChild, child, new); + + /* Moves the original window into the new frame we've created for it */ + xcb_reparent_window(conn, child, new->frame, 0, font->height); + + /* We are interested in property changes */ + mask = XCB_CW_EVENT_MASK; + values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE | + XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_ENTER_WINDOW | + XCB_EVENT_MASK_BUTTON_PRESS; + xcb_change_window_attributes(conn, child, mask, values); + + /* We need to grab the mouse buttons for click to focus */ + xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS, + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE, + 1 /* left mouse button */, + XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */); + + /* Focus the new window */ + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, new->child, XCB_CURRENT_TIME); + + render_layout(conn); } void manage_existing_windows(xcb_connection_t *c, xcb_property_handlers_t *prophs, xcb_window_t root) { - xcb_query_tree_cookie_t wintree; - xcb_query_tree_reply_t *rep; - int i, len; - xcb_window_t *children; - xcb_get_window_attributes_cookie_t *cookies; - - wintree = xcb_query_tree(c, root); - rep = xcb_query_tree_reply(c, wintree, 0); - if(!rep) - return; - len = xcb_query_tree_children_length(rep); - cookies = malloc(len * sizeof(*cookies)); - if(!cookies) - { - free(rep); - return; - } - children = xcb_query_tree_children(rep); - for(i = 0; i < len; ++i) - cookies[i] = xcb_get_window_attributes(c, children[i]); - for(i = 0; i < len; ++i) - { - window_attributes_t wa = { TAG_COOKIE, { cookies[i] } }; - manage_window(prophs, c, children[i], wa); - } - free(rep); + xcb_query_tree_cookie_t wintree; + xcb_query_tree_reply_t *rep; + int i, len; + xcb_window_t *children; + xcb_get_window_attributes_cookie_t *cookies; + + wintree = xcb_query_tree(c, root); + rep = xcb_query_tree_reply(c, wintree, 0); + if(!rep) + return; + len = xcb_query_tree_children_length(rep); + cookies = malloc(len * sizeof(*cookies)); + if(!cookies) + { + free(rep); + return; + } + children = xcb_query_tree_children(rep); + for(i = 0; i < len; ++i) + cookies[i] = xcb_get_window_attributes(c, children[i]); + for(i = 0; i < len; ++i) + { + window_attributes_t wa = { TAG_COOKIE, { cookies[i] } }; + manage_window(prophs, c, children[i], wa); + } + free(rep); } static void initialize_xinerama(xcb_connection_t *conn) { - xcb_xinerama_query_screens_reply_t *reply; - xcb_xinerama_screen_info_t *screen_info; - int screen; + xcb_xinerama_query_screens_reply_t *reply; + xcb_xinerama_screen_info_t *screen_info; + int screen; - if (!xcb_get_extension_data(conn, &xcb_xinerama_id)->present) { - printf("Xinerama extension not found, disabling.\n"); - return; - } + if (!xcb_get_extension_data(conn, &xcb_xinerama_id)->present) { + printf("Xinerama extension not found, disabling.\n"); + return; + } - if (!xcb_xinerama_is_active_reply(conn, xcb_xinerama_is_active(conn), NULL)->state) { - printf("Xinerama is not active (in your X-Server), disabling.\n"); - return; - } + if (!xcb_xinerama_is_active_reply(conn, xcb_xinerama_is_active(conn), NULL)->state) { + printf("Xinerama is not active (in your X-Server), disabling.\n"); + return; + } - reply = xcb_xinerama_query_screens_reply(conn, xcb_xinerama_query_screens_unchecked(conn), NULL); - /* TODO: error check */ - screen_info = xcb_xinerama_query_screens_screen_info(reply); + reply = xcb_xinerama_query_screens_reply(conn, xcb_xinerama_query_screens_unchecked(conn), NULL); + /* TODO: error check */ + screen_info = xcb_xinerama_query_screens_screen_info(reply); - num_screens = xcb_xinerama_query_screens_screen_info_length(reply); + num_screens = xcb_xinerama_query_screens_screen_info_length(reply); - /* Just go through each workspace and associate as many screens as we can. */ - for (screen = 0; screen < num_screens; screen++) { - workspaces[screen].x = screen_info[screen].x_org; - workspaces[screen].y = screen_info[screen].y_org; - workspaces[screen].width = screen_info[screen].width; - workspaces[screen].height = screen_info[screen].height; - workspaces[screen].screen_num = screen; + /* Just go through each workspace and associate as many screens as we can. */ + for (screen = 0; screen < num_screens; screen++) { + workspaces[screen].x = screen_info[screen].x_org; + workspaces[screen].y = screen_info[screen].y_org; + workspaces[screen].width = screen_info[screen].width; + workspaces[screen].height = screen_info[screen].height; + workspaces[screen].screen_num = screen; - printf("found Xinerama screen: %d x %d at %d x %d\n", - screen_info[screen].width, screen_info[screen].height, - screen_info[screen].x_org, screen_info[screen].y_org); - } + printf("found Xinerama screen: %d x %d at %d x %d\n", + screen_info[screen].width, screen_info[screen].height, + screen_info[screen].x_org, screen_info[screen].y_org); + } - free(screen_info); + free(screen_info); } int main(int argc, char *argv[], char *env[]) { - int i, screens; - xcb_connection_t *c; - xcb_property_handlers_t prophs; - xcb_window_t root; + int i, screens; + xcb_connection_t *c; + xcb_property_handlers_t prophs; + xcb_window_t root; - /* Initialize the table data structures for each workspace */ - init_table(); + /* Initialize the table data structures for each workspace */ + init_table(); - memset(&evenths, 0, sizeof(xcb_event_handlers_t)); - memset(&prophs, 0, sizeof(xcb_property_handlers_t)); + memset(&evenths, 0, sizeof(xcb_event_handlers_t)); + memset(&prophs, 0, sizeof(xcb_property_handlers_t)); - byChild = alloc_table(); - byParent = alloc_table(); + byChild = alloc_table(); + byParent = alloc_table(); - TAILQ_INIT(&bindings); + TAILQ_INIT(&bindings); - c = xcb_connect(NULL, &screens); + c = xcb_connect(NULL, &screens); - /* TODO: this has to be more beautiful somewhen */ - int major, minor, error; + /* TODO: this has to be more beautiful somewhen */ + int major, minor, error; - major = XkbMajorVersion; - minor = XkbMinorVersion; + major = XkbMajorVersion; + minor = XkbMinorVersion; - int evBase, errBase; + int evBase, errBase; - if ((xkbdpy = XkbOpenDisplay(getenv("DISPLAY"), &evBase, &errBase, &major, &minor, &error)) == NULL) { - fprintf(stderr, "XkbOpenDisplay() failed\n"); - return 1; - } + if ((xkbdpy = XkbOpenDisplay(getenv("DISPLAY"), &evBase, &errBase, &major, &minor, &error)) == NULL) { + fprintf(stderr, "XkbOpenDisplay() failed\n"); + return 1; + } - int i1; - if (!XkbQueryExtension(xkbdpy,&i1,&evBase,&errBase,&major,&minor)) { - fprintf(stderr, "XKB not supported by X-server\n"); - return 1; - } - /* end of ugliness */ + int i1; + if (!XkbQueryExtension(xkbdpy,&i1,&evBase,&errBase,&major,&minor)) { + fprintf(stderr, "XKB not supported by X-server\n"); + return 1; + } + /* end of ugliness */ - xcb_event_handlers_init(c, &evenths); - for(i = 2; i < 128; ++i) - xcb_event_set_handler(&evenths, i, handle_event, 0); + xcb_event_handlers_init(c, &evenths); + for(i = 2; i < 128; ++i) + xcb_event_set_handler(&evenths, i, handle_event, 0); - for(i = 0; i < 256; ++i) - xcb_event_set_error_handler(&evenths, i, (xcb_generic_error_handler_t)handle_event, 0); + for(i = 0; i < 256; ++i) + xcb_event_set_error_handler(&evenths, i, (xcb_generic_error_handler_t)handle_event, 0); - /* Expose = an Application should redraw itself. That is, we have to redraw our - * contents (= top/bottom bar, titlebars for each window) */ - xcb_event_set_expose_handler(&evenths, handle_expose_event, 0); + /* Expose = an Application should redraw itself. That is, we have to redraw our + * contents (= top/bottom bar, titlebars for each window) */ + xcb_event_set_expose_handler(&evenths, handle_expose_event, 0); - /* Key presses/releases are pretty obvious, I think */ - xcb_event_set_key_press_handler(&evenths, handle_key_press, 0); - xcb_event_set_key_release_handler(&evenths, handle_key_release, 0); + /* Key presses/releases are pretty obvious, I think */ + xcb_event_set_key_press_handler(&evenths, handle_key_press, 0); + xcb_event_set_key_release_handler(&evenths, handle_key_release, 0); - /* Enter window = user moved his mouse over the window */ - xcb_event_set_enter_notify_handler(&evenths, handle_enter_notify, 0); + /* Enter window = user moved his mouse over the window */ + xcb_event_set_enter_notify_handler(&evenths, handle_enter_notify, 0); - /* Button press = user pushed a mouse button over one of our windows */ - xcb_event_set_button_press_handler(&evenths, handle_button_press, 0); + /* Button press = user pushed a mouse button over one of our windows */ + xcb_event_set_button_press_handler(&evenths, handle_button_press, 0); - xcb_event_set_unmap_notify_handler(&evenths, handle_unmap_notify_event, 0); + xcb_event_set_unmap_notify_handler(&evenths, handle_unmap_notify_event, 0); - xcb_property_handlers_init(&prophs, &evenths); - xcb_event_set_map_notify_handler(&evenths, handle_map_notify_event, &prophs); + xcb_property_handlers_init(&prophs, &evenths); + xcb_event_set_map_notify_handler(&evenths, handle_map_notify_event, &prophs); - xcb_watch_wm_name(&prophs, 128, handle_windowname_change, 0); + xcb_watch_wm_name(&prophs, 128, handle_windowname_change, 0); - root = xcb_aux_get_screen(c, screens)->root; - root_win = root; + root = xcb_aux_get_screen(c, screens)->root; + root_win = root; - uint32_t mask = XCB_CW_EVENT_MASK; - uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE }; - xcb_change_window_attributes(c, root, mask, values); + uint32_t mask = XCB_CW_EVENT_MASK; + uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE }; + xcb_change_window_attributes(c, root, mask, values); - #define BIND(key, modifier, cmd) { \ - Binding *new = malloc(sizeof(Binding)); \ - new->keycode = key; \ - new->mods = modifier; \ - new->command = cmd; \ - TAILQ_INSERT_TAIL(&bindings, new, bindings); \ - } + #define BIND(key, modifier, cmd) { \ + Binding *new = malloc(sizeof(Binding)); \ + new->keycode = key; \ + new->mods = modifier; \ + new->command = cmd; \ + TAILQ_INSERT_TAIL(&bindings, new, bindings); \ + } - /* 38 = 'a' */ - BIND(38, BIND_MODE_SWITCH, "foo"); + /* 38 = 'a' */ + BIND(38, BIND_MODE_SWITCH, "foo"); - BIND(30, 0, "exec /usr/pkg/bin/urxvt"); + BIND(30, 0, "exec /usr/pkg/bin/urxvt"); - BIND(44, BIND_MOD_1, "h"); - BIND(45, BIND_MOD_1, "j"); - BIND(46, BIND_MOD_1, "k"); - BIND(47, BIND_MOD_1, "l"); + BIND(44, BIND_MOD_1, "h"); + BIND(45, BIND_MOD_1, "j"); + BIND(46, BIND_MOD_1, "k"); + BIND(47, BIND_MOD_1, "l"); - BIND(44, BIND_MOD_1 | BIND_CONTROL, "sh"); - BIND(45, BIND_MOD_1 | BIND_CONTROL, "sj"); - BIND(46, BIND_MOD_1 | BIND_CONTROL, "sk"); - BIND(47, BIND_MOD_1 | BIND_CONTROL, "sl"); + BIND(44, BIND_MOD_1 | BIND_CONTROL, "sh"); + BIND(45, BIND_MOD_1 | BIND_CONTROL, "sj"); + BIND(46, BIND_MOD_1 | BIND_CONTROL, "sk"); + BIND(47, BIND_MOD_1 | BIND_CONTROL, "sl"); - BIND(44, BIND_MOD_1 | BIND_SHIFT, "mh"); - BIND(45, BIND_MOD_1 | BIND_SHIFT, "mj"); - BIND(46, BIND_MOD_1 | BIND_SHIFT, "mk"); - BIND(47, BIND_MOD_1 | BIND_SHIFT, "ml"); + BIND(44, BIND_MOD_1 | BIND_SHIFT, "mh"); + BIND(45, BIND_MOD_1 | BIND_SHIFT, "mj"); + BIND(46, BIND_MOD_1 | BIND_SHIFT, "mk"); + BIND(47, BIND_MOD_1 | BIND_SHIFT, "ml"); - BIND(10, BIND_MOD_1 , "1"); - BIND(11, BIND_MOD_1 , "2"); - BIND(12, BIND_MOD_1 , "3"); - BIND(13, BIND_MOD_1 , "4"); - BIND(14, BIND_MOD_1 , "5"); - BIND(15, BIND_MOD_1 , "6"); - BIND(16, BIND_MOD_1 , "7"); - BIND(17, BIND_MOD_1 , "8"); - BIND(18, BIND_MOD_1 , "9"); - BIND(19, BIND_MOD_1 , "0"); + BIND(10, BIND_MOD_1 , "1"); + BIND(11, BIND_MOD_1 , "2"); + BIND(12, BIND_MOD_1 , "3"); + BIND(13, BIND_MOD_1 , "4"); + BIND(14, BIND_MOD_1 , "5"); + BIND(15, BIND_MOD_1 , "6"); + BIND(16, BIND_MOD_1 , "7"); + BIND(17, BIND_MOD_1 , "8"); + BIND(18, BIND_MOD_1 , "9"); + BIND(19, BIND_MOD_1 , "0"); - Binding *bind; - TAILQ_FOREACH(bind, &bindings, bindings) { - printf("Grabbing %d\n", bind->keycode); - if (bind->mods & BIND_MODE_SWITCH) - xcb_grab_key(c, 0, root, 0, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC); - else xcb_grab_key(c, 0, root, bind->mods, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); - } + Binding *bind; + TAILQ_FOREACH(bind, &bindings, bindings) { + printf("Grabbing %d\n", bind->keycode); + if (bind->mods & BIND_MODE_SWITCH) + xcb_grab_key(c, 0, root, 0, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC); + else xcb_grab_key(c, 0, root, bind->mods, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); + } - /* check for Xinerama */ - printf("Checking for Xinerama...\n"); - initialize_xinerama(c); + /* check for Xinerama */ + printf("Checking for Xinerama...\n"); + initialize_xinerama(c); - start_application(TERMINAL); + start_application(TERMINAL); - xcb_flush(c); + xcb_flush(c); - manage_existing_windows(c, &prophs, root); + manage_existing_windows(c, &prophs, root); - xcb_event_wait_for_event_loop(&evenths); + xcb_event_wait_for_event_loop(&evenths); - /* not reached */ - return 0; + /* not reached */ + return 0; } diff --git a/src/table.c b/src/table.c index 33d1b4fe..c0f52f11 100644 --- a/src/table.c +++ b/src/table.c @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ /* * This file provides functions for easier accessing of _the_ table * @@ -26,21 +36,21 @@ int current_row = 0; * */ void init_table() { - int i; - memset(workspaces, 0, sizeof(workspaces)); + int i; + memset(workspaces, 0, sizeof(workspaces)); - for (i = 0; i < 10; i++) { - expand_table_cols(&(workspaces[i])); - expand_table_rows(&(workspaces[i])); - } + for (i = 0; i < 10; i++) { + expand_table_cols(&(workspaces[i])); + expand_table_rows(&(workspaces[i])); + } } static void new_container(Container **container) { - Container *new; - new = *container = calloc(sizeof(Container), 1); - CIRCLEQ_INIT(&(new->clients)); - new->colspan = 1; - new->rowspan = 1; + Container *new; + new = *container = calloc(sizeof(Container), 1); + CIRCLEQ_INIT(&(new->clients)); + new->colspan = 1; + new->rowspan = 1; } /* @@ -48,14 +58,14 @@ static void new_container(Container **container) { * */ void expand_table_rows(Workspace *workspace) { - int c; + int c; - workspace->rows++; + workspace->rows++; - for (c = 0; c < workspace->cols; c++) { - workspace->table[c] = realloc(workspace->table[c], sizeof(Container*) * workspace->rows); - new_container(&(workspace->table[c][workspace->rows-1])); - } + for (c = 0; c < workspace->cols; c++) { + workspace->table[c] = realloc(workspace->table[c], sizeof(Container*) * workspace->rows); + new_container(&(workspace->table[c][workspace->rows-1])); + } } /* @@ -63,14 +73,14 @@ void expand_table_rows(Workspace *workspace) { * */ void expand_table_cols(Workspace *workspace) { - int c; + int c; - workspace->cols++; + workspace->cols++; - workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols); - workspace->table[workspace->cols-1] = calloc(sizeof(Container*) * workspace->rows, 1); - for (c = 0; c < workspace->rows; c++) - new_container(&(workspace->table[workspace->cols-1][c])); + workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols); + workspace->table[workspace->cols-1] = calloc(sizeof(Container*) * workspace->rows, 1); + for (c = 0; c < workspace->rows; c++) + new_container(&(workspace->table[workspace->cols-1][c])); } /* @@ -78,6 +88,6 @@ void expand_table_cols(Workspace *workspace) { * */ bool cell_exists(int col, int row) { - return (col >= 0 && col < c_ws->rows) && - (row >= 0 && row < c_ws->cols); + return (col >= 0 && col < c_ws->rows) && + (row >= 0 && row < c_ws->cols); } diff --git a/src/util.c b/src/util.c index 81ae50df..525fb434 100644 --- a/src/util.c +++ b/src/util.c @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #include #include #include @@ -17,23 +27,23 @@ * */ void start_application(const char *command) { - if (fork() == 0) { - /* Child process */ - if (fork() == 0) { - /* Stores the path of the shell */ - static const char *shell = NULL; + if (fork() == 0) { + /* Child process */ + if (fork() == 0) { + /* Stores the path of the shell */ + static const char *shell = NULL; - if (shell == NULL) - if ((shell = getenv("SHELL")) == NULL) - shell = "/bin/sh"; + if (shell == NULL) + if ((shell = getenv("SHELL")) == NULL) + shell = "/bin/sh"; - /* This is the child */ - execl(shell, shell, "-c", command, NULL); - /* not reached */ - } - exit(0); - } - wait(0); + /* This is the child */ + execl(shell, shell, "-c", command, NULL); + /* not reached */ + } + exit(0); + } + wait(0); } /* @@ -42,10 +52,10 @@ void start_application(const char *command) { * */ void check_error(xcb_connection_t *connection, xcb_void_cookie_t cookie, char *err_message) { - xcb_generic_error_t *error = xcb_request_check(connection, cookie); - if (error != NULL) { - fprintf(stderr, "ERROR: %s : %d\n", err_message , error->error_code); - xcb_disconnect(connection); - exit(-1); - } + xcb_generic_error_t *error = xcb_request_check(connection, cookie); + if (error != NULL) { + fprintf(stderr, "ERROR: %s : %d\n", err_message , error->error_code); + xcb_disconnect(connection); + exit(-1); + } } diff --git a/src/xcb.c b/src/xcb.c index b445437a..f4b9bc39 100644 --- a/src/xcb.c +++ b/src/xcb.c @@ -1,3 +1,13 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * (c) 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ #include #include #include @@ -15,28 +25,28 @@ * */ uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex) { - #define RGB_8_TO_16(i) (65535 * ((i) & 0xFF) / 255) + #define RGB_8_TO_16(i) (65535 * ((i) & 0xFF) / 255) char strgroups[3][3] = {{hex[1], hex[2], '\0'}, {hex[3], hex[4], '\0'}, {hex[5], hex[6], '\0'}}; - int rgb16[3] = {RGB_8_TO_16(strtol(strgroups[0], NULL, 16)), - RGB_8_TO_16(strtol(strgroups[1], NULL, 16)), - RGB_8_TO_16(strtol(strgroups[2], NULL, 16))}; + int rgb16[3] = {RGB_8_TO_16(strtol(strgroups[0], NULL, 16)), + RGB_8_TO_16(strtol(strgroups[1], NULL, 16)), + RGB_8_TO_16(strtol(strgroups[2], NULL, 16))}; - xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; + xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; - xcb_colormap_t colormapId = xcb_generate_id(conn); - xcb_create_colormap(conn, XCB_COLORMAP_ALLOC_NONE, colormapId, window, root_screen->root_visual); - xcb_alloc_color_reply_t *reply = xcb_alloc_color_reply(conn, - xcb_alloc_color(conn, colormapId, rgb16[0], rgb16[1], rgb16[2]), NULL); + xcb_colormap_t colormapId = xcb_generate_id(conn); + xcb_create_colormap(conn, XCB_COLORMAP_ALLOC_NONE, colormapId, window, root_screen->root_visual); + xcb_alloc_color_reply_t *reply = xcb_alloc_color_reply(conn, + xcb_alloc_color(conn, colormapId, rgb16[0], rgb16[1], rgb16[2]), NULL); - if (!reply) { - printf("color fail\n"); - exit(1); - } + if (!reply) { + printf("color fail\n"); + exit(1); + } - uint32_t pixel = reply->pixel; - free(reply); - xcb_free_colormap(conn, colormapId); - return pixel; + uint32_t pixel = reply->pixel; + free(reply); + xcb_free_colormap(conn, colormapId); + return pixel; } -- 2.39.5