]> git.sur5r.net Git - i3/i3/commitdiff
Cleanups, first strike. Move stuff to separate files, eliminate warnings
authorMichael Stapelberg <michael+git@stapelberg.de>
Fri, 13 Feb 2009 18:04:45 +0000 (19:04 +0100)
committerMichael Stapelberg <michael+git@stapelberg.de>
Fri, 13 Feb 2009 18:04:45 +0000 (19:04 +0100)
18 files changed:
Makefile
commands.c [new file with mode: 0644]
commands.h [new file with mode: 0644]
debug.c [new file with mode: 0644]
debug.h [new file with mode: 0644]
font.c
handlers.c [new file with mode: 0644]
handlers.h [new file with mode: 0644]
i3.h [new file with mode: 0644]
layout.c [new file with mode: 0644]
layout.h [new file with mode: 0644]
mainx.c
table.c
table.h
util.c [new file with mode: 0644]
util.h [new file with mode: 0644]
xcb.c [new file with mode: 0644]
xcb.h [new file with mode: 0644]

index b7b3fc4003e4d676be12e2cbb17d587548819be7..9e919dc82c51ce8294f1ec4521aec47dc4f15d96 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,9 +4,9 @@ CFLAGS += -Wall
 # Extended debugging flags, macros shall be available in gcc
 CFLAGS += -gdwarf-2
 CFLAGS += -g3
-CFLAGS += -I/usr/include/xcb
+#CFLAGS += -I/usr/include/xcb
 CFLAGS += -I/usr/local/include/
-CFLAGS += -I/usr/local/include/xcb
+#CFLAGS += -I/usr/local/include/xcb
 CFLAGS += -I/usr/pkg/include
 
 LDFLAGS += -lxcb-wm
