]> git.sur5r.net Git - i3/i3/commitdiff
Focus changes (up/down) implemented
authorMichael Stapelberg <michael+git@stapelberg.de>
Sun, 8 Feb 2009 01:39:56 +0000 (02:39 +0100)
committerMichael Stapelberg <michael+git@stapelberg.de>
Sun, 8 Feb 2009 01:39:56 +0000 (02:39 +0100)
Makefile
data.h
mainx.c

index 4d8e000618a2d40482ab7337cbb821af6f43e0ca..2fdcab5886088e77096b9cc40c11799e5122aa77 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,2 +1,2 @@
 all:
-       gcc -Wall -g -I/usr/include/xcb -o mainx mainx.c -lxcb-wm
+       gcc -Wall -gdwarf-2 -g3 -I/usr/include/xcb -o mainx mainx.c -lxcb-wm
diff --git a/data.h b/data.h
index 5c3fea1533c013b1197fc2440957792579ec8ac1..b80718021c65cbfca0331fc23b74d56e52855e0d 100644 (file)
--- a/data.h
+++ b/data.h
@@ -4,14 +4,22 @@
  */
 #include "queue.h"
 
+/* Forward definitions */
+typedef struct Cell Cell;
+typedef struct Font Font;
+typedef struct Container Container;
+typedef struct Client Client;
+
+typedef enum { D_LEFT, D_RIGHT, D_UP, D_DOWN } direction_t;
+
 /*
  * Defines a position in the table
  *
  */
-typedef struct Cell {
+struct Cell {
        int row;
        int column;
-} Cell;
+};
 
 /*
  * We need to save the height of a font because it is required for each drawing of
@@ -19,20 +27,23 @@ typedef struct Cell {
  * Font-entry will be filled for later use.
  *
  */
-typedef struct Font {
+struct Font {
        char *name;
        int height;
-} Font;
+};
 
 /*
  * A client is X11-speak for a window.
  *
  */
-typedef struct Client {
+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;
+
 
        /* XCB contexts */
        xcb_gcontext_t titlegc;
@@ -40,14 +51,17 @@ typedef struct Client {
        xcb_window_t child;
 
        /* The following entry provides the necessary list pointers to use Client with LIST_* macros */
-       LIST_ENTRY(Client) clients;
-} Client;
+       CIRCLEQ_ENTRY(Client) clients;
+};
 
 /*
  * A container is either in default or stacking mode. It sits inside the table.
  *
  */
