]> git.sur5r.net Git - i3/i3/commitdiff
More documentation, cleanups, and a cache for get_colorpixel()
authorMichael Stapelberg <michael+git@stapelberg.de>
Tue, 24 Feb 2009 13:18:08 +0000 (14:18 +0100)
committerMichael Stapelberg <michael+git@stapelberg.de>
Tue, 24 Feb 2009 13:18:08 +0000 (14:18 +0100)
include/data.h
include/util.h
include/xcb.h
src/handlers.c
src/layout.c
src/util.c
src/xcb.c

index b4db800a01a3064a1add912540f67479baa44fbc..6a430f2907aa380fc1145499cb1e98a4edd0d9e0 100644 (file)
@@ -7,17 +7,39 @@
  *
  * See file LICENSE for license information.
  *
+ * include/data.h: This file defines all data structures used by i3
+ *
  */
 #include <xcb/xcb.h>
 #include <stdbool.h>
 
 #ifndef _DATA_H
 #define _DATA_H
+#include "queue.h"
+
 /*
- * This file defines all data structures used by i3
+ * To get the big concept: There are helper structures like struct Colorpixel or
+ * struct Stack_Window. Everything which is also defined as type (see forward definitions)
+ * is considered to be a major structure, thus important.
+ *
+ * Let’s start from the biggest to the smallest:
+ * - An i3Screen is a virtual screen (Xinerama). This can be a single one, though two monitors
+ *   might be connected, if you’re running clone mode. There can also be multiple of them.
+ *
+ * - Each i3Screen contains Workspaces. The concept is known from various other window managers.
+ *   Basically, a workspace is a specific set of windows, usually grouped thematically (irc,
+ *   www, work, …). You can switch between these.
+ *
+ * - Each Workspace has a table, which is our layout abstraction. You manage your windows
+ *   by moving them around in your table. It grows as necessary.
+ *
+ * - Each cell of the table has a container, which can be in default or stacking mode. In default
+ *   mode, each client is given equally much space in the container. In stacking mode, only one
+ *   client is shown at a time, but all the titlebars are rendered at the top.
+ *
+ * - Inside the container are clients, which is X11-speak for a window.
  *
  */
-#include "queue.h"
 
 /* Forward definitions */
 typedef struct Cell Cell;
@@ -29,18 +51,20 @@ typedef struct Workspace Workspace;
 typedef struct Rect Rect;
 typedef struct Screen i3Screen;
 
-/* Helper types */
+/******************************************************************************
+ * 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_SHIFT = XCB_MOD_MASK_SHIFT,        /* (1 << 0) */
+        BIND_CONTROL = XCB_MOD_MASK_CONTROL,    /* (1 << 2) */
+        BIND_MOD_1 = XCB_MOD_MASK_1,            /* (1 << 3) */
+        BIND_MOD_2 = XCB_MOD_MASK_2,            /* (1 << 4) */
+        BIND_MOD_3 = XCB_MOD_MASK_3,            /* (1 << 5) */
+        BIND_MOD_4 = XCB_MOD_MASK_4,            /* (1 << 6) */
+        BIND_MOD_5 = XCB_MOD_MASK_5,            /* (1 << 7) */
         BIND_MODE_SWITCH = (1 << 8)
 };
 
@@ -49,6 +73,53 @@ struct Rect {
         uint32_t width, height;
 };
 