diff --git a/commands.c b/commands.c
new file mode 100644 (file)
index 0000000..8e3161c
--- /dev/null
@@ -0,0 +1,348 @@
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <xcb/xcb.h>
+
+#include "util.h"
+#include "data.h"
+#include "table.h"
+#include "layout.h"
+#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;
+}
+
+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");
+       }
+}
+
+/*
+ * Tries to move the window inside its current container.
+ *
+ * Returns true if the window could be moved, false otherwise.
+ *
+ */
+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;
+}
+
+/*
+ * Moves the current window to the given direction, creating a column/row if
+ * necessary
+ *
+ */
+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);
+}
+
+/*
+ * "Snaps" the current container (not possible for windows, because it works at table base)
+ * to the given direction, that is, adjusts cellspan/rowspan
+ *
+ */
+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);
+}
+
+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);
+}
+
+/*
+ * Parses a command, see file CMDMODE for more information
+ *
+ */
+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 <exec>? */
+       if (strncmp(command, "exec ", strlen("exec ")) == 0) {
+               printf("starting \"%s\"\n", command + strlen("exec "));
+               start_application(command+strlen("exec "), NULL);
+               return;
+       }
+
+       /* Is it a <with>? */
+       if (command[0] == 'w') {
+               /* TODO: implement */
+               printf("not yet implemented.\n");
+               return;
+       }
+
+       /* It's a normal <cmd> */
+       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 <where> */
+       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/commands.h b/commands.h
new file mode 100644 (file)
index 0000000..148f56f
--- /dev/null
@@ -0,0 +1,8 @@
+#include <xcb/xcb.h>
+
+#ifndef _COMMANDS_H
+#define _COMMANDS_H
+
+void parse_command(xcb_connection_t *conn, const char *command);
+
+#endif
diff --git a/debug.c b/debug.c
new file mode 100644 (file)
index 0000000..cbdbd36
--- /dev/null
+++ b/debug.c
@@ -0,0 +1,235 @@
+#include <stdio.h>
+#include <xcb/xcb.h>
+
+/* Debug functions here, especially the FormatEvent-stuff, which prints unhandled events */
+
+static const char *labelError[] = {
+    "Success",
+    "BadRequest",
+    "BadValue",
+    "BadWindow",
+    "BadPixmap",
+    "BadAtom",
+    "BadCursor",
+    "BadFont",
+    "BadMatch",
+    "BadDrawable",
+    "BadAccess",
+    "BadAlloc",
+    "BadColor",
+    "BadGC",
+    "BadIDChoice",
+    "BadName",
+    "BadLength",
+    "BadImplementation",
+};
+
+static const char *labelRequest[] = {
+    "no request",
+    "CreateWindow",
+    "ChangeWindowAttributes",
+    "GetWindowAttributes",
+    "DestroyWindow",
+    "DestroySubwindows",
+    "ChangeSaveSet",
+    "ReparentWindow",
+    "MapWindow",
+    "MapSubwindows",
+    "UnmapWindow",
+    "UnmapSubwindows",
+    "ConfigureWindow",
+    "CirculateWindow",
+    "GetGeometry",
+    "QueryTree",
+    "InternAtom",
+    "GetAtomName",
+    "ChangeProperty",
+    "DeleteProperty",
+    "GetProperty",
+    "ListProperties",
+    "SetSelectionOwner",
+    "GetSelectionOwner",
+    "ConvertSelection",
+    "SendEvent",
+    "GrabPointer",
+    "UngrabPointer",
+    "GrabButton",
+    "UngrabButton",
+    "ChangeActivePointerGrab",
+    "GrabKeyboard",
+    "UngrabKeyboard",
+    "GrabKey",
+    "UngrabKey",
+    "AllowEvents",
+    "GrabServer",
+    "UngrabServer",
+    "QueryPointer",
+    "GetMotionEvents",
+    "TranslateCoords",
+    "WarpPointer",
+    "SetInputFocus",
+    "GetInputFocus",
+    "QueryKeymap",
+    "OpenFont",
+    "CloseFont",
+    "QueryFont",
+    "QueryTextExtents",
+    "ListFonts",
+    "ListFontsWithInfo",
+    "SetFontPath",
+    "GetFontPath",
+    "CreatePixmap",
+    "FreePixmap",
+    "CreateGC",
+    "ChangeGC",
+    "CopyGC",
+    "SetDashes",
+    "SetClipRectangles",
+    "FreeGC",
+    "ClearArea",
+    "CopyArea",
+    "CopyPlane",
+    "PolyPoint",
+    "PolyLine",
+    "PolySegment",
+    "PolyRectangle",
+    "PolyArc",
+    "FillPoly",
+    "PolyFillRectangle",
+    "PolyFillArc",
+    "PutImage",
+    "GetImage",
+    "PolyText",
+    "PolyText",
+    "ImageText",
+    "ImageText",
+    "CreateColormap",
+    "FreeColormap",
+    "CopyColormapAndFree",
+    "InstallColormap",
+    "UninstallColormap",
+    "ListInstalledColormaps",
+    "AllocColor",
+    "AllocNamedColor",
+    "AllocColorCells",
+    "AllocColorPlanes",
+    "FreeColors",
+    "StoreColors",
+    "StoreNamedColor",
+    "QueryColors",
+    "LookupColor",
+    "CreateCursor",
+    "CreateGlyphCursor",
+    "FreeCursor",
+    "RecolorCursor",
+    "QueryBestSize",
+    "QueryExtension",
+    "ListExtensions",
+    "ChangeKeyboardMapping",
+    "GetKeyboardMapping",
+    "ChangeKeyboardControl",
+    "GetKeyboardControl",
+    "Bell",
+    "ChangePointerControl",
+    "GetPointerControl",
+    "SetScreenSaver",
+    "GetScreenSaver",
+    "ChangeHosts",
+    "ListHosts",
+    "SetAccessControl",
+    "SetCloseDownMode",
+    "KillClient",
+    "RotateProperties",
+    "ForceScreenSaver",
+    "SetPointerMapping",
+    "GetPointerMapping",
+    "SetModifierMapping",
+    "GetModifierMapping",
+    "major 120",
+    "major 121",
+    "major 122",
+    "major 123",
+    "major 124",
+    "major 125",
+    "major 126",
+    "NoOperation",
+};
+
+static const char *labelEvent[] = {
+    "error",
+    "reply",
+    "KeyPress",
+    "KeyRelease",
+    "ButtonPress",
+    "ButtonRelease",
+    "MotionNotify",
+    "EnterNotify",
+    "LeaveNotify",
+    "FocusIn",
+    "FocusOut",
+    "KeymapNotify",
+    "Expose",
+    "GraphicsExpose",
+    "NoExpose",
+    "VisibilityNotify",
+    "CreateNotify",
+    "DestroyNotify",
+    "UnmapNotify",
+    "MapNotify",
+    "MapRequest",
+    "ReparentNotify",
+    "ConfigureNotify",
+    "ConfigureRequest",
+    "GravityNotify",
+    "ResizeRequest",
+    "CirculateNotify",
+    "CirculateRequest",
+    "PropertyNotify",
+    "SelectionClear",
+    "SelectionRequest",
+    "SelectionNotify",
+    "ColormapNotify",
+    "ClientMessage",
+    "MappingNotify",
+};
+
+static const char *labelSendEvent[] = {
+    "",
+    " (from SendEvent)",
+};
+
+int format_event(xcb_generic_event_t *e) {
+    uint8_t sendEvent;
+    uint16_t seqnum;
+
+    sendEvent = (e->response_type & 0x80) ? 1 : 0;
+    e->response_type &= ~0x80;
+    seqnum = *((uint16_t *) e + 1);
+
+    switch(e->response_type) {
+    case 0:
+        printf("Error %s on seqnum %d (%s).\n",
+            labelError[*((uint8_t *) e + 1)],
+            seqnum,
+            labelRequest[*((uint8_t *) e + 10)]);
+        break;
+    default:
+        printf("Event %s following seqnum %d%s.\n",
+            labelEvent[e->response_type],
+            seqnum,
+            labelSendEvent[sendEvent]);
+        break;
+    case XCB_KEYMAP_NOTIFY:
+        printf("Event %s%s.\n",
+            labelEvent[e->response_type],
+            labelSendEvent[sendEvent]);
+        break;
+    }
+
+    fflush(stdout);
+    return 1;
+}
+
+int handle_event(void *ignored, xcb_connection_t *c, xcb_generic_event_t *e) {
+        return format_event(e);
+}
diff --git a/debug.h b/debug.h
new file mode 100644 (file)
index 0000000..3d9cf3e
--- /dev/null
+++ b/debug.h
@@ -0,0 +1,6 @@
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+int handle_event(void *ignored, xcb_connection_t *c, xcb_generic_event_t *e);
+
+#endif
diff --git a/font.c b/font.c
index 407955a0be508c19d37ccae3d37932e8a0689318..803ac0a6a778c3a06a0446299cab8350f320c087 100644 (file)
--- a/font.c
+++ b/font.c
@@ -8,17 +8,7 @@
 #include <xcb/xcb.h>
 
 #include "data.h"
