]> git.sur5r.net Git - i3/i3/commitdiff
Cleanups, documentation
authorMichael Stapelberg <michael+git@stapelberg.de>
Tue, 24 Feb 2009 00:24:28 +0000 (01:24 +0100)
committerMichael Stapelberg <michael+git@stapelberg.de>
Tue, 24 Feb 2009 00:24:28 +0000 (01:24 +0100)
include/i3.h
src/handlers.c
src/layout.c
src/mainx.c

index 2861e01c311122796ccc7dd40f6ada03591af0a6..c21d24a8140a7871dcdd60181309b165561ab773 100644 (file)
 #ifndef _I3_H
 #define _I3_H
 
+#define NUM_ATOMS 9
+
 extern Display *xkbdpy;
 extern TAILQ_HEAD(bindings_head, Binding) bindings;
 extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
 extern xcb_event_handlers_t evenths;
 extern char *pattern;
 extern int num_screens;
-extern xcb_atom_t atoms[9];
+extern xcb_atom_t atoms[NUM_ATOMS];
 
 #endif
index f31e23bd46a5839ccb6571f6e732abfa8af1bf8f..23d3172a70664ecc23cbcfda4de12f53e14d3d17 100644 (file)
@@ -292,6 +292,10 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
         return 1;
 }
 
+/*
+ * A new window appeared on the screen (=was mapped), so let’s manage it.
+ *
+ */
 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;
index 0530388482502defc502d6cd8a4a7f0043505df8..87d2f2882e360f066bad0882c62b7a2d7f983934 100644 (file)
@@ -154,7 +154,7 @@ static void reposition_client(xcb_connection_t *connection, Client *client) {
 static void resize_client(xcb_connection_t *connection, Client *client) {
         i3Font *font = load_font(connection, pattern);
 
-        printf("resizing client \"%s\" to %d x %d\n", client->name, client->rect.width, client->rect.height);
+        printf("resizing client to %d x %d\n", client->rect.width, client->rect.height);
         xcb_configure_window(connection, client->frame,
                         XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
                         &(client->rect.width));
index e49362a0bcd42334e3025346a77a2dde0db131db..96d948f4e6898beb7c7805c792bd415979e2f3d1 100644 (file)
 #include "util.h"
 #include "xcb.h"
 #include "xinerama.h"
+#include "i3.h"
 
 #define TERMINAL "/usr/pkg/bin/urxvt"
 
+/* This is our connection to X11 for use with XKB */
 Display *xkbdpy;
 
-TAILQ_HEAD(bindings_head, Binding) bindings = TAILQ_HEAD_INITIALIZER(bindings);
-SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins = SLIST_HEAD_INITIALIZER(stack_wins);
-xcb_event_handlers_t evenths;
+/* The list of key bindings */
+struct bindings_head bindings = TAILQ_HEAD_INITIALIZER(bindings);
+
+/* This is a list of Stack_Windows, global, for easier/faster access on expose events */
+struct stack_wins_head stack_wins = SLIST_HEAD_INITIALIZER(stack_wins);
 
-xcb_window_t root_win;
-xcb_atom_t atoms[9];
+/* The event handlers need to be global because they are accessed by our custom event handler
+   in handle_button_press(), needed for graphical resizing */
+xcb_event_handlers_t evenths;
+xcb_atom_t atoms[NUM_ATOMS];
 
 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?
+ * Do some sanity checks and then reparent the window.
  *
  */
-void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *c, xcb_window_t window, window_attributes_t wa)
-{
+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);
+
+        if (wa.tag == TAG_COOKIE) {
+                /* Check if the window is mapped (it could be not mapped when intializing and
+                   calling manage_window() for every window) */
+                if ((attr = xcb_get_window_attributes_reply(c, wa.u.cookie, 0)) == NULL)
                         return;
-                }
+
+                if (attr->map_state != XCB_MAP_STATE_VIEWABLE)
+                        goto out;
+
                 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;
-        }
+
+        /* Check if the window is already managed */
+        if (!wa.u.override_redirect && table_get(byChild, window))
+                goto out;
+
+        /* Don’t manage clients with the override_redirect flag */
+        if (wa.u.override_redirect)
+                goto out;
+
+        /* Get the initial geometry (position, size, …) */
         geomc = xcb_get_geometry(c, d);
-        if(!attr)
-        {
+        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);
+        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);
+out:
+        free(attr);
+        return;
 }
 
 /*
@@ -124,7 +127,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
 
         xcb_get_property_cookie_t wm_type_cookie, strut_cookie;
 
-        /* Place requests for propertys ASAP */
+        /* Place requests for properties ASAP */
         wm_type_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_WINDOW_TYPE], UINT32_MAX);
         strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
 
