]> git.sur5r.net Git - i3/i3/commitdiff
Implement keybindings, adjust CMDMODE grammar, update DEPENDS
authorMichael Stapelberg <michael+git@stapelberg.de>
Tue, 10 Feb 2009 19:49:47 +0000 (20:49 +0100)
committerMichael Stapelberg <michael+git@stapelberg.de>
Tue, 10 Feb 2009 19:49:47 +0000 (20:49 +0100)
CMDMODE
DEPENDS [new file with mode: 0644]
REQUIREMENTS [deleted file]
data.h
mainx.c

diff --git a/CMDMODE b/CMDMODE
index d7c2462eec40000e8dfac00abe9450a80f43922f..c7881e1ffb9ebe99ac3364e5f20bbc53db411ce5 100644 (file)
--- a/CMDMODE
+++ b/CMDMODE
@@ -13,7 +13,11 @@ cmd := [ <times> ] [ <move> | <snap> ] <where>
 
 oder
 
-with := { [ <times> ] <where> }+ <enter> <cmd>
+with := <w> { [ <times> ] <where> }+ <space> <cmd>
+
+oder
+
+exec := exec <path>
 
 an jeder Stelle kann mit escape abgebrochen werden
 
@@ -29,4 +33,4 @@ Fenster nach rechts verschieben:
 ml
 
 Fenster und Fenster untendrunter nach rechts verschieben:
-wk<enter>ml
+wk ml
diff --git a/DEPENDS b/DEPENDS
new file mode 100644 (file)
index 0000000..21e6877
--- /dev/null
+++ b/DEPENDS
@@ -0,0 +1,13 @@
+You need the following libraries. The version given is to be understand as the minimum
+version. However, if any of these libraries changes the API, i3 may not compile anymore.
+In that case, please try using the versions mentioned below until a fix is provided.
+
+ * xcb-proto-1.3 (2008-12-10)
+ * libxcb-1.1.93 (2008-12-11)
+ * xcb-util-0.3.3 (2009-01-31)
+ * Xlib, the one that comes with your X-Server
+
+Get the libraries from:
+http://xcb.freedesktop.org/dist/xcb-proto-1.3.tar.bz2
+http://xcb.freedesktop.org/dist/libxcb-1.1.93.tar.bz2
+http://xcb.freedesktop.org/dist/xcb-util-0.3.3.tar.bz2
diff --git a/REQUIREMENTS b/REQUIREMENTS
deleted file mode 100644 (file)
index be3ecf7..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-We’ve developed with:
- * libxcb-1.1.93 (2008-12-11)
- * xcb-util-0.3.3 (2009-01-31)
diff --git a/data.h b/data.h
index 9fa7b0632a9e3114adfd1445943da44588710e40..03896109de8ec8313f5cf3e04e4bb6bb6a0fcb1d 100644 (file)
--- a/data.h
+++ b/data.h
@@ -13,9 +13,23 @@ typedef struct Cell Cell;
 typedef struct Font i3Font;
 typedef struct Container Container;
 typedef struct Client Client;