-
-/* TODO: This is just here to be somewhere. Move it somewhere else. */
-void check_error(xcb_connection_t *connection, xcb_void_cookie_t cookie, char *errMessage) {
-       xcb_generic_error_t *error = xcb_request_check (connection, cookie);
-       if (error != NULL) {
-               fprintf(stderr, "ERROR: %s : %d\n", errMessage , error->error_code);
-               xcb_disconnect(connection);
-               exit(-1);
-       }
-}
-
+#include "util.h"
 
 i3Font *load_font(xcb_connection_t *c, const char *pattern) {
        /* TODO: this function should be caching */
diff --git a/handlers.c b/handlers.c
new file mode 100644 (file)
index 0000000..5864036
--- /dev/null
@@ -0,0 +1,326 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <xcb/xcb.h>
+
+#include <xcb/xcb_wm.h>
+#include <X11/XKBlib.h>
+
+#include "i3.h"
+#include "debug.h"
+#include "table.h"
+#include "layout.h"
+#include "commands.h"
+#include "data.h"
+#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);
+}
+
+
+/*
+ * Due to bindings like Mode_switch + <a>, we need to bind some keys in XCB_GRAB_MODE_SYNC.
+ * Therefore, we just replay all key presses.
+ *
+ */
+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;
+}
+
+/*
+ * There was a key press. We lookup the key symbol and see if there are any bindings
+ * on that. This allows to do things like binding special characters (think of ä) to
+ * functions to get one more modifier while not losing AltGr :-)
+ * TODO: this description needs to be more understandable
+ *
+ */
+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;
+}
+
+
+/*
+ * When the user moves the mouse pointer onto a window, this callback gets called.
+ *
+ */
+int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_event_t *event) {
+       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);
+
+       /* 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);
+
+       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;
+}
+
+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;
+}
+
+/*
+ * Our window decorations were unmapped. That means, the window will be killed now,
+ * so we better clean up before.
+ *
+ */
+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;
+}
+
+/*
+ * Called when a window changes its title
+ *
+ */
+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;
+
+       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);
+
+       return 1;
+}
+
+/*
+ * Expose event means we should redraw our windows (= title bar)
+ *
+ */
+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;
+}
diff --git a/handlers.h b/handlers.h
new file mode 100644 (file)
index 0000000..7c82ca4
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _HANDLERS_H
+#define _HANDLERS_H
+
+int handle_key_release(void *ignored, xcb_connection_t *conn, xcb_key_release_event_t *event);
+int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_t *event);
+int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_event_t *event);
+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);
+int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t *event);
+
+
+
+
+
+#endif
diff --git a/i3.h b/i3.h
new file mode 100644 (file)
index 0000000..d2453f4
--- /dev/null
+++ b/i3.h
@@ -0,0 +1,18 @@
+#include <xcb/xcb.h>
+#include <xcb/xcb_event.h>
+
+#include <X11/XKBlib.h>
+
+#include "queue.h"
+
+#ifndef _I3_H
+#define _I3_H
+
+extern Display *xkbdpy;
+extern TAILQ_HEAD(bindings_head, Binding) bindings;
+extern xcb_event_handlers_t evenths;
+extern char *pattern;
+extern char **environment;
+extern int num_screens;
+
+#endif
diff --git a/layout.c b/layout.c
new file mode 100644 (file)
index 0000000..4a09e41
--- /dev/null
+++ b/layout.c
@@ -0,0 +1,181 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <xcb/xcb.h>
+
+#include "font.h"
+#include "i3.h"
+#include "xcb.h"
+#include "table.h"
+#include "util.h"
+
+/* All functions handling layout/drawing of window decorations */
+
+/*
+ * (Re-)draws window decorations for a given Client
+ *
+ */
+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, ...) ? */
+#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); \
+       }
+
+       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;
+
+       values[0] = text_color;
+       values[1] = background_color;
+       values[2] = font->id;
+
+       xcb_change_gc(conn, client->titlegc, mask, values);
+
+       /* 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);
+}
+
+void render_container(xcb_connection_t *connection, Container *container) {
+       Client *client;
+       uint32_t values[4];
+       uint32_t mask = XCB_CONFIG_WINDOW_X |
+                       XCB_CONFIG_WINDOW_Y |
+                       XCB_CONFIG_WINDOW_WIDTH |
+                       XCB_CONFIG_WINDOW_HEIGHT;
+       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: rewrite this block so that the need to puke vanishes :) */
+                       /* TODO: at the moment, every column/row is 200px. This
+                        * needs to be changed to "percentage of the screen" by
+                        * default and adjustable by the user if necessary.
+                        */
+                       values[0] = container->x + (container->col * container->width); /* x */
+                       values[1] = container->y + (container->row * container->height +
+                               (container->height / num_clients) * current_client); /* y */
+
+                       if (client->x != values[0] || client->y != values[1]) {
+                               printf("frame needs to be pushed to %dx%d\n",
+                                               values[0], values[1]);
+                               client->x = values[0];
+                               client->y = values[1];
+                               xcb_configure_window(connection, client->frame,
+                                               XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
+                       }
+                       /* TODO: vertical default layout */
+                       values[0] = container->width; /* width */
+                       values[1] = container->height / num_clients; /* height */
+
+                       if (client->width != values[0] || client->height != values[1]) {
+                               client->width = values[0];
+                               client->height = values[1];
+                               xcb_configure_window(connection, client->frame,
+                                               XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
+                       }
+
+                       /* TODO: hmm, only do this for new wins */
+                       /* The coordinates of the child are relative to its frame, we
+                        * add a border of 2 pixel to each value */
+                       values[0] = 2;
+                       values[1] = font->height + 2 + 2;
+                       values[2] = client->width - (values[0] + 2);
+                       values[3] = client->height - (values[1] + 2);
+                       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);
+
+                       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);
+}
diff --git a/layout.h b/layout.h
new file mode 100644 (file)
index 0000000..aecb2b4
--- /dev/null
+++ b/layout.h
@@ -0,0 +1,9 @@
+#include <xcb/xcb.h>
+
+#ifndef _LAYOUT_H
+#define _LAYOUT_H
+
+void decorate_window(xcb_connection_t *conn, Client *client);
+void render_layout(xcb_connection_t *conn);
+
+#endif
diff --git a/mainx.c b/mainx.c
index 421aab5d342f78567a2629868e636c9fad93844c..359e3f7430099834846e93ef82b0ab931ac49e71 100644 (file)
--- a/mainx.c
+++ b/mainx.c
 #include <X11/XKBlib.h>
 #include <X11/extensions/XKB.h>
 