@@ -133,10 +136,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                 /* TODO: When does this happen for existing clients? Is that a bug? */
                 printf("oh, it's new\n");
                 new = calloc(sizeof(Client), 1);
-                /* We initialize x and y with the invalid coordinates -1 so that they will
-                   get updated at the next render_layout() at any case */
-                new->rect.x = -1;
-                new->rect.y = -1;
+                new->force_reconfigure = true;
         }
         uint32_t mask = 0;
         uint32_t values[3];
@@ -243,33 +243,35 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         render_layout(conn);
 }
 
+/*
+ * Go through all existing windows (if the window manager is restarted) and manage them
+ *
+ */
 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;
+        xcb_query_tree_reply_t *reply;
         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);
+        /* Get the tree of windows whose parent is the root window (= all) */
+        if ((reply = xcb_query_tree_reply(c, xcb_query_tree(c, root), 0)) == NULL)
                 return;
-        }
-        children = xcb_query_tree_children(rep);
+
+        len = xcb_query_tree_children_length(reply);
+        cookies = smalloc(len * sizeof(*cookies));
+
+        /* Request the window attributes for every window */
+        children = xcb_query_tree_children(reply);
         for(i = 0; i < len; ++i)
                 cookies[i] = xcb_get_window_attributes(c, children[i]);
-        for(i = 0; i < len; ++i)
-        {
+
+        /* Call manage_window with the attributes for every window */
+        for(i = 0; i < len; ++i) {
                 window_attributes_t wa = { TAG_COOKIE, { cookies[i] } };
                 manage_window(prophs, c, children[i], wa);
         }
-        free(rep);
+
+        free(reply);
 }
 
 int main(int argc, char *argv[], char *env[]) {
@@ -277,6 +279,7 @@ int main(int argc, char *argv[], char *env[]) {
         xcb_connection_t *c;
         xcb_property_handlers_t prophs;
         xcb_window_t root;
+        xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS];
 
         /* Initialize the table data structures for each workspace */
         init_table();
@@ -289,6 +292,20 @@ int main(int argc, char *argv[], char *env[]) {
 
         c = xcb_connect(NULL, &screens);
 
+        /* Place requests for the atoms we need as soon as possible */
+        #define REQUEST_ATOM(name) atom_cookies[name] = xcb_intern_atom(c, 0, strlen(#name), #name);
+
+        REQUEST_ATOM(_NET_SUPPORTED);
+        REQUEST_ATOM(_NET_WM_STATE_FULLSCREEN);
+        REQUEST_ATOM(_NET_SUPPORTING_WM_CHECK);
+        REQUEST_ATOM(_NET_WM_NAME);
+        REQUEST_ATOM(_NET_WM_STATE);
+        REQUEST_ATOM(_NET_WM_WINDOW_TYPE);
+        REQUEST_ATOM(_NET_WM_DESKTOP);
+        REQUEST_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
+        REQUEST_ATOM(_NET_WM_STRUT_PARTIAL);
+        REQUEST_ATOM(UTF8_STRING);
+
         /* TODO: this has to be more beautiful somewhen */
         int major, minor, error;
 
@@ -310,14 +327,15 @@ int main(int argc, char *argv[], char *env[]) {
         /* end of ugliness */
 
         xcb_event_handlers_init(c, &evenths);
-        for(i = 2; i < 128; ++i)
+
+        /* DEBUG: Trap all events and print them */
+        for (i = 2; i < 128; ++i)
                 xcb_event_set_handler(&evenths, i, handle_event, 0);
 
-        for(i = 0; i < 256; ++i)
+        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) */
+        /* Expose = an Application should redraw itself, in this case it’s our titlebars. */
         xcb_event_set_expose_handler(&evenths, handle_expose_event, 0);
 
         /* Key presses/releases are pretty obvious, I think */
@@ -330,33 +348,42 @@ int main(int argc, char *argv[], char *env[]) {
         /* 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);
+        /* Map notify = there is a new window */
         xcb_event_set_map_notify_handler(&evenths, handle_map_notify_event, &prophs);
 
+        /* Unmap notify = window disappeared. When sent from a client, we don’t manage
+           it any longer. Usually, the client destroys the window shortly afterwards. */
+        xcb_event_set_unmap_notify_handler(&evenths, handle_unmap_notify_event, 0);
+
+        /* Client message = client changed its properties (EWMH) */
+        /* TODO: can’t we do this via property handlers? */
         xcb_event_set_client_message_handler(&evenths, handle_client_message, 0);
 
+        /* Initialize the property handlers */
+        xcb_property_handlers_init(&prophs, &evenths);
+
+        /* Watch the WM_NAME (= title of the window) property */
         xcb_watch_wm_name(&prophs, 128, handle_windowname_change, 0);
 
+        /* Get the root window and set the event mask */
         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_EVENT_MASK_ENTER_WINDOW};
+        uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
+                              XCB_EVENT_MASK_PROPERTY_CHANGE |
+                              XCB_EVENT_MASK_ENTER_WINDOW };
         xcb_change_window_attributes(c, root, mask, values);
 
         /* Setup NetWM atoms */
-        /* TODO: needs cleanup, needs more xcb (asynchronous), needs more error checking */
-#define GET_ATOM(name) { \
-        xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(c, xcb_intern_atom(c, 0, strlen(#name), #name), NULL); \
-        if (!reply) { \
-                printf("Could not get atom " #name "\n"); \
-                exit(-1); \
-        } \
-        atoms[name] = reply->atom; \
-        free(reply); \
-}
+        #define GET_ATOM(name) { \
+                xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(c, atom_cookies[name], NULL); \
+                if (!reply) { \
+                        printf("Could not get atom " #name "\n"); \
+                        exit(-1); \
+                } \
+                atoms[name] = reply->atom; \
+                free(reply); \
+        }
 
         GET_ATOM(_NET_SUPPORTED);
         GET_ATOM(_NET_WM_STATE_FULLSCREEN);
@@ -372,11 +399,13 @@ int main(int argc, char *argv[], char *env[]) {
         xcb_property_set_handler(&prophs, atoms[_NET_WM_WINDOW_TYPE], UINT_MAX, window_type_handler, NULL);
         /* TODO: In order to comply with EWMH, we have to watch _NET_WM_STRUT_PARTIAL */
 
-        check_error(c, xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED], ATOM, 32, 7, atoms), "Could not set _NET_SUPPORTED");
+        /* Set up the atoms we support */
+        check_error(c, xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED],
+                       ATOM, 32, 7, atoms), "Could not set _NET_SUPPORTED");
 
+        /* Set up the window manager’s name */
         xcb_change_property(c, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTING_WM_CHECK], WINDOW, 32, 1, &root);