+typedef struct Binding Binding;
 
 /* 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 table_dimensions_t {
        int x;
        int y;
@@ -30,6 +44,17 @@ struct Cell {
        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
diff --git a/mainx.c b/mainx.c
index dfe1abdf41dcd7d5f41b107aa36e4e965eb24a38..af1d5e9f67be8b8b871e9110bf7574ca0a127e2b 100644 (file)
--- a/mainx.c
+++ b/mainx.c
 
 #define TERMINAL "/usr/pkg/bin/urxvt"
 
-i3Font *myfont;
 Display *xkbdpy;
 
+TAILQ_HEAD(bindings_head, Binding) bindings;
+
 static const int TOP = 20;
 static const int LEFT = 5;
 static const int BOTTOM = 5;
@@ -797,84 +798,142 @@ static void start_application(char *path, char *args) {
        }
 }
 
+/*
+ * Due to bindings like Mode_switch + <a>, we need to bind some keys in XCB_GRAB_MODE_SYNC.
+ * Therefore, we just replay all key presses.
+ *
+ */
+static int handle_key_release(void *ignored, xcb_connection_t *conn, xcb_key_release_event_t *event) {
+       printf("got key release, just passing\n");
+       xcb_allow_events(conn, ReplayKeyboard, event->time);
+       xcb_flush(conn);
+       return 1;
+}
+
+/*
+ * Parses a command, see file CMDMODE for more information
+ *
+ */
+static void parse_command(xcb_connection_t *conn, const char *command) {
+       printf("--- parsing command \"%s\" ---\n", command);
+       /* Hmm, just to be sure */
+       if (command[0] == '\0')
+               return;
+
+       /* Is it an <exec>? */
+       if (strncmp(command, "exec ", strlen("exec ")) == 0) {
+               printf("starting \"%s\"\n", command + strlen("exec "));
+               start_application(command+strlen("exec "), NULL);
+               return;
+       }
+
+       /* Is it a <with>? */
+       if (command[0] == 'w') {
+               /* TODO: implement */
+               printf("not yet implemented.\n");
+               return;
+       }
+
+       /* It's a normal <cmd> */
+       int times;
+       char *rest = NULL;
+       enum { ACTION_FOCUS, ACTION_MOVE, ACTION_SNAP } action = ACTION_FOCUS;
+       direction_t direction;
+       times = strtol(command, &rest, 10);
+       if (rest == NULL) {
+               printf("Invalid command: Consists only of a movement\n");
+               return;
+       }
+       if (*rest == 'm' || *rest == 's') {
+               action = (*rest == 'm' ? ACTION_MOVE : ACTION_SNAP);
+               rest++;
+       }
+
+       /* Now perform action to <where> */
+       while (*rest != '\0') {
+               /* TODO: tags */
+               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)
+                       /* TODO: implement */
+                       printf("snap not yet implemented\n");
+
+               rest++;
+
+       }
+
+       printf("--- done ---\n");
+}
+
 /*
  * There was a key press. We lookup the key symbol and see if there are any bindings
  * on that. This allows to do things like binding special characters (think of ä) to
  * functions to get one more modifier while not losing AltGr :-)
+ * TODO: this description needs to be more understandable
  *
  */
 static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_t *event) {
-       /* FIXME: We need to translate the keypress + state into a string (like, ä)
-          because they do not generate keysyms (use xev and see for yourself) */
-
-       printf("oh yay!\n");
-       printf("gots press %d\n", event->detail);
+       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) {
-               if (state.group+1 == 2)
-                       event->state |= 0x2;
+       if (XkbGetState(xkbdpy, XkbUseCoreKbd, &state) == Success && (state.group+1) == 2)
+               event->state |= 0x2;
+
+       printf("state %d\n", event->state);
+
+       /* Find the binding */
+       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;
+               }
        }
-       printf("i'm in state %d\n", event->state);
-
-
-       xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(conn);
-
-       xcb_keysym_t k0 = xcb_key_symbols_get_keysym(keysyms, event->detail, event->state);
-       if (k0 == XCB_NONE)
-               printf("couldn't get k0\n");
 
-       printf("gots keysym %d and \n", k0);
-
-
-       /* 30 = u
-        * 57 = n
-        * 27 = r
-        * 28 = t
-        * 40 = d
-        *
-        * …uhm, I should probably say that I’ve remapped my keys in hardware :)
-        */
-       direction_t direction;
-       if (event->detail == 30) {
-               /* 'u' */
-               start_application(TERMINAL, NULL);
+       if (best_match == TAILQ_END(&bindings)) {
+               printf("This key was not bound by us?! (most likely a bug)\n");
+               return 1; /* TODO: return 0? what do the codes mean? */
+       }
 
-               return 1;
-       } else if (event->detail == 57) {
-               direction = D_LEFT;
-       } else if (event->detail == 27) {
-               direction = D_DOWN;
-       } else if (event->detail == 28) {
-               direction = D_UP;
-       } else if (event->detail == 40) {
-               direction = D_RIGHT;
-       } else if (event->detail == 25) {
-               Container *con = CUR_CELL;
-               if (con->colspan == 1)
-                       con->colspan++;
-               else con->colspan--;
-               render_layout(conn);
+       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;
-       } else {
-               printf("don't want this.\n");
-               return 1;
        }
 