-#include "xcb_wm.h"
-#include "xcb_aux.h"
-#include "xcb_event.h"
-#include "xcb_property.h"
-#include "xcb_keysyms.h"
-#include "xcb_icccm.h"
-#include "xinerama.h"
+#include <xcb/xcb_wm.h>
+#include <xcb/xcb_aux.h>
+#include <xcb/xcb_event.h>
+#include <xcb/xcb_property.h>
+#include <xcb/xcb_keysyms.h>
+#include <xcb/xcb_icccm.h>
+#include <xcb/xinerama.h>
 #include "data.h"
 
 #include "queue.h"
 #include "table.h"
 #include "font.h"
+#include "layout.h"
+#include "debug.h"
+#include "handlers.h"
+#include "util.h"
 
 #define TERMINAL "/usr/pkg/bin/urxvt"
 
@@ -40,7 +44,7 @@ static const int RIGHT = 5;
 
 /* This is the filtered environment which will be passed to opened applications.
  * It contains DISPLAY (naturally) and locales stuff (LC_*, LANG) */
-static char **environment;
+char **environment;
 
 /* hm, xcb_wm wants us to implement this. */
 table_t *byChild = 0;
@@ -50,209 +54,6 @@ xcb_window_t root_win;
 char *pattern = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso8859-1";
 int num_screens = 0;
 