-typedef struct Container {
+struct Container {
+       /* Those are speaking for themselves: */
+       Client *currently_focused;
+
        /* Position of the container inside our table */
        int row;
        int col;
@@ -56,5 +70,5 @@ typedef struct Container {
        int height;
        /* Ensure MODE_DEFAULT maps to 0 because we use calloc for initialization later */
        enum { MODE_DEFAULT = 0, MODE_STACK = 1 } mode;
-       LIST_HEAD(client_head, Client) clients;
-} Container;
+       CIRCLEQ_HEAD(client_head, Client) clients;
+};
diff --git a/mainx.c b/mainx.c
index 436ba70d7181923eb4558aec73aec554655f8f04..20ed2f5252a63769d94da9a81f9e750586b93122 100644 (file)
--- a/mainx.c
+++ b/mainx.c
@@ -6,6 +6,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdbool.h>
+#include <assert.h>
 
 #include <xcb/xcb.h>
 
@@ -30,9 +31,6 @@ table_t *byChild = 0;
 table_t *byParent = 0;
 xcb_window_t root_win;
 
-/* We have a list of Clients, called all_clients */
-LIST_HEAD(all_clients_head, Client) all_clients;
-
 /* _the_ table. Stores all clients. */
 Container *table[10][10];
 
@@ -348,8 +346,8 @@ void decorate_window(xcb_connection_t *conn, Client *client) {
 
 void render_container(xcb_connection_t *connection, Container *container) {
        Client *client;
-       int values[4];
-       int mask =      XCB_CONFIG_WINDOW_X |
+       uint32_t values[4];
+       uint32_t mask = XCB_CONFIG_WINDOW_X |
                        XCB_CONFIG_WINDOW_Y |
                        XCB_CONFIG_WINDOW_WIDTH |
                        XCB_CONFIG_WINDOW_HEIGHT;
@@ -357,12 +355,12 @@ void render_container(xcb_connection_t *connection, Container *container) {
 
        if (container->mode == MODE_DEFAULT) {
                int num_clients = 0;
-               LIST_FOREACH(client, &(container->clients), clients)
+               CIRCLEQ_FOREACH(client, &(container->clients), clients)
                        num_clients++;
                printf("got %d clients in this default container.\n", num_clients);
 
                int current_client = 0;
-               LIST_FOREACH(client, &(container->clients), clients) {
+               CIRCLEQ_FOREACH(client, &(container->clients), clients) {
                        /* 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.
@@ -430,7 +428,6 @@ void render_layout(xcb_connection_t *conn) {
                                table[cols][rows]->width = width / num_cols;
                                table[cols][rows]->height = height / num_rows;
 
-
                                /* Render it */
                                render_container(conn, table[cols][rows]);
                        }
@@ -448,18 +445,18 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
        Client *new = table_get(byChild, child);
        if (new == NULL) {
                printf("oh, it's new\n");
-               new = malloc(sizeof(Client));
+               new = calloc(sizeof(Client), 1);
        }
-       xcb_drawable_t drawable;
        uint32_t mask = 0;
        uint32_t values[3];
        xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
 
-       /* Insert into the list of all clients */
-       LIST_INSERT_HEAD(&all_clients, new, clients);
-
        /* Insert into the currently active container */
-       LIST_INSERT_HEAD(&(table[current_col][current_row]->clients), new, clients);
+       CIRCLEQ_INSERT_TAIL(&(table[current_col][current_row]->clients), new, clients);
+
+       printf("currently_focused = %p\n", new);
+       table[current_col][current_row]->currently_focused = new;
+       new->container = table[current_col][current_row];
 
        new->window = xcb_generate_id(conn);
        new->child = child;
@@ -520,35 +517,52 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
 
        /* TODO: At the moment, new windows just get focus */
        xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, new->window, XCB_CURRENT_TIME);
-#if 0
-
-       xcb_intern_atom_cookie_t atom_cookie = xcb_intern_atom(conn, 0, strlen("_NET_ACTIVE_WINDOW"), "_NET_ACTIVE_WINDOW");
-       xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, atom_cookie, NULL);
-       int atom = -1;
-       if (reply) {
-                  atom = reply->atom;
-                  printf("setting atom %d\n", atom);
-                     free(reply);
-       }
-       printf("atom = %d\n", atom);
-
-
-               xcb_change_property(conn,
-                               XCB_PROP_MODE_REPLACE,
-                       root,
-                       atom,
-                       WINDOW,
-                       32, /* format, see http://standards.freedesktop.org/wm-spec/1.3/ar01s03.html */
-                       1, /* source indication? FIXME */
-                       &myc.window);
-#endif
 
        render_layout(conn);
 
        xcb_flush(conn);
 }
 
+static bool focus_window_in_container(xcb_connection_t *connection, Container *container,
+               direction_t direction) {
+       /* If this container is empty, we’re done */
+       if (container->currently_focused == NULL)
+               return false;
+
+       Client *candidad;
+       if (direction == D_UP)
+               candidad = CIRCLEQ_PREV(container->currently_focused, clients);
+       else if (direction == D_DOWN)
+               candidad = CIRCLEQ_NEXT(container->currently_focused, clients);
 
+       /* If we don’t have anything to select, we’re done */
+       if (candidad == CIRCLEQ_END(&(container->clients)))
+               return false;
+
+       /* Set focus if we could successfully move */
+       container->currently_focused = candidad;
+       xcb_set_input_focus(connection, XCB_INPUT_FOCUS_NONE, candidad->child, XCB_CURRENT_TIME);
+       xcb_flush(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 = table[current_col][current_row];
+
+               /* 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 {
+               printf("direction unhandled\n");
+       }
+}
 
 
 int format_event(xcb_generic_event_t *e)
@@ -597,9 +611,7 @@ static int handleEvent(void *ignored, xcb_connection_t *c, xcb_generic_event_t *
  * functions to get one more modifier while not losing AltGr :-)
  *
  */
-static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_generic_event_t *e) {
-       xcb_key_press_event_t *event = (xcb_key_press_event_t*)e;
-
+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) */
@@ -608,8 +620,17 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_generic_e
        printf("gots press %d\n", event->detail);
        printf("i'm in state %d\n", event->state);
 
-       if (event->detail == 28) {
-               /* 't' */
+       /* 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' */
                pid_t pid;
                if ((pid = vfork()) == 0) {
                        /* Child */
@@ -621,14 +642,25 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_generic_e
                        argv[0] = "/usr/bin/xterm";
                        argv[1] = NULL;
                        execve("/usr/bin/xterm", argv, env);
+                       /* not reached */
                }
-       } else if (event->detail == 38) {
-               //xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, myc.window, XCB_CURRENT_TIME);
+               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;
        }
 
-       //decorate_window(c, &myc);
+       /* TODO: ctrl -> focus_container(conn, direction) */
+       focus_window(conn, direction);
+       /* TODO: shift -> move_current_window(conn, direction) */
+       /* TODO: shift + ctrl -> move_current_container(conn, direction) */
 
-        return format_event(e);
+        return 1;
 }
 
 /*
@@ -648,6 +680,9 @@ static int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_
                return 1;
        }
 
+       /* Update container */
+       client->container->currently_focused = client;
+
        /* Set focus to the entered window, and flush xcb buffer immediately */
        xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, client->child, XCB_CURRENT_TIME);
        xcb_flush(conn);
@@ -655,10 +690,6 @@ static int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_
        return 1;
 }
 
-static void redrawWindow(xcb_connection_t *c, Client *client) {
-       decorate_window(c, client);
-}
-
 int handle_map_notify_event(void *prophs, xcb_connection_t *c, xcb_map_notify_event_t *e)
 {
        window_attributes_t wa = { TAG_VALUE };
@@ -689,10 +720,10 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *c, xcb_unmap_notify_
        for (rows = 0; rows < 10; rows++)
                for (cols = 0; cols < 10; cols++)
                        if (table[cols][rows] != NULL)
-                               LIST_FOREACH(con_client, &(table[cols][rows]->clients), clients)
+                               CIRCLEQ_FOREACH(con_client, &(table[cols][rows]->clients), clients)
                                        if (con_client == client) {
                                                printf("removing from container\n");
-                                               LIST_REMOVE(con_client, clients);
+                                               CIRCLEQ_REMOVE(&(table[cols][rows]->clients), con_client, clients);
                                                break;
                                        }
 
@@ -719,7 +750,7 @@ printf("exposeevent\n");
        Client *client = table_get(byParent, e->window);
        if(!client || e->count != 0)
                return 1;
-       redrawWindow(c, client);
+       decorate_window(c, client);
        return 1;
 }
 void manage_existing_windows(xcb_connection_t *c, xcb_property_handlers_t *prophs, xcb_window_t root)
@@ -753,7 +784,6 @@ void manage_existing_windows(xcb_connection_t *c, xcb_property_handlers_t *proph
 }
 
 int main() {
-       LIST_INIT(&all_clients);
        int i, j;
        for (i = 0; i < 10; i++)
                for (j = 0; j < 10; j++)
@@ -765,6 +795,7 @@ int main() {
         *
         */
        table[0][0] = calloc(sizeof(Container), 1);
+       CIRCLEQ_INIT(&(table[0][0]->clients));
 
        xcb_connection_t *c;
        xcb_event_handlers_t evenths;
@@ -802,16 +833,17 @@ myfont.height = reply->font_ascent + reply->font_descent;
        for(i = 2; i < 128; ++i)
                xcb_event_set_handler(&evenths, i, handleEvent, 0);
 
-       /* Key presses are pretty obvious, I think */
-       xcb_event_set_handler(&evenths, XCB_KEY_PRESS, handle_key_press, 0);
 
        for(i = 0; i < 256; ++i)
                xcb_event_set_error_handler(&evenths, i, (xcb_generic_error_handler_t) handleEvent, 0);
 
        /* Expose = an Application should redraw itself. That is, we have to redraw our
-        * contents (= Bars) */
+        * contents (= top/bottom bar, titlebars for each window) */
        xcb_event_set_expose_handler(&evenths, handleExposeEvent, 0);
 
+       /* Key presses are pretty obvious, I think */
+       xcb_event_set_key_press_handler(&evenths, handle_key_press, 0);
+
        /* Enter window = user moved his mouse over the window */
        xcb_event_set_enter_notify_handler(&evenths, handle_enter_notify, 0);
 
@@ -830,27 +862,14 @@ myfont.height = reply->font_ascent + reply->font_descent;
 
        /* 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, 28, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
-
-       xcb_grab_key(c, 0, root, 0, 46, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
-#if 0
-   if (xcb_grab_pointer_reply(c, xcb_grab_pointer_unchecked(c, 0, root,
-                                       XCB_EVENT_MASK_BUTTON_PRESS   |
-                                       XCB_EVENT_MASK_BUTTON_RELEASE |
-                                       XCB_EVENT_MASK_ENTER_WINDOW   |
-                                       XCB_EVENT_MASK_LEAVE_WINDOW   |
-                                       XCB_EVENT_MASK_POINTER_MOTION,
-                                       XCB_GRAB_MODE_ASYNC,
-                                       XCB_GRAB_MODE_ASYNC,
-                                       XCB_NONE, XCB_NONE,
-                                       XCB_CURRENT_TIME), NULL))
-printf("could not grab pointer\n");
-#endif
-
 
+       xcb_grab_key(c, 0, root, 0, 30, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
+       xcb_grab_key(c, 0, root, 0, 57, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
+       xcb_grab_key(c, 0, root, 0, 28, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
+       xcb_grab_key(c, 0, root, 0, 27, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
+       xcb_grab_key(c, 0, root, 0, 40, 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);
-               /* 't' */
                pid_t pid;
                if ((pid = vfork()) == 0) {
                        /* Child */