-       /* TODO: ctrl -> focus_container(conn, direction) */
-       /* FIXME: actually wrong but i'm too lazy to grab my keys all the time */
-       if (event->state & XCB_MOD_MASK_CONTROL) {
-               move_current_window(conn, direction);
-       } else if (event->state & XCB_MOD_MASK_1)
-               focus_window(conn, direction);
-       /* TODO: shift -> move_current_window(conn, direction) */
-       /* TODO: shift + ctrl -> move_current_container(conn, direction) */
+       /* If this was an actively grabbed key, and we did not handle it, we need to pass it */
+       if (best_match->mods & BIND_MODE_SWITCH) {
+               printf("passing...\n");
+               xcb_allow_events(conn, ReplayKeyboard, event->time);
+               xcb_flush(conn);
+               return 1;
+       }
 
-        return 1;
+       parse_command(conn, best_match->command);
+       return 1;
 }
 
 /*
@@ -1036,10 +1095,13 @@ int main(int argc, char *argv[], char *env[]) {
        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;
@@ -1057,9 +1119,7 @@ int main(int argc, char *argv[], char *env[]) {
                fprintf(stderr, "XKB not supported by X-server\n");
                return 1;
        }
-
-       /* Font loading */
-       myfont = load_font(c, pattern);
+       /* end of ugliness */
 
        xcb_event_handlers_init(c, &evenths);
        for(i = 2; i < 128; ++i)
@@ -1072,8 +1132,9 @@ int main(int argc, char *argv[], char *env[]) {
         * contents (= top/bottom bar, titlebars for each window) */
        xcb_event_set_expose_handler(&evenths, handleExposeEvent, 0);
 
-       /* Key presses are pretty obvious, I think */
+       /* 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);
@@ -1090,27 +1151,37 @@ int main(int argc, char *argv[], char *env[]) {
        uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE };
        xcb_change_window_attributes(c, root, mask, values);
 
-       /* Grab 'a' */
-       //xcb_grab_key(c, 0, root, 0, 38, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
-
-       xcb_grab_key(c, 0, root, 0, 30, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
-       xcb_grab_key(c, 0, root, 0, 38, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
+       #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");
 
-       xcb_grab_key(c, 0, root, XCB_MOD_MASK_1, 57, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
-       xcb_grab_key(c, 0, root, XCB_MOD_MASK_1, 28, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
-       xcb_grab_key(c, 0, root, XCB_MOD_MASK_1, 27, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
-       xcb_grab_key(c, 0, root, XCB_MOD_MASK_1, 40, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
+       BIND(30, 0, "exec /usr/pkg/bin/urxvt");
 
-       xcb_grab_key(c, 0, root, XCB_MOD_MASK_CONTROL, 57, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
-       xcb_grab_key(c, 0, root, XCB_MOD_MASK_CONTROL, 28, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
-       xcb_grab_key(c, 0, root, XCB_MOD_MASK_CONTROL, 27, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
-       xcb_grab_key(c, 0, root, XCB_MOD_MASK_CONTROL, 40, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
-       xcb_grab_key(c, 0, root, XCB_MOD_MASK_CONTROL, 25, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
+       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, "mh");
+       BIND(45, BIND_MOD_1 | BIND_CONTROL, "mj");
+       BIND(46, BIND_MOD_1 | BIND_CONTROL, "mk");
+       BIND(47, BIND_MOD_1 | BIND_CONTROL, "ml");
 
+       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);
+       }
 
-       //xcb_grab_key(c, 0, root, XCB_BUTTON_MASK_ANY, 40, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
        start_application(TERMINAL, NULL);
 
        xcb_flush(c);