-
-int current_col = 0;
-int current_row = 0;
-
-
-int globalc = 0;
-
-
-static const char *labelError[] = {
-    "Success",
-    "BadRequest",
-    "BadValue",
-    "BadWindow",
-    "BadPixmap",
-    "BadAtom",
-    "BadCursor",
-    "BadFont",
-    "BadMatch",
-    "BadDrawable",
-    "BadAccess",
-    "BadAlloc",
-    "BadColor",
-    "BadGC",
-    "BadIDChoice",
-    "BadName",
-    "BadLength",
-    "BadImplementation",
-};
-
-static const char *labelRequest[] = {
-    "no request",
-    "CreateWindow",
-    "ChangeWindowAttributes",
-    "GetWindowAttributes",
-    "DestroyWindow",
-    "DestroySubwindows",
-    "ChangeSaveSet",
-    "ReparentWindow",
-    "MapWindow",
-    "MapSubwindows",
-    "UnmapWindow",
-    "UnmapSubwindows",
-    "ConfigureWindow",
-    "CirculateWindow",
-    "GetGeometry",
-    "QueryTree",
-    "InternAtom",
-    "GetAtomName",
-    "ChangeProperty",
-    "DeleteProperty",
-    "GetProperty",
-    "ListProperties",
-    "SetSelectionOwner",
-    "GetSelectionOwner",
-    "ConvertSelection",
-    "SendEvent",
-    "GrabPointer",
-    "UngrabPointer",
-    "GrabButton",
-    "UngrabButton",
-    "ChangeActivePointerGrab",
-    "GrabKeyboard",
-    "UngrabKeyboard",
-    "GrabKey",
-    "UngrabKey",
-    "AllowEvents",
-    "GrabServer",
-    "UngrabServer",
-    "QueryPointer",
-    "GetMotionEvents",
-    "TranslateCoords",
-    "WarpPointer",
-    "SetInputFocus",
-    "GetInputFocus",
-    "QueryKeymap",
-    "OpenFont",
-    "CloseFont",
-    "QueryFont",
-    "QueryTextExtents",
-    "ListFonts",
-    "ListFontsWithInfo",
-    "SetFontPath",
-    "GetFontPath",
-    "CreatePixmap",
-    "FreePixmap",
-    "CreateGC",
-    "ChangeGC",
-    "CopyGC",
-    "SetDashes",
-    "SetClipRectangles",
-    "FreeGC",
-    "ClearArea",
-    "CopyArea",
-    "CopyPlane",
-    "PolyPoint",
-    "PolyLine",
-    "PolySegment",
-    "PolyRectangle",
-    "PolyArc",
-    "FillPoly",
-    "PolyFillRectangle",
-    "PolyFillArc",
-    "PutImage",
-    "GetImage",
-    "PolyText",
-    "PolyText",
-    "ImageText",
-    "ImageText",
-    "CreateColormap",
-    "FreeColormap",
-    "CopyColormapAndFree",
-    "InstallColormap",
-    "UninstallColormap",
-    "ListInstalledColormaps",
-    "AllocColor",
-    "AllocNamedColor",
-    "AllocColorCells",
-    "AllocColorPlanes",
-    "FreeColors",
-    "StoreColors",
-    "StoreNamedColor",
-    "QueryColors",
-    "LookupColor",
-    "CreateCursor",
-    "CreateGlyphCursor",
-    "FreeCursor",
-    "RecolorCursor",
-    "QueryBestSize",
-    "QueryExtension",
-    "ListExtensions",
-    "ChangeKeyboardMapping",
-    "GetKeyboardMapping",
-    "ChangeKeyboardControl",
-    "GetKeyboardControl",
-    "Bell",
-    "ChangePointerControl",
-    "GetPointerControl",
-    "SetScreenSaver",
-    "GetScreenSaver",
-    "ChangeHosts",
-    "ListHosts",
-    "SetAccessControl",
-    "SetCloseDownMode",
-    "KillClient",
-    "RotateProperties",
-    "ForceScreenSaver",
-    "SetPointerMapping",
-    "GetPointerMapping",
-    "SetModifierMapping",
-    "GetModifierMapping",
-    "major 120",
-    "major 121",
-    "major 122",
-    "major 123",
-    "major 124",
-    "major 125",
-    "major 126",
-    "NoOperation",
-};
-
-static const char *labelEvent[] = {
-    "error",
-    "reply",
-    "KeyPress",
-    "KeyRelease",
-    "ButtonPress",
-    "ButtonRelease",
-    "MotionNotify",
-    "EnterNotify",
-    "LeaveNotify",
-    "FocusIn",
-    "FocusOut",
-    "KeymapNotify",
-    "Expose",
-    "GraphicsExpose",
-    "NoExpose",
-    "VisibilityNotify",
-    "CreateNotify",
-    "DestroyNotify",
-    "UnmapNotify",
-    "MapNotify",
-    "MapRequest",
-    "ReparentNotify",
-    "ConfigureNotify",
-    "ConfigureRequest",
-    "GravityNotify",
-    "ResizeRequest",
-    "CirculateNotify",
-    "CirculateRequest",
-    "PropertyNotify",
-    "SelectionClear",
-    "SelectionRequest",
-    "SelectionNotify",
-    "ColormapNotify",
-    "ClientMessage",
-    "MappingNotify",
-};
-
-static const char *labelSendEvent[] = {
-    "",
-    " (from SendEvent)",
-};
-
 /*
  *
  * TODO: what exactly does this, what happens if we leave stuff out?
@@ -308,211 +109,6 @@ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *c, xcb_win
        free(geom);
 }
 
-
-/*
- * Returns the colorpixel to use for the given hex color (think of HTML).
- *
- * The hex_color has to start with #, for example #FF00FF.
- *
- * NOTE that get_colorpixel() does _NOT_ check the given color code for validity.
- * This has to be done by the caller.
- *
- */
-uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex) {
-       #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))};
-
-       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);
-
-       if (!reply) {
-               printf("color fail\n");
-               exit(1);
-       }
-
-       uint32_t pixel = reply->pixel;
-       free(reply);
-       xcb_free_colormap(conn, colormapId);
-       return pixel;
-}
-
-/*
- * (Re-)draws window decorations for a given Client
- *
- */
-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, ...) ? */
-#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); \
-       }
-
-       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;
-
-       values[0] = text_color;
-       values[1] = background_color;
-       values[2] = font->id;
-
-       xcb_change_gc(conn, client->titlegc, mask, values);
-
-       /* 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);
-       free(label);
-}
-
-void render_container(xcb_connection_t *connection, Container *container) {
-       Client *client;
-       uint32_t values[4];
-       uint32_t mask = XCB_CONFIG_WINDOW_X |
-                       XCB_CONFIG_WINDOW_Y |
-                       XCB_CONFIG_WINDOW_WIDTH |
-                       XCB_CONFIG_WINDOW_HEIGHT;
-       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: rewrite this block so that the need to puke vanishes :) */
-                       /* TODO: at the moment, every column/row is 200px. This
-                        * needs to be changed to "percentage of the screen" by
-                        * default and adjustable by the user if necessary.
-                        */
-                       values[0] = container->x + (container->col * container->width); /* x */
-                       values[1] = container->y + (container->row * container->height +
-                               (container->height / num_clients) * current_client); /* y */
-
-                       if (client->x != values[0] || client->y != values[1]) {
-                               printf("frame needs to be pushed to %dx%d\n",
-                                               values[0], values[1]);
-                               client->x = values[0];
-                               client->y = values[1];
-                               xcb_configure_window(connection, client->frame,
-                                               XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
-                       }
-                       /* TODO: vertical default layout */
-                       values[0] = container->width; /* width */
-                       values[1] = container->height / num_clients; /* height */
-
-                       if (client->width != values[0] || client->height != values[1]) {
-                               client->width = values[0];
-                               client->height = values[1];
-                               xcb_configure_window(connection, client->frame,
-                                               XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
-                       }
-
-                       /* TODO: hmm, only do this for new wins */
-                       /* The coordinates of the child are relative to its frame, we
-                        * add a border of 2 pixel to each value */
-                       values[0] = 2;
-                       values[1] = font->height + 2 + 2;
-                       values[2] = client->width - (values[0] + 2);
-                       values[3] = client->height - (values[1] + 2);
-                       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);
-
-                       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);
-}
-
 /*
  * Let’s own this window…
  *
@@ -609,701 +205,6 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
        render_layout(conn);
 }
 
-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;
-}
-
-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");
-       }
-}
-
-/*
- * Tries to move the window inside its current container.
- *
- * Returns true if the window could be moved, false otherwise.
- *
- */
-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;
-}
-
-/*
- * Moves the current window to the given direction, creating a column/row if
- * necessary
- *
- */
-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);
-}
-
-/*
- * "Snaps" the current container (not possible for windows, because it works at table base)
- * to the given direction, that is, adjusts cellspan/rowspan
- *
- */
-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);
-}
-
-int format_event(xcb_generic_event_t *e)
-{           
-    uint8_t sendEvent;
-    uint16_t seqnum;
-
-    sendEvent = (e->response_type & 0x80) ? 1 : 0;
-    e->response_type &= ~0x80;
-    seqnum = *((uint16_t *) e + 1);
-
-    switch(e->response_type) 
-    {   
-    case 0:
-        printf("Error %s on seqnum %d (%s).\n",
-            labelError[*((uint8_t *) e + 1)],
-            seqnum,
-            labelRequest[*((uint8_t *) e + 10)]);
-        break;
-    default:
-        printf("Event %s following seqnum %d%s.\n",
-            labelEvent[e->response_type],
-            seqnum,
-            labelSendEvent[sendEvent]);
-        break;  
-    case XCB_KEYMAP_NOTIFY:
-        printf("Event %s%s.\n",
-            labelEvent[e->response_type],
-            labelSendEvent[sendEvent]);
-        break;
-    }
-
-    fflush(stdout);
-    return 1;
-}
-
-
-static int handleEvent(void *ignored, xcb_connection_t *c, xcb_generic_event_t *e)
-{
-        return format_event(e);
-}
-
-/*
- * Starts the given application with the given args.
- *
- */
-static void start_application(const char *path, const char *args) {
-       pid_t pid;
-       if ((pid = vfork()) == 0) {
-               /* This is the child */
-               char *argv[2];
-               /* TODO: For now, we ignore args. Later on, they should be parsed
-                  correctly (like in the shell?) */
-               argv[0] = strdup(path);
-               argv[1] = NULL;
-               execve(path, argv, environment);
-               /* not reached */
-       }
-}
-
-/*
- * Due to bindings like Mode_switch + <a>, we need to bind some keys in XCB_GRAB_MODE_SYNC.
- * Therefore, we just replay all key presses.
- *
- */
-static 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, ReplayKeyboard, event->time);
-       xcb_flush(conn);
-       return 1;
-}
-
-static void show_workspace(xcb_connection_t *conn, int workspace) {
-       int cols, rows;
-       Client *client;
-       printf("show_workspace(%d)\n", workspace);
-
-       /* 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_win, XCB_CURRENT_TIME);
-
-       //xcb_ungrab_server(conn);
-
-       render_layout(conn);
-}
-
-/*
- * Parses a command, see file CMDMODE for more information
- *
- */
-static 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 <exec>? */
-       if (strncmp(command, "exec ", strlen("exec ")) == 0) {
-               printf("starting \"%s\"\n", command + strlen("exec "));
-               start_application(command+strlen("exec "), NULL);
-               return;
-       }
-
-       /* Is it a <with>? */
-       if (command[0] == 'w') {
-               /* TODO: implement */
-               printf("not yet implemented.\n");
-               return;
-       }
-
-       /* It's a normal <cmd> */
-       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 <where> */
-       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");
-}
-
-/*
- * There was a key press. We lookup the key symbol and see if there are any bindings
- * on that. This allows to do things like binding special characters (think of ä) to
- * functions to get one more modifier while not losing AltGr :-)
- * TODO: this description needs to be more understandable
- *
- */
-static 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;
-}
-
-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);
-}
-
-/*
- * When the user moves the mouse pointer onto a window, this callback gets called.
- *
- */
-static int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_event_t *event) {
-       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);
-
-       /* 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);
-
-       return 1;
-}
-
-static 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) {
-                       handleEvent(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 *c, xcb_map_notify_event_t *e)
-{
-       window_attributes_t wa = { TAG_VALUE };
-       wa.u.override_redirect = e->override_redirect;
-       printf("MapNotify for 0x%08x.\n", e->window);
-       manage_window(prophs, c, e->window, wa);
-       return 1;
-}
-
-/*
- * Our window decorations were unmapped. That means, the window will be killed now,
- * so we better clean up before.
- *
- */
-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;
-}
-
-/*
- * Called when a window changes its title
- *
- */
-static 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;
-
-       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);
-
-       return 1;
-}
-
-
-static int handleExposeEvent(void *data, xcb_connection_t *c, xcb_expose_event_t *e) {
-printf("exposeevent\n");
-       Client *client = table_get(byParent, e->window);
-       if(!client || e->count != 0)
-               return 1;
-       decorate_window(c, client);
-       return 1;
-}
 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;
