]> git.sur5r.net Git - i3/i3/commitdiff
Move stuff to include/ and src/
authorMichael Stapelberg <michael+git@stapelberg.de>
Fri, 13 Feb 2009 18:09:25 +0000 (19:09 +0100)
committerMichael Stapelberg <michael+git@stapelberg.de>
Fri, 13 Feb 2009 18:09:25 +0000 (19:09 +0100)
41 files changed:
Makefile
commands.c [deleted file]
commands.h [deleted file]
data.h [deleted file]
debug.c [deleted file]
debug.h [deleted file]
font.c [deleted file]
font.h [deleted file]
handlers.c [deleted file]
handlers.h [deleted file]
i3.h [deleted file]
include/commands.h [new file with mode: 0644]
include/data.h [new file with mode: 0644]
include/debug.h [new file with mode: 0644]
include/font.h [new file with mode: 0644]
include/handlers.h [new file with mode: 0644]
include/i3.h [new file with mode: 0644]
include/layout.h [new file with mode: 0644]
include/queue.h [new file with mode: 0644]
include/table.h [new file with mode: 0644]
include/util.h [new file with mode: 0644]
include/xcb.h [new file with mode: 0644]
layout.c [deleted file]
layout.h [deleted file]
mainx.c [deleted file]
queue.h [deleted file]
src/commands.c [new file with mode: 0644]
src/debug.c [new file with mode: 0644]
src/font.c [new file with mode: 0644]
src/handlers.c [new file with mode: 0644]
src/layout.c [new file with mode: 0644]
src/mainx.c [new file with mode: 0644]
src/table.c [new file with mode: 0644]
src/util.c [new file with mode: 0644]
src/xcb.c [new file with mode: 0644]
table.c [deleted file]
table.h [deleted file]
util.c [deleted file]
util.h [deleted file]
xcb.c [deleted file]
xcb.h [deleted file]

index 9e919dc82c51ce8294f1ec4521aec47dc4f15d96..3fd244fb75e792e092e2eb9002afe60a1ad8f874 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,9 +4,8 @@ CFLAGS += -Wall
 # Extended debugging flags, macros shall be available in gcc
 CFLAGS += -gdwarf-2
 CFLAGS += -g3
-#CFLAGS += -I/usr/include/xcb
+CFLAGS += -Iinclude
 CFLAGS += -I/usr/local/include/
-#CFLAGS += -I/usr/local/include/xcb
 CFLAGS += -I/usr/pkg/include
 
 LDFLAGS += -lxcb-wm
@@ -18,13 +17,16 @@ ifeq ($(UNAME),NetBSD)
 LDFLAGS += -Wl,-rpath,/usr/local/lib -Wl,-rpath,/usr/pkg/lib
 endif
 