+/*
+ * Defines a position in the table
+ *
+ */
+struct Cell {
+        int row;
+        int column;
+};
+
+/*
+ * Used for the cache of colorpixels.
+ *
+ */
+struct Colorpixel {
+        uint32_t pixel;
+
+        char *hex;
+
+        SLIST_ENTRY(Colorpixel) colorpixels;
+};
+
+/*
+ * Contains data for the windows needed to draw the titlebars on in stacking mode
+ *
+ */
+struct Stack_Window {
+        xcb_window_t window;
+        xcb_gcontext_t gc;
+        uint32_t width, height;
+
+        /* Backpointer to the container this stack window is in */
+        Container *container;
+
+        SLIST_ENTRY(Stack_Window) stack_windows;
+};
+
+
+/******************************************************************************
+ * Major types
+ *****************************************************************************/
+
+/*
+ * The concept of Workspaces is known from various other window managers. Basically,
+ * a workspace is a specific set of windows, usually grouped thematically (irc,
+ * www, work, …). You can switch between these.
+ *
+ */
 struct Workspace {
         /* x, y, width, height */
         Rect rect;
@@ -75,14 +146,10 @@ struct Workspace {
 };
 
 /*
- * Defines a position in the table
+ * Holds a keybinding, consisting of a keycode combined with modifiers and the command
+ * which is executed as soon as the key is pressed (see src/command.c)
  *
  */
-struct Cell {
-        int row;
-        int column;
-};
-
 struct Binding {
         /* Keycode to bind */
         uint32_t keycode;
@@ -118,9 +185,9 @@ struct Font {
  *
  */
 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 */
+        /* 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 */
+        Cell old_position;
 
         /* Backpointer. A client is inside a container */
         Container *container;
@@ -155,9 +222,12 @@ struct Client {
         bool awaiting_useless_unmap;
 
         /* 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 */
+        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 */
+
+        /* Cache of colorpixels for this client */
+        SLIST_HEAD(colorpixel_head, Colorpixel) colorpixels;
 
         /* The following entry provides the necessary list pointers to use Client with LIST_* macros */
         CIRCLEQ_ENTRY(Client) clients;
@@ -165,22 +235,7 @@ struct Client {
 };
 
 /*
- * Contains data for the windows needed to draw the titlebars on in stacking mode
- *
- */
-struct Stack_Window {
-        xcb_window_t window;
-        xcb_gcontext_t gc;
-        uint32_t width, height;
-
-        /* Backpointer to the container this stack window is in */
-        Container *container;
-
-        SLIST_ENTRY(Stack_Window) stack_windows;
-};
-
-/*
- * A container is either in default or stacking mode. It sits inside the table.
+ * A container is either in default or stacking mode. It sits inside each cell of the table.
  *
  */
 struct Container {
@@ -212,6 +267,11 @@ struct Container {
         CIRCLEQ_HEAD(client_head, Client) clients;
 };
 
+/*
+ * This is a virtual screen (Xinerama). This can be a single one, though two monitors
+ * might be connected, if you’re running clone mode. There can also be multiple of them.
+ *
+ */
 struct Screen {
         /* Virtual screen number */
         int num;
index e1728c557ca17eaf133544c60c8d68b6d037386e..c2a89c84816b9b2c5d824189a19485923211a306 100644 (file)
@@ -26,6 +26,7 @@ int min(int a, int b);
 int max(int a, int b);
 void die(char *fmt, ...);
 void *smalloc(size_t size);
+void *scalloc(size_t size);
 char *sstrdup(const char *str);
 void start_application(const char *command);
 void check_error(xcb_connection_t *connection, xcb_void_cookie_t cookie, char *err_message);
index 1f372c36624146c2e523aa200d009cb6c89d2ad4..bf5daa3ee6b60a0826785c3a9f8c2a8cbdad333f 100644 (file)
@@ -27,7 +27,7 @@ enum { _NET_SUPPORTED = 0,
         UTF8_STRING
 };
 
-uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex);
+uint32_t get_colorpixel(xcb_connection_t *conn, Client *client, xcb_window_t window, char *hex);
 xcb_window_t create_window(xcb_connection_t *conn, Rect r, uint16_t window_class, uint32_t mask, uint32_t *values);
 void xcb_change_gc_single(xcb_connection_t *conn, xcb_gcontext_t gc, uint32_t mask, uint32_t value);
 void xcb_draw_line(xcb_connection_t *conn, xcb_drawable_t drawable, xcb_gcontext_t gc,
index 23d3172a70664ecc23cbcfda4de12f53e14d3d17..e1edd5c64c159195deea5a48797046b3eff006d2 100644 (file)
@@ -204,7 +204,7 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
         }
         xcb_window_t helpwin = create_window(conn, helprect, XCB_WINDOW_CLASS_INPUT_OUTPUT, 0, NULL);
 
-        uint32_t values[1] = {get_colorpixel(conn, helpwin, "#4c7899")};
+        uint32_t values[1] = {get_colorpixel(conn, NULL, helpwin, "#4c7899")};
         xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(conn, helpwin, XCB_CW_BACK_PIXEL, values);
         check_error(conn, cookie, "Could not change window attributes (background color)");
 
index 87d2f2882e360f066bad0882c62b7a2d7f983934..131ce3c2bef74edda18afd1e50fa0a86a5fffc5d 100644 (file)
@@ -37,17 +37,13 @@ int get_unoccupied_x(Workspace *workspace, int row) {
 
         for (int cols = 0; cols < workspace->cols;) {
                 Container *con = workspace->table[cols][row];
-                printf("oh hai. wf[%d][%d] = %f\n", cols, row, con->width_factor);
-                printf("colspan = %d\n", con->colspan);
+                printf("width_factor[%d][%d] = %f, colspan = %d\n", cols, row, con->width_factor, con->colspan);
                 if (con->width_factor == 0)
                         unoccupied -= workspace->rect.width * default_factor * con->colspan;
                 cols += con->colspan;
         }
 
-        /* TODO: Check (as soon as the whole implementation is done) if this case does ever occur,
-           because this function only gets called when at least one client was resized */
-        if (unoccupied == 0)
-                unoccupied = workspace->rect.width;
+        assert(unoccupied != 0);
 
         printf("unoccupied space: %d\n", unoccupied);
         return unoccupied;
@@ -62,24 +58,21 @@ int get_unoccupied_y(Workspace *workspace, int col) {
 
         for (int rows = 0; rows < workspace->rows;) {
                 Container *con = workspace->table[col][rows];
-                printf("oh hai. wf[%d][%d] = %f\n", col, rows, con->height_factor);
-                printf("rowspan = %d\n", con->rowspan);
+                printf("height_factor[%d][%d] = %f, rowspan %d\n", col, rows, con->height_factor, con->rowspan);
                 if (con->height_factor == 0)
                         unoccupied -= workspace->rect.height * default_factor * con->rowspan;
                 rows += con->rowspan;
         }
 
-        /* TODO: Check (as soon as the whole implementation is done) if this case does ever occur,
-           because this function only gets called when at least one client was resized */
-        if (unoccupied == 0)
-                unoccupied = workspace->rect.height;
+        assert(unoccupied != 0);
 
         printf("unoccupied space: %d\n", unoccupied);
         return unoccupied;
 }
 
 /*
- * (Re-)draws window decorations for a given Client
+ * (Re-)draws window decorations for a given Client onto the given drawable/graphic context.
+ * When in stacking mode, the window decorations are drawn onto an own window.
  *
  */
 void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t drawable, xcb_gcontext_t gc, int offset) {
@@ -93,13 +86,13 @@ void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t draw
                 return;
 
         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");
+                background_color = get_colorpixel(conn, client, client->frame, "#285577");
+                text_color = get_colorpixel(conn, client, client->frame, "#ffffff");
+                border_color = get_colorpixel(conn, client, 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");
+                background_color = get_colorpixel(conn, client, client->frame, "#222222");
+                text_color = get_colorpixel(conn, client, client->frame, "#888888");
+                border_color = get_colorpixel(conn, client, client->frame, "#333333");
         }
 
         /* Our plan is the following:
@@ -110,7 +103,6 @@ void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t draw
 
         /* Draw a green rectangle around the window */
         xcb_change_gc_single(conn, gc, XCB_GC_FOREGROUND, background_color);
-        printf("drawing at offset %d\n", offset);
 
         xcb_rectangle_t rect = {0, offset, client->rect.width, offset + client->rect.height};
         xcb_poly_fill_rectangle(conn, drawable, gc, 1, &rect);
@@ -128,7 +120,6 @@ void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t draw
         /* TODO: utf8? */
         char *label;
         asprintf(&label, "(%08x) %.*s", client->frame, client->name_len, client->name);
-        printf("label is %s\n", label);
         xcb_void_cookie_t text_cookie = xcb_image_text_8_checked(conn, strlen(label), drawable,
                                         gc, 3 /* X */, offset + font->height /* Y = baseline of font */, label);
         check_error(conn, text_cookie, "Could not draw client's title");
index 25a968f93a3ed0b30687bbbd5a85f2456159ba69..f68c9797933c1997b1f988aacb56c2be695b6472 100644 (file)
@@ -58,6 +58,12 @@ void *smalloc(size_t size) {
         return result;
 }
 
+void *scalloc(size_t size) {
+        void *result = calloc(size, 1);
+        exit_if_null(result, "Too less memory for calloc(%d)\n", size);
+        return result;
+}
+
 char *sstrdup(const char *str) {
         char *result = strdup(str);
         exit_if_null(result, "Too less memory for strdup()\n");
@@ -157,13 +163,14 @@ void set_focus(xcb_connection_t *conn, Client *client) {
 void switch_layout_mode(xcb_connection_t *conn, Container *container, int mode) {
         if (mode == MODE_STACK) {
                 /* When entering stacking mode, we need to open a window on which we can draw the
-                   title bars of the clients */
-                Rect rect = {container->x, container->y, container->width, 15 /* TODO: exact */ };
+                   title bars of the clients, it has height 1 because we don’t bother here with
+                   calculating the correct height - it will be adjusted when rendering anyways. */
+                Rect rect = {container->x, container->y, container->width, 1 };
 
-                /* Don’t generate events for our new window, it should *not* be managed */
                 uint32_t mask = 0;
                 uint32_t values[2];
 
+                /* Don’t generate events for our new window, it should *not* be managed */
                 mask |= XCB_CW_OVERRIDE_REDIRECT;
                 values[0] = 1;
 
@@ -250,14 +257,15 @@ void toggle_fullscreen(xcb_connection_t *conn, Client *client) {
                                 values[0], values[1], values[2], values[3]);
 
                 /* Raise the window */
-                xcb_circulate_window(conn, XCB_CIRCULATE_RAISE_LOWEST, client->frame);
+                values[0] = XCB_STACK_MODE_ABOVE;
+                xcb_configure_window(conn, client->frame, XCB_CONFIG_WINDOW_STACK_MODE, values);
 
                 xcb_configure_window(conn, client->frame, mask, values);
                 xcb_configure_window(conn, client->child, mask, values);
 
                 xcb_flush(conn);
         } else {
-                printf("left fullscreen\n");
+                printf("leaving fullscreen mode\n");
                 /* Because the coordinates of the window haven’t changed, it would not be
                    re-configured if we don’t set the following flag */
                 client->force_reconfigure = true;
index 00f59fa119893849577e84e3abd5c051b56bbb38..b2101dcf5b98d8552e1f9d13412cbd5d64bce9a5 100644 (file)
--- a/src/xcb.c
+++ b/src/xcb.c
@@ -13,6 +13,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include <xcb/xcb.h>
 
  *
  * The hex_color has to start with #, for example #FF00FF.
  *
+ * The client argument is optional. If it is given, the colorpixel will be cached.
+ *
  * 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) {
-        /* TODO: We need to store the colorpixels per child to remove these unnecessary requests every time */
+uint32_t get_colorpixel(xcb_connection_t *conn, Client *client, xcb_window_t window, char *hex) {
+        /* Lookup this colorpixel in the cache if a client was specified */
+        if (client != NULL) {
+                struct Colorpixel *pixel;
+                SLIST_FOREACH(pixel, &(client->colorpixels), colorpixels)
+                        if (strcmp(pixel->hex, hex) == 0)
+                                return pixel->pixel;
+        }
         #define RGB_8_TO_16(i) (65535 * ((i) & 0xFF) / 255)
         char strgroups[3][3] = {{hex[1], hex[2], '\0'},
                                 {hex[3], hex[4], '\0'},
@@ -54,6 +63,16 @@ uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex)
         uint32_t pixel = reply->pixel;
         free(reply);
         xcb_free_colormap(conn, colormap_id);
+
+        /* Store the result in the cache if a client was specified */
+        if (client != NULL) {
+                struct Colorpixel *cache_pixel = scalloc(sizeof(struct Colorpixel));
+                cache_pixel->hex = sstrdup(hex);
+                cache_pixel->pixel = pixel;
+
+                SLIST_INSERT_HEAD(&(client->colorpixels), cache_pixel, colorpixels);
+        }
+
         return pixel;
 }