@@ -1429,14 +330,14 @@ int main(int argc, char *argv[], char *env[]) {
 
        xcb_event_handlers_init(c, &evenths);
        for(i = 2; i < 128; ++i)
-               xcb_event_set_handler(&evenths, i, handleEvent, 0);
+               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) handleEvent, 0);
+               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, handleExposeEvent, 0);
+       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);
diff --git a/table.c b/table.c
index 9c53237d144fdeda8459d82ced888ccd7fdfe63c..33d1b4fe15d49fc27cb1c715ccc0f5889ccf8b52 100644 (file)
--- a/table.c
+++ b/table.c
@@ -18,6 +18,8 @@ int current_workspace = 0;
 Workspace workspaces[10];
 /* Convenience pointer to the current workspace */
 Workspace *c_ws = &workspaces[0];
+int current_col = 0;
+int current_row = 0;
 
 /*
  * Initialize table
@@ -25,7 +27,6 @@ Workspace *c_ws = &workspaces[0];
  */
 void init_table() {
        int i;
-       printf("sizof(workspaces) = %d\n", sizeof(workspaces));
        memset(workspaces, 0, sizeof(workspaces));
 
        for (i = 0; i < 10; i++) {
diff --git a/table.h b/table.h
index fff8be51a50d62c067500092e15844854f968f8a..1d6ca8f76dd7541a8ef4384ab31ddca2ba60cbcf 100644 (file)
--- a/table.h
+++ b/table.h
@@ -9,6 +9,8 @@
 
 extern Workspace *c_ws;
 extern Workspace workspaces[10];
+extern int current_col;
+extern int current_row;
 
 void init_table();
 void expand_table_rows(Workspace *workspace);
diff --git a/util.c b/util.c
new file mode 100644 (file)
index 0000000..1263cdc
--- /dev/null
+++ b/util.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "i3.h"
+
+/*
+ * Starts the given application with the given args.
+ *
+ */
+void start_application(const char *path, const char *args) {
+       pid_t pid;
+       if ((pid = vfork()) == 0) {
+               /* This is the child */
+               char *argv[2];
+               /* TODO: For now, we ignore args. Later on, they should be parsed
+                  correctly (like in the shell?) */
+               argv[0] = strdup(path);
+               argv[1] = NULL;
+               execve(path, argv, environment);
+               /* not reached */
+       }
+}
+
+/*
+ * Checks a generic cookie for errors and quits with the given message if there
+ * was an error.
+ *
+ */
+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);
+       }
+}
diff --git a/util.h b/util.h
new file mode 100644 (file)
index 0000000..9eb2a44
--- /dev/null
+++ b/util.h
@@ -0,0 +1,7 @@
+#ifndef _UTIL_H
+#define _UTIL_H
+
+void start_application(const char *path, const char *args);
+void check_error(xcb_connection_t *connection, xcb_void_cookie_t cookie, char *err_message);
+
+#endif
diff --git a/xcb.c b/xcb.c
new file mode 100644 (file)
index 0000000..b445437
--- /dev/null
+++ b/xcb.c
@@ -0,0 +1,42 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <xcb/xcb.h>
+/* All the helper functions needed for efficiently using XCB */
+
+/*
+ * Returns the colorpixel to use for the given hex color (think of HTML).
+ *
+ * The hex_color has to start with #, for example #FF00FF.
+ *
+ * NOTE that get_colorpixel() does _NOT_ check the given color code for validity.
+ * This has to be done by the caller.
+ *
+ */
+uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex) {
+       #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))};
+
+       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);
+
+       if (!reply) {
+               printf("color fail\n");
+               exit(1);
+       }
+
+       uint32_t pixel = reply->pixel;
+       free(reply);
+       xcb_free_colormap(conn, colormapId);
+       return pixel;
+}
diff --git a/xcb.h b/xcb.h
new file mode 100644 (file)
index 0000000..c8224ef
--- /dev/null
+++ b/xcb.h
@@ -0,0 +1,6 @@
+#ifndef _XCB_H
+#define _XCB_H
+
+uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex);
+
+#endif