-FILES=$(patsubst %.c,%.o,$(wildcard *.c))
+FILES=$(patsubst %.c,%.o,$(wildcard src/*.c))
 
-%.o: %.c %.h data.h
+src/%.o: src/%.c include/%.h include/data.h
        $(CC) $(CFLAGS) -c -o $@ $<
 
 all: ${FILES}
-       $(CC) -o mainx ${FILES} $(LDFLAGS)
+       $(CC) -o i3 ${FILES} $(LDFLAGS)
 
 clean:
-       rm -f *.o
+       rm -f src/*.o
+
+distclean: clean
+       rm -f i3
diff --git a/commands.c b/commands.c
deleted file mode 100644 (file)
index 8e3161c..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-#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
deleted file mode 100644 (file)
index 148f56f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <xcb/xcb.h>
-
-#ifndef _COMMANDS_H
-#define _COMMANDS_H
-
-void parse_command(xcb_connection_t *conn, const char *command);
-
-#endif
diff --git a/data.h b/data.h
deleted file mode 100644 (file)
index 203e790..0000000
--- a/data.h
+++ /dev/null
@@ -1,145 +0,0 @@
-#include <xcb/xcb.h>
-
-#ifndef _DATA_H
-#define _DATA_H
-/*
- * This file defines all data structures used by i3
- *
- */
-#include "queue.h"
-
-/* Forward definitions */
-typedef struct Cell Cell;
-typedef struct Font i3Font;
-typedef struct Container Container;
-typedef struct Client Client;
-typedef struct Binding Binding;
-typedef struct Workspace Workspace;
-
-/* Helper types */
-typedef enum { D_LEFT, D_RIGHT, D_UP, D_DOWN } direction_t;
-
-enum {
-       BIND_NONE = 0,
-       BIND_MOD_1 = XCB_MOD_MASK_1,
-       BIND_MOD_2 = XCB_MOD_MASK_2,
-       BIND_MOD_3 = XCB_MOD_MASK_3,
-       BIND_MOD_4 = XCB_MOD_MASK_4,
-       BIND_MOD_5 = XCB_MOD_MASK_5,
-       BIND_SHIFT = XCB_MOD_MASK_SHIFT,
-       BIND_CONTROL = XCB_MOD_MASK_CONTROL,
-       BIND_MODE_SWITCH = (1 << 8)
-};
-
-struct Workspace {
-       int x;
-       int y;
-       int width;
-       int height;
-       int screen_num;
-       int num;
-
-       /* table dimensions */
-       int cols;
-       int rows;
-
-       /* These are stored here just while this workspace is _not_ shown (see show_workspace()) */
-       int current_row;
-       int current_col;
-
-       /* This is a two-dimensional dynamic array of Container-pointers. I’ve always wanted
-        * to be a three-star programmer :) */
-       Container ***table;
-};
-
-/*
- * Defines a position in the table
- *
- */
-struct Cell {
-       int row;
-       int column;
-};
-
-struct Binding {
-       /* Keycode to bind */
-       uint32_t keycode;
-       /* Bitmask consisting of BIND_MOD_1, BIND_MODE_SWITCH, … */
-       uint32_t mods;
-       /* Command, like in command mode */
-       char *command;
-
-       TAILQ_ENTRY(Binding) bindings;
-};
-
-/*
- * We need to save the height of a font because it is required for each drawing of
- * text but relatively hard to get. As soon as a new font needs to be loaded, a
- * Font-entry will be filled for later use.
- *
- */
-struct Font {
-       /* The name of the font, that is what the pattern resolves to */
-       char *name;
-       /* A copy of the pattern to build a cache */
-       char *pattern;
-       /* The height of the font, built from font_ascent + font_descent */
-       int height;
-       /* The xcb-id for the font */
-       xcb_font_t id;
-};
-
-/*
- * A client is X11-speak for a window.
- *
- */
-struct Client {
-       /* TODO: this is NOT final */
-       Cell old_position; /* if you set a client to floating and set it back to managed,
-                             it does remember its old position and *tries* to get back there */
-
-       /* Backpointer. A client is inside a container */
-       Container *container;
-
-       int x, y;
-       int width, height;
-
-       /* Name */
-       char *name;
-       int name_len;
-
-       /* XCB contexts */
-       xcb_window_t frame; /* Our window: The frame around the client */
-       xcb_gcontext_t titlegc; /* The titlebar’s graphic context inside the frame */
-       xcb_window_t child; /* The client’s window */
-
-       /* The following entry provides the necessary list pointers to use Client with LIST_* macros */
-       CIRCLEQ_ENTRY(Client) clients;
-};
-
-/*
- * A container is either in default or stacking mode. It sits inside the table.
- *
- */
-struct Container {
-       /* Those are speaking for themselves: */
-       Client *currently_focused;
-       int colspan;
-       int rowspan;
-
-       /* Position of the container inside our table */
-       int row;
-       int col;
-       /* Xinerama: X/Y of the container */
-       int x;
-       int y;
-       /* Width/Height of the container. Changeable by the user */
-       int width;
-       int height;
-
-       /* Ensure MODE_DEFAULT maps to 0 because we use calloc for initialization later */
-       enum { MODE_DEFAULT = 0, MODE_STACK = 1 } mode;
-       CIRCLEQ_HEAD(client_head, Client) clients;
-};
-
-#endif
diff --git a/debug.c b/debug.c
deleted file mode 100644 (file)
index cbdbd36..0000000
--- a/debug.c
+++ /dev/null
@@ -1,235 +0,0 @@
-#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
deleted file mode 100644 (file)
index 3d9cf3e..0000000
--- a/debug.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#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
deleted file mode 100644 (file)
index 803ac0a..0000000
--- a/font.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Handles font loading
- *
- */
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <xcb/xcb.h>
-
-#include "data.h"
-#include "util.h"
-
-i3Font *load_font(xcb_connection_t *c, const char *pattern) {
-       /* TODO: this function should be caching */
-       i3Font *new = malloc(sizeof(i3Font));
-
-       xcb_list_fonts_with_info_cookie_t cookie = xcb_list_fonts_with_info(c, 1, strlen(pattern), pattern);
-       xcb_list_fonts_with_info_reply_t *reply = xcb_list_fonts_with_info_reply(c, cookie, NULL);
-       if (!reply) {
-               printf("Could not load font\n");
-               exit(1);
-       }
-
-       /* Oh my, this is so ugly :-(. Why can’t they just return a null-terminated
-        * string? That’s what abstraction layers are for. */
-       char buffer[xcb_list_fonts_with_info_name_length(reply)+1];
-       memset(buffer, 0, sizeof(buffer));
-       memcpy(buffer, xcb_list_fonts_with_info_name(reply), sizeof(buffer)-1);
-       new->name = strdup(buffer);
-       new->pattern = strdup(pattern);
-       new->height = reply->font_ascent + reply->font_descent;
-
-       /* Actually load the font */
-       new->id = xcb_generate_id(c);
-       xcb_void_cookie_t font_cookie = xcb_open_font_checked(c, new->id, strlen(pattern), pattern);
-       check_error(c, font_cookie, "Could not open font");
-
-       return new;
-}
diff --git a/font.h b/font.h
deleted file mode 100644 (file)
index 732c369..0000000
--- a/font.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <xcb/xcb.h>
-
-#include "data.h"
-
-#ifndef _FONT_H
-#define _FONT_H
-
-i3Font *load_font(xcb_connection_t *c, const char *pattern);
-
-#endif
diff --git a/handlers.c b/handlers.c
deleted file mode 100644 (file)
index 5864036..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-#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
deleted file mode 100644 (file)
index 7c82ca4..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#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
deleted file mode 100644 (file)
index d2453f4..0000000
--- a/i3.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#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/include/commands.h b/include/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/include/data.h b/include/data.h
new file mode 100644 (file)
index 0000000..203e790
--- /dev/null
@@ -0,0 +1,145 @@
+#include <xcb/xcb.h>
+
+#ifndef _DATA_H
+#define _DATA_H
+/*
+ * This file defines all data structures used by i3
+ *
+ */
+#include "queue.h"
+
+/* Forward definitions */
+typedef struct Cell Cell;
+typedef struct Font i3Font;
+typedef struct Container Container;
+typedef struct Client Client;
+typedef struct Binding Binding;
+typedef struct Workspace Workspace;
+
+/* Helper types */
+typedef enum { D_LEFT, D_RIGHT, D_UP, D_DOWN } direction_t;
+
+enum {
+       BIND_NONE = 0,
+       BIND_MOD_1 = XCB_MOD_MASK_1,
+       BIND_MOD_2 = XCB_MOD_MASK_2,
+       BIND_MOD_3 = XCB_MOD_MASK_3,
+       BIND_MOD_4 = XCB_MOD_MASK_4,
+       BIND_MOD_5 = XCB_MOD_MASK_5,
+       BIND_SHIFT = XCB_MOD_MASK_SHIFT,
+       BIND_CONTROL = XCB_MOD_MASK_CONTROL,
+       BIND_MODE_SWITCH = (1 << 8)
+};
+
+struct Workspace {
+       int x;
+       int y;
+       int width;
+       int height;
+       int screen_num;
+       int num;
+
+       /* table dimensions */
+       int cols;
+       int rows;
+
+       /* These are stored here just while this workspace is _not_ shown (see show_workspace()) */
+       int current_row;
+       int current_col;
+
+       /* This is a two-dimensional dynamic array of Container-pointers. I’ve always wanted
+        * to be a three-star programmer :) */
+       Container ***table;
+};
+
+/*
+ * Defines a position in the table
+ *
+ */
+struct Cell {
+       int row;
+       int column;
+};
+
+struct Binding {
+       /* Keycode to bind */
+       uint32_t keycode;
+       /* Bitmask consisting of BIND_MOD_1, BIND_MODE_SWITCH, … */
+       uint32_t mods;
+       /* Command, like in command mode */
+       char *command;
+
+       TAILQ_ENTRY(Binding) bindings;
+};
+
+/*
+ * We need to save the height of a font because it is required for each drawing of
+ * text but relatively hard to get. As soon as a new font needs to be loaded, a
+ * Font-entry will be filled for later use.
+ *
+ */
+struct Font {
+       /* The name of the font, that is what the pattern resolves to */
+       char *name;
+       /* A copy of the pattern to build a cache */
+       char *pattern;
+       /* The height of the font, built from font_ascent + font_descent */
+       int height;
+       /* The xcb-id for the font */
+       xcb_font_t id;
+};
+
+/*
+ * A client is X11-speak for a window.
+ *
+ */
+struct Client {
+       /* TODO: this is NOT final */
+       Cell old_position; /* if you set a client to floating and set it back to managed,
+                             it does remember its old position and *tries* to get back there */
+
+       /* Backpointer. A client is inside a container */
+       Container *container;
+
+       int x, y;
+       int width, height;
+
+       /* Name */
+       char *name;
+       int name_len;
+
+       /* XCB contexts */
+       xcb_window_t frame; /* Our window: The frame around the client */
+       xcb_gcontext_t titlegc; /* The titlebar’s graphic context inside the frame */
+       xcb_window_t child; /* The client’s window */
+
+       /* The following entry provides the necessary list pointers to use Client with LIST_* macros */
+       CIRCLEQ_ENTRY(Client) clients;
+};
+
+/*
+ * A container is either in default or stacking mode. It sits inside the table.
+ *
+ */
+struct Container {
+       /* Those are speaking for themselves: */
+       Client *currently_focused;
+       int colspan;
+       int rowspan;
+
+       /* Position of the container inside our table */
+       int row;
+       int col;
+       /* Xinerama: X/Y of the container */
+       int x;
+       int y;
+       /* Width/Height of the container. Changeable by the user */
+       int width;
+       int height;
+
+       /* Ensure MODE_DEFAULT maps to 0 because we use calloc for initialization later */
+       enum { MODE_DEFAULT = 0, MODE_STACK = 1 } mode;
+       CIRCLEQ_HEAD(client_head, Client) clients;
+};
+
+#endif
diff --git a/include/debug.h b/include/debug.h
new file mode 100644 (file)
index 0000000..3d9cf3e
--- /dev/null
@@ -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/include/font.h b/include/font.h
new file mode 100644 (file)
index 0000000..732c369
--- /dev/null
@@ -0,0 +1,10 @@
+#include <xcb/xcb.h>
+
+#include "data.h"
+
+#ifndef _FONT_H
+#define _FONT_H
+
+i3Font *load_font(xcb_connection_t *c, const char *pattern);
+
+#endif
diff --git a/include/handlers.h b/include/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/include/i3.h b/include/i3.h
new file mode 100644 (file)
index 0000000..d2453f4
--- /dev/null
@@ -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/include/layout.h b/include/layout.h
new file mode 100644 (file)
index 0000000..aecb2b4
--- /dev/null
@@ -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/include/queue.h b/include/queue.h
new file mode 100644 (file)
index 0000000..75bb957
--- /dev/null
@@ -0,0 +1,527 @@
+/*     $OpenBSD: queue.h,v 1.1 2007/10/26 03:14:08 niallo Exp $        */
+/*     $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $       */
+
+/*
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)queue.h     8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef        _SYS_QUEUE_H_
+#define        _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
+#define _Q_INVALIDATE(a) (a) = ((void *)-1)
+#else
+#define _Q_INVALIDATE(a)
+#endif
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type)                                         \
+struct name {                                                          \
+       struct type *slh_first; /* first element */                     \
+}
+
+#define        SLIST_HEAD_INITIALIZER(head)                                    \
+       { NULL }
+
+#define SLIST_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *sle_next;  /* next element */                      \
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define        SLIST_FIRST(head)       ((head)->slh_first)
+#define        SLIST_END(head)         NULL
+#define        SLIST_EMPTY(head)       (SLIST_FIRST(head) == SLIST_END(head))
+#define        SLIST_NEXT(elm, field)  ((elm)->field.sle_next)
+
+#define        SLIST_FOREACH(var, head, field)                                 \
+       for((var) = SLIST_FIRST(head);                                  \
+           (var) != SLIST_END(head);                                   \
+           (var) = SLIST_NEXT(var, field))
+
+#define        SLIST_FOREACH_PREVPTR(var, varp, head, field)                   \
+       for ((varp) = &SLIST_FIRST((head));                             \
+           ((var) = *(varp)) != SLIST_END(head);                       \
+           (varp) = &SLIST_NEXT((var), field))
+
+/*
+ * Singly-linked List functions.
+ */
+#define        SLIST_INIT(head) {                                              \
+       SLIST_FIRST(head) = SLIST_END(head);                            \
+}
+
+#define        SLIST_INSERT_AFTER(slistelm, elm, field) do {                   \
+       (elm)->field.sle_next = (slistelm)->field.sle_next;             \
+       (slistelm)->field.sle_next = (elm);                             \
+} while (0)
+
+#define        SLIST_INSERT_HEAD(head, elm, field) do {                        \
+       (elm)->field.sle_next = (head)->slh_first;                      \
+       (head)->slh_first = (elm);                                      \
+} while (0)
+
+#define        SLIST_REMOVE_NEXT(head, elm, field) do {                        \
+       (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;  \
+} while (0)
+
+#define        SLIST_REMOVE_HEAD(head, field) do {                             \
+       (head)->slh_first = (head)->slh_first->field.sle_next;          \
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do {                      \
+       if ((head)->slh_first == (elm)) {                               \
+               SLIST_REMOVE_HEAD((head), field);                       \
+       } else {                                                        \
+               struct type *curelm = (head)->slh_first;                \
+                                                                       \
+               while (curelm->field.sle_next != (elm))                 \
+                       curelm = curelm->field.sle_next;                \
+               curelm->field.sle_next =                                \
+                   curelm->field.sle_next->field.sle_next;             \
+               _Q_INVALIDATE((elm)->field.sle_next);                   \
+       }                                                               \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type)                                          \
+struct name {                                                          \
+       struct type *lh_first;  /* first element */                     \
+}
+
+#define LIST_HEAD_INITIALIZER(head)                                    \
+       { NULL }
+
+#define LIST_ENTRY(type)                                               \
+struct {                                                               \
+       struct type *le_next;   /* next element */                      \
+       struct type **le_prev;  /* address of previous next element */  \
+}
+
+/*
+ * List access methods
+ */
+#define        LIST_FIRST(head)                ((head)->lh_first)
+#define        LIST_END(head)                  NULL
+#define        LIST_EMPTY(head)                (LIST_FIRST(head) == LIST_END(head))
+#define        LIST_NEXT(elm, field)           ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field)                                 \
+       for((var) = LIST_FIRST(head);                                   \
+           (var)!= LIST_END(head);                                     \
+           (var) = LIST_NEXT(var, field))
+
+/*
+ * List functions.
+ */
+#define        LIST_INIT(head) do {                                            \
+       LIST_FIRST(head) = LIST_END(head);                              \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do {                    \
+       if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)  \
+               (listelm)->field.le_next->field.le_prev =               \
+                   &(elm)->field.le_next;                              \
+       (listelm)->field.le_next = (elm);                               \
+       (elm)->field.le_prev = &(listelm)->field.le_next;               \
+} while (0)
+
+#define        LIST_INSERT_BEFORE(listelm, elm, field) do {                    \
+       (elm)->field.le_prev = (listelm)->field.le_prev;                \
+       (elm)->field.le_next = (listelm);                               \
+       *(listelm)->field.le_prev = (elm);                              \
+       (listelm)->field.le_prev = &(elm)->field.le_next;               \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do {                                \
+       if (((elm)->field.le_next = (head)->lh_first) != NULL)          \
+               (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+       (head)->lh_first = (elm);                                       \
+       (elm)->field.le_prev = &(head)->lh_first;                       \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do {                                   \
+       if ((elm)->field.le_next != NULL)                               \
+               (elm)->field.le_next->field.le_prev =                   \
+                   (elm)->field.le_prev;                               \
+       *(elm)->field.le_prev = (elm)->field.le_next;                   \
+       _Q_INVALIDATE((elm)->field.le_prev);                            \
+       _Q_INVALIDATE((elm)->field.le_next);                            \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do {                            \
+       if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)     \
+               (elm2)->field.le_next->field.le_prev =                  \
+                   &(elm2)->field.le_next;                             \
+       (elm2)->field.le_prev = (elm)->field.le_prev;                   \
+       *(elm2)->field.le_prev = (elm2);                                \
+       _Q_INVALIDATE((elm)->field.le_prev);                            \
+       _Q_INVALIDATE((elm)->field.le_next);                            \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type)                                       \
+struct name {                                                          \
+       struct type *sqh_first; /* first element */                     \
+       struct type **sqh_last; /* addr of last next element */         \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head)                                 \
+       { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type)                                            \
+struct {                                                               \
+       struct type *sqe_next;  /* next element */                      \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define        SIMPLEQ_FIRST(head)         ((head)->sqh_first)
+#define        SIMPLEQ_END(head)           NULL
+#define        SIMPLEQ_EMPTY(head)         (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define        SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field)                              \
+       for((var) = SIMPLEQ_FIRST(head);                                \
+           (var) != SIMPLEQ_END(head);                                 \
+           (var) = SIMPLEQ_NEXT(var, field))
+
+/*
+ * Simple queue functions.
+ */
+#define        SIMPLEQ_INIT(head) do {                                         \
+       (head)->sqh_first = NULL;                                       \
+       (head)->sqh_last = &(head)->sqh_first;                          \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {                     \
+       if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)        \
+               (head)->sqh_last = &(elm)->field.sqe_next;              \
+       (head)->sqh_first = (elm);                                      \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {                     \
+       (elm)->field.sqe_next = NULL;                                   \
+       *(head)->sqh_last = (elm);                                      \
+       (head)->sqh_last = &(elm)->field.sqe_next;                      \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
+       if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+               (head)->sqh_last = &(elm)->field.sqe_next;              \
+       (listelm)->field.sqe_next = (elm);                              \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, field) do {                  \
+       if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+               (head)->sqh_last = &(head)->sqh_first;                  \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type)                                         \
+struct name {                                                          \
+       struct type *tqh_first; /* first element */                     \
+       struct type **tqh_last; /* addr of last next element */         \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head)                                   \
+       { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *tqe_next;  /* next element */                      \
+       struct type **tqe_prev; /* address of previous next element */  \
+}
+
+/*
+ * tail queue access methods
+ */
+#define        TAILQ_FIRST(head)               ((head)->tqh_first)
+#define        TAILQ_END(head)                 NULL
+#define        TAILQ_NEXT(elm, field)          ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname)                                     \
+       (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field)                               \
+       (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define        TAILQ_EMPTY(head)                                               \
+       (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field)                                        \
+       for((var) = TAILQ_FIRST(head);                                  \
+           (var) != TAILQ_END(head);                                   \
+           (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field)              \
+       for((var) = TAILQ_LAST(head, headname);                         \
+           (var) != TAILQ_END(head);                                   \
+           (var) = TAILQ_PREV(var, headname, field))
+
+/*
+ * Tail queue functions.
+ */
+#define        TAILQ_INIT(head) do {                                           \
+       (head)->tqh_first = NULL;                                       \
+       (head)->tqh_last = &(head)->tqh_first;                          \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do {                       \
+       if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)        \
+               (head)->tqh_first->field.tqe_prev =                     \
+                   &(elm)->field.tqe_next;                             \
+       else                                                            \
+               (head)->tqh_last = &(elm)->field.tqe_next;              \
+       (head)->tqh_first = (elm);                                      \
+       (elm)->field.tqe_prev = &(head)->tqh_first;                     \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do {                       \
+       (elm)->field.tqe_next = NULL;                                   \
+       (elm)->field.tqe_prev = (head)->tqh_last;                       \
+       *(head)->tqh_last = (elm);                                      \
+       (head)->tqh_last = &(elm)->field.tqe_next;                      \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {             \
+       if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   &(elm)->field.tqe_next;                             \
+       else                                                            \
+               (head)->tqh_last = &(elm)->field.tqe_next;              \
+       (listelm)->field.tqe_next = (elm);                              \
+       (elm)->field.tqe_prev = &(listelm)->field.tqe_next;             \
+} while (0)
+
+#define        TAILQ_INSERT_BEFORE(listelm, elm, field) do {                   \
+       (elm)->field.tqe_prev = (listelm)->field.tqe_prev;              \
+       (elm)->field.tqe_next = (listelm);                              \
+       *(listelm)->field.tqe_prev = (elm);                             \
+       (listelm)->field.tqe_prev = &(elm)->field.tqe_next;             \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do {                            \
+       if (((elm)->field.tqe_next) != NULL)                            \
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   (elm)->field.tqe_prev;                              \
+       else                                                            \
+               (head)->tqh_last = (elm)->field.tqe_prev;               \
+       *(elm)->field.tqe_prev = (elm)->field.tqe_next;                 \
+       _Q_INVALIDATE((elm)->field.tqe_prev);                           \
+       _Q_INVALIDATE((elm)->field.tqe_next);                           \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do {                     \
+       if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)   \
+               (elm2)->field.tqe_next->field.tqe_prev =                \
+                   &(elm2)->field.tqe_next;                            \
+       else                                                            \
+               (head)->tqh_last = &(elm2)->field.tqe_next;             \
+       (elm2)->field.tqe_prev = (elm)->field.tqe_prev;                 \
+       *(elm2)->field.tqe_prev = (elm2);                               \
+       _Q_INVALIDATE((elm)->field.tqe_prev);                           \
+       _Q_INVALIDATE((elm)->field.tqe_next);                           \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type)                                       \
+struct name {                                                          \
+       struct type *cqh_first;         /* first element */             \
+       struct type *cqh_last;          /* last element */              \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head)                                 \
+       { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type)                                            \
+struct {                                                               \
+       struct type *cqe_next;          /* next element */              \
+       struct type *cqe_prev;          /* previous element */          \
+}
+
+/*
+ * Circular queue access methods
+ */
+#define        CIRCLEQ_FIRST(head)             ((head)->cqh_first)
+#define        CIRCLEQ_LAST(head)              ((head)->cqh_last)
+#define        CIRCLEQ_END(head)               ((void *)(head))
+#define        CIRCLEQ_NEXT(elm, field)        ((elm)->field.cqe_next)
+#define        CIRCLEQ_PREV(elm, field)        ((elm)->field.cqe_prev)
+#define        CIRCLEQ_EMPTY(head)                                             \
+       (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
+
+#define CIRCLEQ_FOREACH(var, head, field)                              \
+       for((var) = CIRCLEQ_FIRST(head);                                \
+           (var) != CIRCLEQ_END(head);                                 \
+           (var) = CIRCLEQ_NEXT(var, field))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field)                      \
+       for((var) = CIRCLEQ_LAST(head);                                 \
+           (var) != CIRCLEQ_END(head);                                 \
+           (var) = CIRCLEQ_PREV(var, field))
+
+/*
+ * Circular queue functions.
+ */
+#define        CIRCLEQ_INIT(head) do {                                         \
+       (head)->cqh_first = CIRCLEQ_END(head);                          \
+       (head)->cqh_last = CIRCLEQ_END(head);                           \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
+       (elm)->field.cqe_next = (listelm)->field.cqe_next;              \
+       (elm)->field.cqe_prev = (listelm);                              \
+       if ((listelm)->field.cqe_next == CIRCLEQ_END(head))             \
+               (head)->cqh_last = (elm);                               \
+       else                                                            \
+               (listelm)->field.cqe_next->field.cqe_prev = (elm);      \
+       (listelm)->field.cqe_next = (elm);                              \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {          \
+       (elm)->field.cqe_next = (listelm);                              \
+       (elm)->field.cqe_prev = (listelm)->field.cqe_prev;              \
+       if ((listelm)->field.cqe_prev == CIRCLEQ_END(head))             \
+               (head)->cqh_first = (elm);                              \
+       else                                                            \
+               (listelm)->field.cqe_prev->field.cqe_next = (elm);      \
+       (listelm)->field.cqe_prev = (elm);                              \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {                     \
+       (elm)->field.cqe_next = (head)->cqh_first;                      \
+       (elm)->field.cqe_prev = CIRCLEQ_END(head);                      \
+       if ((head)->cqh_last == CIRCLEQ_END(head))                      \
+               (head)->cqh_last = (elm);                               \
+       else                                                            \
+               (head)->cqh_first->field.cqe_prev = (elm);              \
+       (head)->cqh_first = (elm);                                      \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {                     \
+       (elm)->field.cqe_next = CIRCLEQ_END(head);                      \
+       (elm)->field.cqe_prev = (head)->cqh_last;                       \
+       if ((head)->cqh_first == CIRCLEQ_END(head))                     \
+               (head)->cqh_first = (elm);                              \
+       else                                                            \
+               (head)->cqh_last->field.cqe_next = (elm);               \
+       (head)->cqh_last = (elm);                                       \
+} while (0)
+
+#define        CIRCLEQ_REMOVE(head, elm, field) do {                           \
+       if ((elm)->field.cqe_next == CIRCLEQ_END(head))                 \
+               (head)->cqh_last = (elm)->field.cqe_prev;               \
+       else                                                            \
+               (elm)->field.cqe_next->field.cqe_prev =                 \
+                   (elm)->field.cqe_prev;                              \
+       if ((elm)->field.cqe_prev == CIRCLEQ_END(head))                 \
+               (head)->cqh_first = (elm)->field.cqe_next;              \
+       else                                                            \
+               (elm)->field.cqe_prev->field.cqe_next =                 \
+                   (elm)->field.cqe_next;                              \
+       _Q_INVALIDATE((elm)->field.cqe_prev);                           \
+       _Q_INVALIDATE((elm)->field.cqe_next);                           \
+} while (0)
+
+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do {                   \
+       if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==         \
+           CIRCLEQ_END(head))                                          \
+               (head)->cqh_last = (elm2);                              \
+       else                                                            \
+               (elm2)->field.cqe_next->field.cqe_prev = (elm2);        \
+       if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==         \
+           CIRCLEQ_END(head))                                          \
+               (head)->cqh_first = (elm2);                             \
+       else                                                            \
+               (elm2)->field.cqe_prev->field.cqe_next = (elm2);        \
+       _Q_INVALIDATE((elm)->field.cqe_prev);                           \
+       _Q_INVALIDATE((elm)->field.cqe_next);                           \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/include/table.h b/include/table.h
new file mode 100644 (file)
index 0000000..1d6ca8f
--- /dev/null
@@ -0,0 +1,20 @@
+#include <stdbool.h>
+#include "data.h"
+
+#ifndef _TABLE_H
+#define _TABLE_H
+
+#define CUR_TABLE (c_ws->table)
+#define CUR_CELL (CUR_TABLE[current_col][current_row])
+
+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);
+void expand_table_cols(Workspace *workspace);
+bool cell_exists(int col, int row);
+
+#endif
diff --git a/include/util.h b/include/util.h
new file mode 100644 (file)
index 0000000..9eb2a44
--- /dev/null
@@ -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/include/xcb.h b/include/xcb.h
new file mode 100644 (file)
index 0000000..c8224ef
--- /dev/null
@@ -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
diff --git a/layout.c b/layout.c
deleted file mode 100644 (file)
index 4a09e41..0000000
--- a/layout.c
+++ /dev/null
@@ -1,181 +0,0 @@
-#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
deleted file mode 100644 (file)
index aecb2b4..0000000
--- a/layout.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#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
deleted file mode 100644 (file)
index 359e3f7..0000000
--- a/mainx.c
+++ /dev/null
@@ -1,427 +0,0 @@
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <assert.h>
-
-#include <xcb/xcb.h>
-
-#include <X11/XKBlib.h>
-#include <X11/extensions/XKB.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"
-
-Display *xkbdpy;
-
-TAILQ_HEAD(bindings_head, Binding) bindings;
-xcb_event_handlers_t evenths;
-
-static const int TOP = 20;
-static const int LEFT = 5;
-static const int BOTTOM = 5;
-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) */
-char **environment;
-
-/* hm, xcb_wm wants us to implement this. */
-table_t *byChild = 0;
-table_t *byParent = 0;
-xcb_window_t root_win;
-
-char *pattern = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso8859-1";
-int num_screens = 0;
-
-/*
- *
- * TODO: what exactly does this, what happens if we leave stuff out?
- *
- */
-void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *c, xcb_window_t window, window_attributes_t wa)
-{
-       printf("managing window.\n");
-       xcb_drawable_t d = { window };
-       xcb_get_geometry_cookie_t geomc;
-       xcb_get_geometry_reply_t *geom;
-       xcb_get_window_attributes_reply_t *attr = 0;
-       if(wa.tag == TAG_COOKIE)
-       {
-               attr = xcb_get_window_attributes_reply(c, wa.u.cookie, 0);
-               if(!attr)
-                       return;
-               if(attr->map_state != XCB_MAP_STATE_VIEWABLE)
-               {
-                       printf("Window 0x%08x is not mapped. Ignoring.\n", window);
-                       free(attr);
-                       return;
-               }
-               wa.tag = TAG_VALUE;
-               wa.u.override_redirect = attr->override_redirect;
-       }
-       if(!wa.u.override_redirect && table_get(byChild, window))
-       {
-               printf("Window 0x%08x already managed. Ignoring.\n", window);
-               free(attr);
-               return;
-       }
-       if(wa.u.override_redirect)
-       {
-               printf("Window 0x%08x has override-redirect set. Ignoring.\n", window);
-               free(attr);
-               return;
-       }
-       geomc = xcb_get_geometry(c, d);
-       if(!attr)
-       {
-               wa.tag = TAG_COOKIE;
-               wa.u.cookie = xcb_get_window_attributes(c, window);
-               attr = xcb_get_window_attributes_reply(c, wa.u.cookie, 0);
-       }
-       geom = xcb_get_geometry_reply(c, geomc, 0);
-       if(attr && geom)
-       {
-               reparent_window(c, window, attr->visual, geom->root, geom->depth, geom->x, geom->y, geom->width, geom->height);
-               xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME);
-       }
-       free(attr);
-       free(geom);
-}
-
-/*
- * Let’s own this window…
- *
- */
-void reparent_window(xcb_connection_t *conn, xcb_window_t child,
-               xcb_visualid_t visual, xcb_window_t root, uint8_t depth,
-               int16_t x, int16_t y, uint16_t width, uint16_t height) {
-
-       Client *new = table_get(byChild, child);
-       if (new == NULL) {
-               printf("oh, it's new\n");
-               new = calloc(sizeof(Client), 1);
-               new->x = -1;
-               new->y = -1;
-       }
-       uint32_t mask = 0;
-       uint32_t values[3];
-
-       /* Insert into the currently active container */
-       CIRCLEQ_INSERT_TAIL(&(CUR_CELL->clients), new, clients);
-
-       printf("currently_focused = %p\n", new);
-       CUR_CELL->currently_focused = new;
-       new->container = CUR_CELL;
-
-       new->frame = xcb_generate_id(conn);
-       new->child = child;
-       new->width = width;
-       new->height = height;
-
-       /* Don’t generate events for our new window, it should *not* be managed */
-       mask |= XCB_CW_OVERRIDE_REDIRECT;
-       values[0] = 1;
-
-       /* We want to know when… */
-       mask |= XCB_CW_EVENT_MASK;
-       values[1] =     XCB_EVENT_MASK_BUTTON_PRESS | /* …mouse is pressed/released */
-                       XCB_EVENT_MASK_BUTTON_RELEASE |
-                       XCB_EVENT_MASK_EXPOSURE | /* …our window needs to be redrawn */
-                       XCB_EVENT_MASK_ENTER_WINDOW /* …user moves cursor inside our window */;
-
-       printf("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
-
-       /* Yo dawg, I heard you like windows, so I create a window around your window… */
-       xcb_create_window(conn,
-                       depth,
-                       new->frame,
-                       root,
-                       x,
-                       y,
-                       width + LEFT + RIGHT,
-                       height + TOP + BOTTOM,
-                       /* border_width */ 0,
-                       XCB_WINDOW_CLASS_INPUT_OUTPUT,
-                       visual,
-                       mask,
-                       values);
-       xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child);
-
-       /* Map the window on the screen (= make it visible) */
-       xcb_map_window(conn, new->frame);
-
-       /* Generate a graphics context for the titlebar */
-       new->titlegc = xcb_generate_id(conn);
-       xcb_create_gc(conn, new->titlegc, new->frame, 0, 0);
-
-       /* Draw decorations */
-       decorate_window(conn, new);
-
-       /* Put our data structure (Client) into the table */
-       table_put(byParent, new->frame, new);
-       table_put(byChild, child, new);
-
-       /* Moves the original window into the new frame we've created for it */
-       i3Font *font = load_font(conn, pattern);
-       xcb_reparent_window(conn, child, new->frame, 0, font->height);
-
-       /* We are interested in property changes */
-       mask = XCB_CW_EVENT_MASK;
-       values[0] =     XCB_EVENT_MASK_PROPERTY_CHANGE |
-                       XCB_EVENT_MASK_STRUCTURE_NOTIFY |
-                       XCB_EVENT_MASK_ENTER_WINDOW |
-                       XCB_EVENT_MASK_BUTTON_PRESS;
-       xcb_change_window_attributes(conn, child, mask, values);
-
-       /* We need to grab the mouse buttons for click to focus */
-       xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS,
-                       XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE, 1 /* left mouse button */,
-                       XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
-
-       /* Focus the new window */
-       xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, new->child, XCB_CURRENT_TIME);
-
-       render_layout(conn);
-}
-
-void manage_existing_windows(xcb_connection_t *c, xcb_property_handlers_t *prophs, xcb_window_t root) {
-       xcb_query_tree_cookie_t wintree;
-       xcb_query_tree_reply_t *rep;
-       int i, len;
-       xcb_window_t *children;
-       xcb_get_window_attributes_cookie_t *cookies;
-
-       wintree = xcb_query_tree(c, root);
-       rep = xcb_query_tree_reply(c, wintree, 0);
-       if(!rep)
-               return;
-       len = xcb_query_tree_children_length(rep);
-       cookies = malloc(len * sizeof(*cookies));
-       if(!cookies)
-       {
-               free(rep);
-               return;
-       }
-       children = xcb_query_tree_children(rep);
-       for(i = 0; i < len; ++i)
-               cookies[i] = xcb_get_window_attributes(c, children[i]);
-       for(i = 0; i < len; ++i)
-       {
-               window_attributes_t wa = { TAG_COOKIE, { cookies[i] } };
-               manage_window(prophs, c, children[i], wa);
-       }
-       free(rep);
-}
-
-static void initialize_xinerama(xcb_connection_t *conn) {
-       xcb_xinerama_query_screens_reply_t *reply;
-       xcb_xinerama_screen_info_t *screen_info;
-       int screen;
-
-       if (!xcb_get_extension_data(conn, &xcb_xinerama_id)->present) {
-               printf("Xinerama extension not found, disabling.\n");
-               return;
-       }
-
-       if (!xcb_xinerama_is_active_reply(conn, xcb_xinerama_is_active(conn), NULL)->state) {
-               printf("Xinerama is not active (in your X-Server), disabling.\n");
-               return;
-       }
-
-
-       reply = xcb_xinerama_query_screens_reply(conn, xcb_xinerama_query_screens_unchecked(conn), NULL);
-       /* TODO: error check */
-       screen_info = xcb_xinerama_query_screens_screen_info(reply);
-
-       num_screens = xcb_xinerama_query_screens_screen_info_length(reply);
-
-       /* Just go through each workspace and associate as many screens as we can. */
-       for (screen = 0; screen < num_screens; screen++) {
-               workspaces[screen].x = screen_info[screen].x_org;
-               workspaces[screen].y = screen_info[screen].y_org;
-               workspaces[screen].width = screen_info[screen].width;
-               workspaces[screen].height = screen_info[screen].height;
-               workspaces[screen].screen_num = screen;
-
-               printf("found Xinerama screen: %d x %d at %d x %d\n",
-                               screen_info[screen].width, screen_info[screen].height,
-                               screen_info[screen].x_org, screen_info[screen].y_org);
-       }
-
-       free(screen_info);
-}
-
-int main(int argc, char *argv[], char *env[]) {
-       int i, e = 0;
-
-       for (i = 0; (env[i] != NULL); i++)
-               if (strncmp(env[i], "LC_", strlen("LC_")) == 0 ||
-                       strncmp(env[i], "LANG=", strlen("LANG=")) == 0 ||
-                       strncmp(env[i], "DISPLAY=", strlen("DISPLAY=")) == 0) {
-                       printf("Passing environment \"%s\"\n", env[i]);
-                       environment = realloc(environment, sizeof(char*) * ++e);
-                       environment[e-1] = env[i];
-               }
-
-       /* environment has to be NULL-terminated */
-       environment = realloc(environment, sizeof(char*) * ++e);
-       environment[e-1] = NULL;
-
-       init_table();
-
-       xcb_connection_t *c;
-       xcb_property_handlers_t prophs;
-       xcb_window_t root;
-
-       int screens;
-
-       memset(&evenths, 0, sizeof(xcb_event_handlers_t));
-       memset(&prophs, 0, sizeof(xcb_property_handlers_t));
-
-       byChild = alloc_table();
-       byParent = alloc_table();
-
-       TAILQ_INIT(&bindings);
-
-       c = xcb_connect(NULL, &screens);
-
-       printf("x screen is %d\n", screens);
-
-       /* TODO: this has to be more beautiful somewhen */
-       int major, minor, error;
-
-       major = XkbMajorVersion;
-       minor = XkbMinorVersion;
-
-       int evBase, errBase;
-
-       if ((xkbdpy = XkbOpenDisplay(getenv("DISPLAY"), &evBase, &errBase, &major, &minor, &error)) == NULL) {
-               fprintf(stderr, "XkbOpenDisplay() failed\n");
-               return 1;
-       }
-
-       int i1;
-       if (!XkbQueryExtension(xkbdpy,&i1,&evBase,&errBase,&major,&minor)) {
-               fprintf(stderr, "XKB not supported by X-server\n");
-               return 1;
-       }
-       /* end of ugliness */
-
-       xcb_event_handlers_init(c, &evenths);
-       for(i = 2; i < 128; ++i)
-               xcb_event_set_handler(&evenths, i, handle_event, 0);
-
-       for(i = 0; i < 256; ++i)
-               xcb_event_set_error_handler(&evenths, i, (xcb_generic_error_handler_t)handle_event, 0);
-
-       /* Expose = an Application should redraw itself. That is, we have to redraw our
-        * contents (= top/bottom bar, titlebars for each window) */
-       xcb_event_set_expose_handler(&evenths, handle_expose_event, 0);
-
-       /* Key presses/releases are pretty obvious, I think */
-       xcb_event_set_key_press_handler(&evenths, handle_key_press, 0);
-       xcb_event_set_key_release_handler(&evenths, handle_key_release, 0);
-
-       /* Enter window = user moved his mouse over the window */
-       xcb_event_set_enter_notify_handler(&evenths, handle_enter_notify, 0);
-
-       /* Button press = user pushed a mouse button over one of our windows */
-       xcb_event_set_button_press_handler(&evenths, handle_button_press, 0);
-
-       xcb_event_set_unmap_notify_handler(&evenths, handle_unmap_notify_event, 0);
-
-       xcb_property_handlers_init(&prophs, &evenths);
-       xcb_event_set_map_notify_handler(&evenths, handle_map_notify_event, &prophs);
-
-       xcb_watch_wm_name(&prophs, 128, handle_windowname_change, 0);
-
-       root = xcb_aux_get_screen(c, screens)->root;
-       root_win = root;
-
-       uint32_t mask = XCB_CW_EVENT_MASK;
-       uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE };
-       xcb_change_window_attributes(c, root, mask, values);
-
-       #define BIND(key, modifier, cmd) { \
-               Binding *new = malloc(sizeof(Binding)); \
-               new->keycode = key; \
-               new->mods = modifier; \
-               new->command = cmd; \
-               TAILQ_INSERT_TAIL(&bindings, new, bindings); \
-       }
-
-       /* 38 = 'a' */
-       BIND(38, BIND_MODE_SWITCH, "foo");
-
-       BIND(30, 0, "exec /usr/pkg/bin/urxvt");
-
-       BIND(44, BIND_MOD_1, "h");
-       BIND(45, BIND_MOD_1, "j");
-       BIND(46, BIND_MOD_1, "k");
-       BIND(47, BIND_MOD_1, "l");
-
-       BIND(44, BIND_MOD_1 | BIND_CONTROL, "sh");
-       BIND(45, BIND_MOD_1 | BIND_CONTROL, "sj");
-       BIND(46, BIND_MOD_1 | BIND_CONTROL, "sk");
-       BIND(47, BIND_MOD_1 | BIND_CONTROL, "sl");
-
-       BIND(44, BIND_MOD_1 | BIND_SHIFT, "mh");
-       BIND(45, BIND_MOD_1 | BIND_SHIFT, "mj");
-       BIND(46, BIND_MOD_1 | BIND_SHIFT, "mk");
-       BIND(47, BIND_MOD_1 | BIND_SHIFT, "ml");
-
-       BIND(10, BIND_MOD_1 , "1");
-       BIND(11, BIND_MOD_1 , "2");
-       BIND(12, BIND_MOD_1 , "3");
-       BIND(13, BIND_MOD_1 , "4");
-       BIND(14, BIND_MOD_1 , "5");
-       BIND(15, BIND_MOD_1 , "6");
-       BIND(16, BIND_MOD_1 , "7");
-       BIND(17, BIND_MOD_1 , "8");
-       BIND(18, BIND_MOD_1 , "9");
-       BIND(19, BIND_MOD_1 , "0");
-
-       Binding *bind;
-       TAILQ_FOREACH(bind, &bindings, bindings) {
-               printf("Grabbing %d\n", bind->keycode);
-               if (bind->mods & BIND_MODE_SWITCH)
-                       xcb_grab_key(c, 0, root, 0, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC);
-               else xcb_grab_key(c, 0, root, bind->mods, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
-       }
-
-       /* check for Xinerama */
-       printf("Checking for Xinerama...\n");
-       initialize_xinerama(c);
-
-       start_application(TERMINAL, NULL);
-
-       xcb_flush(c);
-
-       manage_existing_windows(c, &prophs, root);
-
-       xcb_event_wait_for_event_loop(&evenths);
-
-       /* not reached */
-       return 0;
-}
diff --git a/queue.h b/queue.h
deleted file mode 100644 (file)
index 56d9c4a..0000000
--- a/queue.h
+++ /dev/null
@@ -1,527 +0,0 @@
-/*     $OpenBSD: queue.h,v 1.1 2007/10/26 03:14:08 niallo Exp $        */
-/*     $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $       */
-
-/*
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *     @(#)queue.h     8.5 (Berkeley) 8/20/94
- */
-
-#ifndef        _SYS_QUEUE_H_
-#define        _SYS_QUEUE_H_
-
-/*
- * This file defines five types of data structures: singly-linked lists, 
- * lists, simple queues, tail queues, and circular queues.
- *
- *
- * A singly-linked list is headed by a single forward pointer. The elements
- * are singly linked for minimum space and pointer manipulation overhead at
- * the expense of O(n) removal for arbitrary elements. New elements can be
- * added to the list after an existing element or at the head of the list.
- * Elements being removed from the head of the list should use the explicit
- * macro for this purpose for optimum efficiency. A singly-linked list may
- * only be traversed in the forward direction.  Singly-linked lists are ideal
- * for applications with large datasets and few or no removals or for
- * implementing a LIFO queue.
- *
- * A list is headed by a single forward pointer (or an array of forward
- * pointers for a hash table header). The elements are doubly linked
- * so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before
- * or after an existing element or at the head of the list. A list
- * may only be traversed in the forward direction.
- *
- * A simple queue is headed by a pair of pointers, one the head of the
- * list and the other to the tail of the list. The elements are singly
- * linked to save space, so elements can only be removed from the
- * head of the list. New elements can be added to the list before or after
- * an existing element, at the head of the list, or at the end of the
- * list. A simple queue may only be traversed in the forward direction.
- *
- * A tail queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before or
- * after an existing element, at the head of the list, or at the end of
- * the list. A tail queue may be traversed in either direction.
- *
- * A circle queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before or after
- * an existing element, at the head of the list, or at the end of the list.
- * A circle queue may be traversed in either direction, but has a more
- * complex end of list detection.
- *
- * For details on the use of these macros, see the queue(3) manual page.
- */
-
-#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
-#define _Q_INVALIDATE(a) (a) = ((void *)-1)
-#else
-#define _Q_INVALIDATE(a)
-#endif
-
-/*
- * Singly-linked List definitions.
- */
-#define SLIST_HEAD(name, type)                                         \
-struct name {                                                          \
-       struct type *slh_first; /* first element */                     \
-}
-#define        SLIST_HEAD_INITIALIZER(head)                                    \
-       { NULL }
-#define SLIST_ENTRY(type)                                              \
-struct {                                                               \
-       struct type *sle_next;  /* next element */                      \
-}
-/*
- * Singly-linked List access methods.
- */
-#define        SLIST_FIRST(head)       ((head)->slh_first)
-#define        SLIST_END(head)         NULL
-#define        SLIST_EMPTY(head)       (SLIST_FIRST(head) == SLIST_END(head))
-#define        SLIST_NEXT(elm, field)  ((elm)->field.sle_next)
-
-#define        SLIST_FOREACH(var, head, field)                                 \
-       for((var) = SLIST_FIRST(head);                                  \
-           (var) != SLIST_END(head);                                   \
-           (var) = SLIST_NEXT(var, field))
-
-#define        SLIST_FOREACH_PREVPTR(var, varp, head, field)                   \
-       for ((varp) = &SLIST_FIRST((head));                             \
-           ((var) = *(varp)) != SLIST_END(head);                       \
-           (varp) = &SLIST_NEXT((var), field))
-
-/*
- * Singly-linked List functions.
- */
-#define        SLIST_INIT(head) {                                              \
-       SLIST_FIRST(head) = SLIST_END(head);                            \
-}
-
-#define        SLIST_INSERT_AFTER(slistelm, elm, field) do {                   \
-       (elm)->field.sle_next = (slistelm)->field.sle_next;             \
-       (slistelm)->field.sle_next = (elm);                             \
-} while (0)
-
-#define        SLIST_INSERT_HEAD(head, elm, field) do {                        \
-       (elm)->field.sle_next = (head)->slh_first;                      \
-       (head)->slh_first = (elm);                                      \
-} while (0)
-
-#define        SLIST_REMOVE_NEXT(head, elm, field) do {                        \
-       (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;  \
-} while (0)
-
-#define        SLIST_REMOVE_HEAD(head, field) do {                             \
-       (head)->slh_first = (head)->slh_first->field.sle_next;          \
-} while (0)
-
-#define SLIST_REMOVE(head, elm, type, field) do {                      \
-       if ((head)->slh_first == (elm)) {                               \
-               SLIST_REMOVE_HEAD((head), field);                       \
-       } else {                                                        \
-               struct type *curelm = (head)->slh_first;                \
-                                                                       \
-               while (curelm->field.sle_next != (elm))                 \
-                       curelm = curelm->field.sle_next;                \
-               curelm->field.sle_next =                                \
-                   curelm->field.sle_next->field.sle_next;             \
-               _Q_INVALIDATE((elm)->field.sle_next);                   \
-       }                                                               \
-} while (0)
-
-/*
- * List definitions.
- */
-#define LIST_HEAD(name, type)                                          \
-struct name {                                                          \
-       struct type *lh_first;  /* first element */                     \
-}
-
-#define LIST_HEAD_INITIALIZER(head)                                    \
-       { NULL }
-
-#define LIST_ENTRY(type)                                               \
-struct {                                                               \
-       struct type *le_next;   /* next element */                      \
-       struct type **le_prev;  /* address of previous next element */  \
-}
-
-/*
- * List access methods
- */
-#define        LIST_FIRST(head)                ((head)->lh_first)
-#define        LIST_END(head)                  NULL
-#define        LIST_EMPTY(head)                (LIST_FIRST(head) == LIST_END(head))
-#define        LIST_NEXT(elm, field)           ((elm)->field.le_next)
-
-#define LIST_FOREACH(var, head, field)                                 \
-       for((var) = LIST_FIRST(head);                                   \
-           (var)!= LIST_END(head);                                     \
-           (var) = LIST_NEXT(var, field))
-
-/*
- * List functions.
- */
-#define        LIST_INIT(head) do {                                            \
-       LIST_FIRST(head) = LIST_END(head);                              \
-} while (0)
-
-#define LIST_INSERT_AFTER(listelm, elm, field) do {                    \
-       if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)  \
-               (listelm)->field.le_next->field.le_prev =               \
-                   &(elm)->field.le_next;                              \
-       (listelm)->field.le_next = (elm);                               \
-       (elm)->field.le_prev = &(listelm)->field.le_next;               \
-} while (0)
-
-#define        LIST_INSERT_BEFORE(listelm, elm, field) do {                    \
-       (elm)->field.le_prev = (listelm)->field.le_prev;                \
-       (elm)->field.le_next = (listelm);                               \
-       *(listelm)->field.le_prev = (elm);                              \
-       (listelm)->field.le_prev = &(elm)->field.le_next;               \
-} while (0)
-
-#define LIST_INSERT_HEAD(head, elm, field) do {                                \
-       if (((elm)->field.le_next = (head)->lh_first) != NULL)          \
-               (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
-       (head)->lh_first = (elm);                                       \
-       (elm)->field.le_prev = &(head)->lh_first;                       \
-} while (0)
-
-#define LIST_REMOVE(elm, field) do {                                   \
-       if ((elm)->field.le_next != NULL)                               \
-               (elm)->field.le_next->field.le_prev =                   \
-                   (elm)->field.le_prev;                               \
-       *(elm)->field.le_prev = (elm)->field.le_next;                   \
-       _Q_INVALIDATE((elm)->field.le_prev);                            \
-       _Q_INVALIDATE((elm)->field.le_next);                            \
-} while (0)
-
-#define LIST_REPLACE(elm, elm2, field) do {                            \
-       if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)     \
-               (elm2)->field.le_next->field.le_prev =                  \
-                   &(elm2)->field.le_next;                             \
-       (elm2)->field.le_prev = (elm)->field.le_prev;                   \
-       *(elm2)->field.le_prev = (elm2);                                \
-       _Q_INVALIDATE((elm)->field.le_prev);                            \
-       _Q_INVALIDATE((elm)->field.le_next);                            \
-} while (0)
-
-/*
- * Simple queue definitions.
- */
-#define SIMPLEQ_HEAD(name, type)                                       \
-struct name {                                                          \
-       struct type *sqh_first; /* first element */                     \
-       struct type **sqh_last; /* addr of last next element */         \
-}
-
-#define SIMPLEQ_HEAD_INITIALIZER(head)                                 \
-       { NULL, &(head).sqh_first }
-
-#define SIMPLEQ_ENTRY(type)                                            \
-struct {                                                               \
-       struct type *sqe_next;  /* next element */                      \
-}
-
-/*
- * Simple queue access methods.
- */
-#define        SIMPLEQ_FIRST(head)         ((head)->sqh_first)
-#define        SIMPLEQ_END(head)           NULL
-#define        SIMPLEQ_EMPTY(head)         (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
-#define        SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)
-
-#define SIMPLEQ_FOREACH(var, head, field)                              \
-       for((var) = SIMPLEQ_FIRST(head);                                \
-           (var) != SIMPLEQ_END(head);                                 \
-           (var) = SIMPLEQ_NEXT(var, field))
-
-/*
- * Simple queue functions.
- */
-#define        SIMPLEQ_INIT(head) do {                                         \
-       (head)->sqh_first = NULL;                                       \
-       (head)->sqh_last = &(head)->sqh_first;                          \
-} while (0)
-
-#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {                     \
-       if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)        \
-               (head)->sqh_last = &(elm)->field.sqe_next;              \
-       (head)->sqh_first = (elm);                                      \
-} while (0)
-
-#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {                     \
-       (elm)->field.sqe_next = NULL;                                   \
-       *(head)->sqh_last = (elm);                                      \
-       (head)->sqh_last = &(elm)->field.sqe_next;                      \
-} while (0)
-
-#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
-       if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
-               (head)->sqh_last = &(elm)->field.sqe_next;              \
-       (listelm)->field.sqe_next = (elm);                              \
-} while (0)
-
-#define SIMPLEQ_REMOVE_HEAD(head, field) do {                  \
-       if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
-               (head)->sqh_last = &(head)->sqh_first;                  \
-} while (0)
-
-/*
- * Tail queue definitions.
- */
-#define TAILQ_HEAD(name, type)                                         \
-struct name {                                                          \
-       struct type *tqh_first; /* first element */                     \
-       struct type **tqh_last; /* addr of last next element */         \
-}
-
-#define TAILQ_HEAD_INITIALIZER(head)                                   \
-       { NULL, &(head).tqh_first }
-
-#define TAILQ_ENTRY(type)                                              \
-struct {                                                               \
-       struct type *tqe_next;  /* next element */                      \
-       struct type **tqe_prev; /* address of previous next element */  \
-}
-
-/* 
- * tail queue access methods 
- */
-#define        TAILQ_FIRST(head)               ((head)->tqh_first)
-#define        TAILQ_END(head)                 NULL
-#define        TAILQ_NEXT(elm, field)          ((elm)->field.tqe_next)
-#define TAILQ_LAST(head, headname)                                     \
-       (*(((struct headname *)((head)->tqh_last))->tqh_last))
-/* XXX */
-#define TAILQ_PREV(elm, headname, field)                               \
-       (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
-#define        TAILQ_EMPTY(head)                                               \
-       (TAILQ_FIRST(head) == TAILQ_END(head))
-
-#define TAILQ_FOREACH(var, head, field)                                        \
-       for((var) = TAILQ_FIRST(head);                                  \
-           (var) != TAILQ_END(head);                                   \
-           (var) = TAILQ_NEXT(var, field))
-
-#define TAILQ_FOREACH_REVERSE(var, head, headname, field)              \
-       for((var) = TAILQ_LAST(head, headname);                         \
-           (var) != TAILQ_END(head);                                   \
-           (var) = TAILQ_PREV(var, headname, field))
-
-/*
- * Tail queue functions.
- */
-#define        TAILQ_INIT(head) do {                                           \
-       (head)->tqh_first = NULL;                                       \
-       (head)->tqh_last = &(head)->tqh_first;                          \
-} while (0)
-
-#define TAILQ_INSERT_HEAD(head, elm, field) do {                       \
-       if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)        \
-               (head)->tqh_first->field.tqe_prev =                     \
-                   &(elm)->field.tqe_next;                             \
-       else                                                            \
-               (head)->tqh_last = &(elm)->field.tqe_next;              \
-       (head)->tqh_first = (elm);                                      \
-       (elm)->field.tqe_prev = &(head)->tqh_first;                     \
-} while (0)
-
-#define TAILQ_INSERT_TAIL(head, elm, field) do {                       \
-       (elm)->field.tqe_next = NULL;                                   \
-       (elm)->field.tqe_prev = (head)->tqh_last;                       \
-       *(head)->tqh_last = (elm);                                      \
-       (head)->tqh_last = &(elm)->field.tqe_next;                      \
-} while (0)
-
-#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {             \
-       if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
-               (elm)->field.tqe_next->field.tqe_prev =                 \
-                   &(elm)->field.tqe_next;                             \
-       else                                                            \
-               (head)->tqh_last = &(elm)->field.tqe_next;              \
-       (listelm)->field.tqe_next = (elm);                              \
-       (elm)->field.tqe_prev = &(listelm)->field.tqe_next;             \
-} while (0)
-
-#define        TAILQ_INSERT_BEFORE(listelm, elm, field) do {                   \
-       (elm)->field.tqe_prev = (listelm)->field.tqe_prev;              \
-       (elm)->field.tqe_next = (listelm);                              \
-       *(listelm)->field.tqe_prev = (elm);                             \
-       (listelm)->field.tqe_prev = &(elm)->field.tqe_next;             \
-} while (0)
-
-#define TAILQ_REMOVE(head, elm, field) do {                            \
-       if (((elm)->field.tqe_next) != NULL)                            \
-               (elm)->field.tqe_next->field.tqe_prev =                 \
-                   (elm)->field.tqe_prev;                              \
-       else                                                            \
-               (head)->tqh_last = (elm)->field.tqe_prev;               \
-       *(elm)->field.tqe_prev = (elm)->field.tqe_next;                 \
-       _Q_INVALIDATE((elm)->field.tqe_prev);                           \
-       _Q_INVALIDATE((elm)->field.tqe_next);                           \
-} while (0)
-
-#define TAILQ_REPLACE(head, elm, elm2, field) do {                     \
-       if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)   \
-               (elm2)->field.tqe_next->field.tqe_prev =                \
-                   &(elm2)->field.tqe_next;                            \
-       else                                                            \
-               (head)->tqh_last = &(elm2)->field.tqe_next;             \
-       (elm2)->field.tqe_prev = (elm)->field.tqe_prev;                 \
-       *(elm2)->field.tqe_prev = (elm2);                               \
-       _Q_INVALIDATE((elm)->field.tqe_prev);                           \
-       _Q_INVALIDATE((elm)->field.tqe_next);                           \
-} while (0)
-
-/*
- * Circular queue definitions.
- */
-#define CIRCLEQ_HEAD(name, type)                                       \
-struct name {                                                          \
-       struct type *cqh_first;         /* first element */             \
-       struct type *cqh_last;          /* last element */              \
-}
-
-#define CIRCLEQ_HEAD_INITIALIZER(head)                                 \
-       { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
-
-#define CIRCLEQ_ENTRY(type)                                            \
-struct {                                                               \
-       struct type *cqe_next;          /* next element */              \
-       struct type *cqe_prev;          /* previous element */          \
-}
-
-/*
- * Circular queue access methods 
- */
-#define        CIRCLEQ_FIRST(head)             ((head)->cqh_first)
-#define        CIRCLEQ_LAST(head)              ((head)->cqh_last)
-#define        CIRCLEQ_END(head)               ((void *)(head))
-#define        CIRCLEQ_NEXT(elm, field)        ((elm)->field.cqe_next)
-#define        CIRCLEQ_PREV(elm, field)        ((elm)->field.cqe_prev)
-#define        CIRCLEQ_EMPTY(head)                                             \
-       (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
-
-#define CIRCLEQ_FOREACH(var, head, field)                              \
-       for((var) = CIRCLEQ_FIRST(head);                                \
-           (var) != CIRCLEQ_END(head);                                 \
-           (var) = CIRCLEQ_NEXT(var, field))
-
-#define CIRCLEQ_FOREACH_REVERSE(var, head, field)                      \
-       for((var) = CIRCLEQ_LAST(head);                                 \
-           (var) != CIRCLEQ_END(head);                                 \
-           (var) = CIRCLEQ_PREV(var, field))
-
-/*
- * Circular queue functions.
- */
-#define        CIRCLEQ_INIT(head) do {                                         \
-       (head)->cqh_first = CIRCLEQ_END(head);                          \
-       (head)->cqh_last = CIRCLEQ_END(head);                           \
-} while (0)
-
-#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
-       (elm)->field.cqe_next = (listelm)->field.cqe_next;              \
-       (elm)->field.cqe_prev = (listelm);                              \
-       if ((listelm)->field.cqe_next == CIRCLEQ_END(head))             \
-               (head)->cqh_last = (elm);                               \
-       else                                                            \
-               (listelm)->field.cqe_next->field.cqe_prev = (elm);      \
-       (listelm)->field.cqe_next = (elm);                              \
-} while (0)
-
-#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {          \
-       (elm)->field.cqe_next = (listelm);                              \
-       (elm)->field.cqe_prev = (listelm)->field.cqe_prev;              \
-       if ((listelm)->field.cqe_prev == CIRCLEQ_END(head))             \
-               (head)->cqh_first = (elm);                              \
-       else                                                            \
-               (listelm)->field.cqe_prev->field.cqe_next = (elm);      \
-       (listelm)->field.cqe_prev = (elm);                              \
-} while (0)
-
-#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {                     \
-       (elm)->field.cqe_next = (head)->cqh_first;                      \
-       (elm)->field.cqe_prev = CIRCLEQ_END(head);                      \
-       if ((head)->cqh_last == CIRCLEQ_END(head))                      \
-               (head)->cqh_last = (elm);                               \
-       else                                                            \
-               (head)->cqh_first->field.cqe_prev = (elm);              \
-       (head)->cqh_first = (elm);                                      \
-} while (0)
-
-#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {                     \
-       (elm)->field.cqe_next = CIRCLEQ_END(head);                      \
-       (elm)->field.cqe_prev = (head)->cqh_last;                       \
-       if ((head)->cqh_first == CIRCLEQ_END(head))                     \
-               (head)->cqh_first = (elm);                              \
-       else                                                            \
-               (head)->cqh_last->field.cqe_next = (elm);               \
-       (head)->cqh_last = (elm);                                       \
-} while (0)
-
-#define        CIRCLEQ_REMOVE(head, elm, field) do {                           \
-       if ((elm)->field.cqe_next == CIRCLEQ_END(head))                 \
-               (head)->cqh_last = (elm)->field.cqe_prev;               \
-       else                                                            \
-               (elm)->field.cqe_next->field.cqe_prev =                 \
-                   (elm)->field.cqe_prev;                              \
-       if ((elm)->field.cqe_prev == CIRCLEQ_END(head))                 \
-               (head)->cqh_first = (elm)->field.cqe_next;              \
-       else                                                            \
-               (elm)->field.cqe_prev->field.cqe_next =                 \
-                   (elm)->field.cqe_next;                              \
-       _Q_INVALIDATE((elm)->field.cqe_prev);                           \
-       _Q_INVALIDATE((elm)->field.cqe_next);                           \
-} while (0)
-
-#define CIRCLEQ_REPLACE(head, elm, elm2, field) do {                   \
-       if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==         \
-           CIRCLEQ_END(head))                                          \
-               (head)->cqh_last = (elm2);                              \
-       else                                                            \
-               (elm2)->field.cqe_next->field.cqe_prev = (elm2);        \
-       if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==         \
-           CIRCLEQ_END(head))                                          \
-               (head)->cqh_first = (elm2);                             \
-       else                                                            \
-               (elm2)->field.cqe_prev->field.cqe_next = (elm2);        \
-       _Q_INVALIDATE((elm)->field.cqe_prev);                           \
-       _Q_INVALIDATE((elm)->field.cqe_next);                           \
-} while (0)
-
-#endif /* !_SYS_QUEUE_H_ */
diff --git a/src/commands.c b/src/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/src/debug.c b/src/debug.c
new file mode 100644 (file)
index 0000000..cbdbd36
--- /dev/null
@@ -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/src/font.c b/src/font.c
new file mode 100644 (file)
index 0000000..803ac0a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Handles font loading
+ *
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <xcb/xcb.h>
+
+#include "data.h"
+#include "util.h"
+
+i3Font *load_font(xcb_connection_t *c, const char *pattern) {
+       /* TODO: this function should be caching */
+       i3Font *new = malloc(sizeof(i3Font));
+
+       xcb_list_fonts_with_info_cookie_t cookie = xcb_list_fonts_with_info(c, 1, strlen(pattern), pattern);
+       xcb_list_fonts_with_info_reply_t *reply = xcb_list_fonts_with_info_reply(c, cookie, NULL);
+       if (!reply) {
+               printf("Could not load font\n");
+               exit(1);
+       }
+
+       /* Oh my, this is so ugly :-(. Why can’t they just return a null-terminated
+        * string? That’s what abstraction layers are for. */
+       char buffer[xcb_list_fonts_with_info_name_length(reply)+1];
+       memset(buffer, 0, sizeof(buffer));
+       memcpy(buffer, xcb_list_fonts_with_info_name(reply), sizeof(buffer)-1);
+       new->name = strdup(buffer);
+       new->pattern = strdup(pattern);
+       new->height = reply->font_ascent + reply->font_descent;
+
+       /* Actually load the font */
+       new->id = xcb_generate_id(c);
+       xcb_void_cookie_t font_cookie = xcb_open_font_checked(c, new->id, strlen(pattern), pattern);
+       check_error(c, font_cookie, "Could not open font");
+
+       return new;
+}
diff --git a/src/handlers.c b/src/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/src/layout.c b/src/layout.c
new file mode 100644 (file)
index 0000000..4a09e41
--- /dev/null
@@ -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/src/mainx.c b/src/mainx.c
new file mode 100644 (file)
index 0000000..359e3f7
--- /dev/null
@@ -0,0 +1,427 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include <xcb/xcb.h>
+
+#include <X11/XKBlib.h>
+#include <X11/extensions/XKB.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"
+
+Display *xkbdpy;
+
+TAILQ_HEAD(bindings_head, Binding) bindings;
+xcb_event_handlers_t evenths;
+
+static const int TOP = 20;
+static const int LEFT = 5;
+static const int BOTTOM = 5;
+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) */
+char **environment;
+
+/* hm, xcb_wm wants us to implement this. */
+table_t *byChild = 0;
+table_t *byParent = 0;
+xcb_window_t root_win;
+
+char *pattern = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso8859-1";
+int num_screens = 0;
+
+/*
+ *
+ * TODO: what exactly does this, what happens if we leave stuff out?
+ *
+ */
+void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *c, xcb_window_t window, window_attributes_t wa)
+{
+       printf("managing window.\n");
+       xcb_drawable_t d = { window };
+       xcb_get_geometry_cookie_t geomc;
+       xcb_get_geometry_reply_t *geom;
+       xcb_get_window_attributes_reply_t *attr = 0;
+       if(wa.tag == TAG_COOKIE)
+       {
+               attr = xcb_get_window_attributes_reply(c, wa.u.cookie, 0);
+               if(!attr)
+                       return;
+               if(attr->map_state != XCB_MAP_STATE_VIEWABLE)
+               {
+                       printf("Window 0x%08x is not mapped. Ignoring.\n", window);
+                       free(attr);
+                       return;
+               }
+               wa.tag = TAG_VALUE;
+               wa.u.override_redirect = attr->override_redirect;
+       }
+       if(!wa.u.override_redirect && table_get(byChild, window))
+       {
+               printf("Window 0x%08x already managed. Ignoring.\n", window);
+               free(attr);
+               return;
+       }
+       if(wa.u.override_redirect)
+       {
+               printf("Window 0x%08x has override-redirect set. Ignoring.\n", window);
+               free(attr);
+               return;
+       }
+       geomc = xcb_get_geometry(c, d);
+       if(!attr)
+       {
+               wa.tag = TAG_COOKIE;
+               wa.u.cookie = xcb_get_window_attributes(c, window);
+               attr = xcb_get_window_attributes_reply(c, wa.u.cookie, 0);
+       }
+       geom = xcb_get_geometry_reply(c, geomc, 0);
+       if(attr && geom)
+       {
+               reparent_window(c, window, attr->visual, geom->root, geom->depth, geom->x, geom->y, geom->width, geom->height);
+               xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME);
+       }
+       free(attr);
+       free(geom);
+}
+
+/*
+ * Let’s own this window…
+ *
+ */
+void reparent_window(xcb_connection_t *conn, xcb_window_t child,
+               xcb_visualid_t visual, xcb_window_t root, uint8_t depth,
+               int16_t x, int16_t y, uint16_t width, uint16_t height) {
+
+       Client *new = table_get(byChild, child);
+       if (new == NULL) {
+               printf("oh, it's new\n");
+               new = calloc(sizeof(Client), 1);
+               new->x = -1;
+               new->y = -1;
+       }
+       uint32_t mask = 0;
+       uint32_t values[3];
+
+       /* Insert into the currently active container */
+       CIRCLEQ_INSERT_TAIL(&(CUR_CELL->clients), new, clients);
+
+       printf("currently_focused = %p\n", new);
+       CUR_CELL->currently_focused = new;
+       new->container = CUR_CELL;
+
+       new->frame = xcb_generate_id(conn);
+       new->child = child;
+       new->width = width;
+       new->height = height;
+
+       /* Don’t generate events for our new window, it should *not* be managed */
+       mask |= XCB_CW_OVERRIDE_REDIRECT;
+       values[0] = 1;
+
+       /* We want to know when… */
+       mask |= XCB_CW_EVENT_MASK;
+       values[1] =     XCB_EVENT_MASK_BUTTON_PRESS | /* …mouse is pressed/released */
+                       XCB_EVENT_MASK_BUTTON_RELEASE |
+                       XCB_EVENT_MASK_EXPOSURE | /* …our window needs to be redrawn */
+                       XCB_EVENT_MASK_ENTER_WINDOW /* …user moves cursor inside our window */;
+
+       printf("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
+
+       /* Yo dawg, I heard you like windows, so I create a window around your window… */
+       xcb_create_window(conn,
+                       depth,
+                       new->frame,
+                       root,
+                       x,
+                       y,
+                       width + LEFT + RIGHT,
+                       height + TOP + BOTTOM,
+                       /* border_width */ 0,
+                       XCB_WINDOW_CLASS_INPUT_OUTPUT,
+                       visual,
+                       mask,
+                       values);
+       xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child);
+
+       /* Map the window on the screen (= make it visible) */
+       xcb_map_window(conn, new->frame);
+
+       /* Generate a graphics context for the titlebar */
+       new->titlegc = xcb_generate_id(conn);
+       xcb_create_gc(conn, new->titlegc, new->frame, 0, 0);
+
+       /* Draw decorations */
+       decorate_window(conn, new);
+
+       /* Put our data structure (Client) into the table */
+       table_put(byParent, new->frame, new);
+       table_put(byChild, child, new);
+
+       /* Moves the original window into the new frame we've created for it */
+       i3Font *font = load_font(conn, pattern);
+       xcb_reparent_window(conn, child, new->frame, 0, font->height);
+
+       /* We are interested in property changes */
+       mask = XCB_CW_EVENT_MASK;
+       values[0] =     XCB_EVENT_MASK_PROPERTY_CHANGE |
+                       XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+                       XCB_EVENT_MASK_ENTER_WINDOW |
+                       XCB_EVENT_MASK_BUTTON_PRESS;
+       xcb_change_window_attributes(conn, child, mask, values);
+
+       /* We need to grab the mouse buttons for click to focus */
+       xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS,
+                       XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE, 1 /* left mouse button */,
+                       XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
+
+       /* Focus the new window */
+       xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, new->child, XCB_CURRENT_TIME);
+
+       render_layout(conn);
+}
+
+void manage_existing_windows(xcb_connection_t *c, xcb_property_handlers_t *prophs, xcb_window_t root) {
+       xcb_query_tree_cookie_t wintree;
+       xcb_query_tree_reply_t *rep;
+       int i, len;
+       xcb_window_t *children;
+       xcb_get_window_attributes_cookie_t *cookies;
+
+       wintree = xcb_query_tree(c, root);
+       rep = xcb_query_tree_reply(c, wintree, 0);
+       if(!rep)
+               return;
+       len = xcb_query_tree_children_length(rep);
+       cookies = malloc(len * sizeof(*cookies));
+       if(!cookies)
+       {
+               free(rep);
+               return;
+       }
+       children = xcb_query_tree_children(rep);
+       for(i = 0; i < len; ++i)
+               cookies[i] = xcb_get_window_attributes(c, children[i]);
+       for(i = 0; i < len; ++i)
+       {
+               window_attributes_t wa = { TAG_COOKIE, { cookies[i] } };
+               manage_window(prophs, c, children[i], wa);
+       }
+       free(rep);
+}
+
+static void initialize_xinerama(xcb_connection_t *conn) {
+       xcb_xinerama_query_screens_reply_t *reply;
+       xcb_xinerama_screen_info_t *screen_info;
+       int screen;
+
+       if (!xcb_get_extension_data(conn, &xcb_xinerama_id)->present) {
+               printf("Xinerama extension not found, disabling.\n");
+               return;
+       }
+
+       if (!xcb_xinerama_is_active_reply(conn, xcb_xinerama_is_active(conn), NULL)->state) {
+               printf("Xinerama is not active (in your X-Server), disabling.\n");
+               return;
+       }
+
+
+       reply = xcb_xinerama_query_screens_reply(conn, xcb_xinerama_query_screens_unchecked(conn), NULL);
+       /* TODO: error check */
+       screen_info = xcb_xinerama_query_screens_screen_info(reply);
+
+       num_screens = xcb_xinerama_query_screens_screen_info_length(reply);
+
+       /* Just go through each workspace and associate as many screens as we can. */
+       for (screen = 0; screen < num_screens; screen++) {
+               workspaces[screen].x = screen_info[screen].x_org;
+               workspaces[screen].y = screen_info[screen].y_org;
+               workspaces[screen].width = screen_info[screen].width;
+               workspaces[screen].height = screen_info[screen].height;
+               workspaces[screen].screen_num = screen;
+
+               printf("found Xinerama screen: %d x %d at %d x %d\n",
+                               screen_info[screen].width, screen_info[screen].height,
+                               screen_info[screen].x_org, screen_info[screen].y_org);
+       }
+
+       free(screen_info);
+}
+
+int main(int argc, char *argv[], char *env[]) {
+       int i, e = 0;
+
+       for (i = 0; (env[i] != NULL); i++)
+               if (strncmp(env[i], "LC_", strlen("LC_")) == 0 ||
+                       strncmp(env[i], "LANG=", strlen("LANG=")) == 0 ||
+                       strncmp(env[i], "DISPLAY=", strlen("DISPLAY=")) == 0) {
+                       printf("Passing environment \"%s\"\n", env[i]);
+                       environment = realloc(environment, sizeof(char*) * ++e);
+                       environment[e-1] = env[i];
+               }
+
+       /* environment has to be NULL-terminated */
+       environment = realloc(environment, sizeof(char*) * ++e);
+       environment[e-1] = NULL;
+
+       init_table();
+
+       xcb_connection_t *c;
+       xcb_property_handlers_t prophs;
+       xcb_window_t root;
+
+       int screens;
+
+       memset(&evenths, 0, sizeof(xcb_event_handlers_t));
+       memset(&prophs, 0, sizeof(xcb_property_handlers_t));
+
+       byChild = alloc_table();
+       byParent = alloc_table();
+
+       TAILQ_INIT(&bindings);
+
+       c = xcb_connect(NULL, &screens);
+
+       printf("x screen is %d\n", screens);
+
+       /* TODO: this has to be more beautiful somewhen */
+       int major, minor, error;
+
+       major = XkbMajorVersion;
+       minor = XkbMinorVersion;
+
+       int evBase, errBase;
+
+       if ((xkbdpy = XkbOpenDisplay(getenv("DISPLAY"), &evBase, &errBase, &major, &minor, &error)) == NULL) {
+               fprintf(stderr, "XkbOpenDisplay() failed\n");
+               return 1;
+       }
+
+       int i1;
+       if (!XkbQueryExtension(xkbdpy,&i1,&evBase,&errBase,&major,&minor)) {
+               fprintf(stderr, "XKB not supported by X-server\n");
+               return 1;
+       }
+       /* end of ugliness */
+
+       xcb_event_handlers_init(c, &evenths);
+       for(i = 2; i < 128; ++i)
+               xcb_event_set_handler(&evenths, i, handle_event, 0);
+
+       for(i = 0; i < 256; ++i)
+               xcb_event_set_error_handler(&evenths, i, (xcb_generic_error_handler_t)handle_event, 0);
+
+       /* Expose = an Application should redraw itself. That is, we have to redraw our
+        * contents (= top/bottom bar, titlebars for each window) */
+       xcb_event_set_expose_handler(&evenths, handle_expose_event, 0);
+
+       /* Key presses/releases are pretty obvious, I think */
+       xcb_event_set_key_press_handler(&evenths, handle_key_press, 0);
+       xcb_event_set_key_release_handler(&evenths, handle_key_release, 0);
+
+       /* Enter window = user moved his mouse over the window */
+       xcb_event_set_enter_notify_handler(&evenths, handle_enter_notify, 0);
+
+       /* Button press = user pushed a mouse button over one of our windows */
+       xcb_event_set_button_press_handler(&evenths, handle_button_press, 0);
+
+       xcb_event_set_unmap_notify_handler(&evenths, handle_unmap_notify_event, 0);
+
+       xcb_property_handlers_init(&prophs, &evenths);
+       xcb_event_set_map_notify_handler(&evenths, handle_map_notify_event, &prophs);
+
+       xcb_watch_wm_name(&prophs, 128, handle_windowname_change, 0);
+
+       root = xcb_aux_get_screen(c, screens)->root;
+       root_win = root;
+
+       uint32_t mask = XCB_CW_EVENT_MASK;
+       uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE };
+       xcb_change_window_attributes(c, root, mask, values);
+
+       #define BIND(key, modifier, cmd) { \
+               Binding *new = malloc(sizeof(Binding)); \
+               new->keycode = key; \
+               new->mods = modifier; \
+               new->command = cmd; \
+               TAILQ_INSERT_TAIL(&bindings, new, bindings); \
+       }
+
+       /* 38 = 'a' */
+       BIND(38, BIND_MODE_SWITCH, "foo");
+
+       BIND(30, 0, "exec /usr/pkg/bin/urxvt");
+
+       BIND(44, BIND_MOD_1, "h");
+       BIND(45, BIND_MOD_1, "j");
+       BIND(46, BIND_MOD_1, "k");
+       BIND(47, BIND_MOD_1, "l");
+
+       BIND(44, BIND_MOD_1 | BIND_CONTROL, "sh");
+       BIND(45, BIND_MOD_1 | BIND_CONTROL, "sj");
+       BIND(46, BIND_MOD_1 | BIND_CONTROL, "sk");
+       BIND(47, BIND_MOD_1 | BIND_CONTROL, "sl");
+
+       BIND(44, BIND_MOD_1 | BIND_SHIFT, "mh");
+       BIND(45, BIND_MOD_1 | BIND_SHIFT, "mj");
+       BIND(46, BIND_MOD_1 | BIND_SHIFT, "mk");
+       BIND(47, BIND_MOD_1 | BIND_SHIFT, "ml");
+
+       BIND(10, BIND_MOD_1 , "1");
+       BIND(11, BIND_MOD_1 , "2");
+       BIND(12, BIND_MOD_1 , "3");
+       BIND(13, BIND_MOD_1 , "4");
+       BIND(14, BIND_MOD_1 , "5");
+       BIND(15, BIND_MOD_1 , "6");
+       BIND(16, BIND_MOD_1 , "7");
+       BIND(17, BIND_MOD_1 , "8");
+       BIND(18, BIND_MOD_1 , "9");
+       BIND(19, BIND_MOD_1 , "0");
+
+       Binding *bind;
+       TAILQ_FOREACH(bind, &bindings, bindings) {
+               printf("Grabbing %d\n", bind->keycode);
+               if (bind->mods & BIND_MODE_SWITCH)
+                       xcb_grab_key(c, 0, root, 0, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC);
+               else xcb_grab_key(c, 0, root, bind->mods, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
+       }
+
+       /* check for Xinerama */
+       printf("Checking for Xinerama...\n");
+       initialize_xinerama(c);
+
+       start_application(TERMINAL, NULL);
+
+       xcb_flush(c);
+
+       manage_existing_windows(c, &prophs, root);
+
+       xcb_event_wait_for_event_loop(&evenths);
+
+       /* not reached */
+       return 0;
+}
diff --git a/src/table.c b/src/table.c
new file mode 100644 (file)
index 0000000..33d1b4f
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * This file provides functions for easier accessing of _the_ table
+ *
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include "data.h"
+#include "table.h"
+
+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
+ *
+ */
+void init_table() {
+       int i;
+       memset(workspaces, 0, sizeof(workspaces));
+
+       for (i = 0; i < 10; i++) {
+               expand_table_cols(&(workspaces[i]));
+               expand_table_rows(&(workspaces[i]));
+       }
+}
+
+static void new_container(Container **container) {
+       Container *new;
+       new = *container = calloc(sizeof(Container), 1);
+       CIRCLEQ_INIT(&(new->clients));
+       new->colspan = 1;
+       new->rowspan = 1;
+}
+
+/*
+ * Add one row to the table
+ *
+ */
+void expand_table_rows(Workspace *workspace) {
+       int c;
+
+       workspace->rows++;
+
+       for (c = 0; c < workspace->cols; c++) {
+               workspace->table[c] = realloc(workspace->table[c], sizeof(Container*) * workspace->rows);
+               new_container(&(workspace->table[c][workspace->rows-1]));
+       }
+}
+
+/*
+ * Add one column to the table
+ *
+ */
+void expand_table_cols(Workspace *workspace) {
+       int c;
+
+       workspace->cols++;
+
+       workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols);
+       workspace->table[workspace->cols-1] = calloc(sizeof(Container*) * workspace->rows, 1);
+       for (c = 0; c < workspace->rows; c++)
+               new_container(&(workspace->table[workspace->cols-1][c]));
+}
+
+/*
+ * Performs simple bounds checking for the given column/row
+ *
+ */
+bool cell_exists(int col, int row) {
+       return (col >= 0 && col < c_ws->rows) &&
+               (row >= 0 && row < c_ws->cols);
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644 (file)
index 0000000..1263cdc
--- /dev/null
@@ -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/src/xcb.c b/src/xcb.c
new file mode 100644 (file)
index 0000000..b445437
--- /dev/null
+++ b/src/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/table.c b/table.c
deleted file mode 100644 (file)
index 33d1b4f..0000000
--- a/table.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * This file provides functions for easier accessing of _the_ table
- *
- */
-#include <stdio.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <assert.h>
-
-#include "data.h"
-#include "table.h"
-
-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
- *
- */
-void init_table() {
-       int i;
-       memset(workspaces, 0, sizeof(workspaces));
-
-       for (i = 0; i < 10; i++) {
-               expand_table_cols(&(workspaces[i]));
-               expand_table_rows(&(workspaces[i]));
-       }
-}
-
-static void new_container(Container **container) {
-       Container *new;
-       new = *container = calloc(sizeof(Container), 1);
-       CIRCLEQ_INIT(&(new->clients));
-       new->colspan = 1;
-       new->rowspan = 1;
-}
-
-/*
- * Add one row to the table
- *
- */
-void expand_table_rows(Workspace *workspace) {
-       int c;
-
-       workspace->rows++;
-
-       for (c = 0; c < workspace->cols; c++) {
-               workspace->table[c] = realloc(workspace->table[c], sizeof(Container*) * workspace->rows);
-               new_container(&(workspace->table[c][workspace->rows-1]));
-       }
-}
-
-/*
- * Add one column to the table
- *
- */
-void expand_table_cols(Workspace *workspace) {
-       int c;
-
-       workspace->cols++;
-
-       workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols);
-       workspace->table[workspace->cols-1] = calloc(sizeof(Container*) * workspace->rows, 1);
-       for (c = 0; c < workspace->rows; c++)
-               new_container(&(workspace->table[workspace->cols-1][c]));
-}
-
-/*
- * Performs simple bounds checking for the given column/row
- *
- */
-bool cell_exists(int col, int row) {
-       return (col >= 0 && col < c_ws->rows) &&
-               (row >= 0 && row < c_ws->cols);
-}
diff --git a/table.h b/table.h
deleted file mode 100644 (file)
index 1d6ca8f..0000000
--- a/table.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#include <stdbool.h>
-#include "data.h"
-
-#ifndef _TABLE_H
-#define _TABLE_H
-
-#define CUR_TABLE (c_ws->table)
-#define CUR_CELL (CUR_TABLE[current_col][current_row])
-
-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);
-void expand_table_cols(Workspace *workspace);
-bool cell_exists(int col, int row);
-
-#endif
diff --git a/util.c b/util.c
deleted file mode 100644 (file)
index 1263cdc..0000000
--- a/util.c
+++ /dev/null
@@ -1,38 +0,0 @@
-#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
deleted file mode 100644 (file)
index 9eb2a44..0000000
--- a/util.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#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
deleted file mode 100644 (file)
index b445437..0000000
--- a/xcb.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#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
deleted file mode 100644 (file)
index c8224ef..0000000
--- a/xcb.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _XCB_H
-#define _XCB_H
-
-uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex);
-
-#endif