-
-        xcb_change_property(c, XCB_PROP_MODE_REPLACE, root, atoms[_NET_WM_NAME] , atoms[UTF8_STRING], 8, strlen("i3"), "i3");
+        xcb_change_property(c, XCB_PROP_MODE_REPLACE, root, atoms[_NET_WM_NAME], atoms[UTF8_STRING], 8, strlen("i3"), "i3");
 
         #define BIND(key, modifier, cmd) { \
                 Binding *new = malloc(sizeof(Binding)); \
@@ -422,6 +451,7 @@ int main(int argc, char *argv[], char *env[]) {
         BIND(18, BIND_MOD_1 , "9");
         BIND(19, BIND_MOD_1 , "0");
 
+        /* Grab the bound keys */
         Binding *bind;
         TAILQ_FOREACH(bind, &bindings, bindings) {
                 printf("Grabbing %d\n", bind->keycode);
@@ -434,6 +464,7 @@ int main(int argc, char *argv[], char *env[]) {
         printf("Checking for Xinerama...\n");
         initialize_xinerama(c);
 
+        /* DEBUG: Start a terminal */
         start_application(TERMINAL);
 
         xcb_flush(c);
@@ -441,9 +472,8 @@ int main(int argc, char *argv[], char *env[]) {
         manage_existing_windows(c, &prophs, root);
 
         /* Get pointer position to see on which screen we’re starting */
-        xcb_query_pointer_cookie_t pointer_cookie = xcb_query_pointer(c, root);
-        xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(c, pointer_cookie, NULL);
-        if (reply == NULL) {
+        xcb_query_pointer_reply_t *reply;
+        if ((reply = xcb_query_pointer(c, xcb_query_pointer(c, root), NULL)) == NULL) {
                 printf("Could not get pointer position\n");
                 return 1;
         }
@@ -458,6 +488,7 @@ int main(int argc, char *argv[], char *env[]) {
                 c_ws = &workspaces[screen->current_workspace];
         }
 
+        /* Enter xcb’s event handler */
         xcb_event_wait_for_event_loop(&evenths);
 
         /* not reached */