]> git.sur5r.net Git - i3/i3/blob - src/layout.c
Add vim hints, copyright notice to each file, add LICENSE, retab! everything
[i3/i3] / src / layout.c
1 /*
2  * vim:ts=8:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  *
6  * (c) 2009 Michael Stapelberg and contributors
7  *
8  * See file LICENSE for license information.
9  *
10  */
11 #define _GNU_SOURCE
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <xcb/xcb.h>
16
17 #include "font.h"
18 #include "i3.h"
19 #include "xcb.h"
20 #include "table.h"
21 #include "util.h"
22
23 /* All functions handling layout/drawing of window decorations */
24
25 /*
26  * (Re-)draws window decorations for a given Client
27  *
28  */
29 void decorate_window(xcb_connection_t *conn, Client *client) {
30         uint32_t mask = 0;
31         uint32_t values[3];
32         i3Font *font = load_font(conn, pattern);
33         uint32_t background_color,
34                  text_color,
35                  border_color;
36
37         if (client->container->currently_focused == client) {
38                 background_color = get_colorpixel(conn, client->frame, "#285577");
39                 text_color = get_colorpixel(conn, client->frame, "#ffffff");
40                 border_color = get_colorpixel(conn, client->frame, "#4c7899");
41         } else {
42                 background_color = get_colorpixel(conn, client->frame, "#222222");
43                 text_color = get_colorpixel(conn, client->frame, "#888888");
44                 border_color = get_colorpixel(conn, client->frame, "#333333");
45         }
46
47         /* Our plan is the following:
48            - Draw a rect around the whole client in background_color
49            - Draw two lines in a lighter color
50            - Draw the window’s title
51
52            Note that xcb_image_text apparently adds 1xp border around the font? Can anyone confirm this?
53          */
54
55         /* Draw a green rectangle around the window */
56         mask = XCB_GC_FOREGROUND;
57         values[0] = background_color;
58         xcb_change_gc(conn, client->titlegc, mask, values);
59
60         xcb_rectangle_t rect = {0, 0, client->width, client->height};
61         xcb_poly_fill_rectangle(conn, client->frame, client->titlegc, 1, &rect);
62
63         /* Draw the lines */
64         /* TODO: this needs to be more beautiful somewhen. maybe stdarg + change_gc(gc, ...) ? */
65 #define DRAW_LINE(colorpixel, x, y, to_x, to_y) { \
66                 uint32_t draw_values[1]; \
67                 draw_values[0] = colorpixel; \
68                 xcb_change_gc(conn, client->titlegc, XCB_GC_FOREGROUND, draw_values); \
69                 xcb_point_t points[] = {{x, y}, {to_x, to_y}}; \
70                 xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, client->frame, client->titlegc, 2, points); \
71         }
72
73         DRAW_LINE(border_color, 2, 0, client->width, 0);
74         DRAW_LINE(border_color, 2, font->height + 3, 2 + client->width, font->height + 3);
75
76         /* Draw the font */
77         mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
78
79         values[0] = text_color;
80         values[1] = background_color;
81         values[2] = font->id;
82
83         xcb_change_gc(conn, client->titlegc, mask, values);
84
85         /* TODO: utf8? */
86         char *label;
87         asprintf(&label, "(%08x) %.*s", client->frame, client->name_len, client->name);
88         xcb_void_cookie_t text_cookie = xcb_image_text_8_checked(conn, strlen(label), client->frame,
89                                         client->titlegc, 3 /* X */, font->height /* Y = baseline of font */, label);
90         check_error(conn, text_cookie, "Could not draw client's title");
91         free(label);
92 }
93
94 static void render_container(xcb_connection_t *connection, Container *container) {
95         Client *client;
96         i3Font *font = load_font(connection, pattern);
97
98         if (container->mode == MODE_DEFAULT) {
99                 int num_clients = 0;
100                 CIRCLEQ_FOREACH(client, &(container->clients), clients)
101                         num_clients++;
102                 printf("got %d clients in this default container.\n", num_clients);
103
104                 int current_client = 0;
105                 CIRCLEQ_FOREACH(client, &(container->clients), clients) {
106                         /* TODO: at the moment, every column/row is screen / num_cols. This
107                          * needs to be changed to "percentage of the screen" by
108                          * default and adjustable by the user if necessary.
109                          */
110
111                         /* Check if we changed client->x or client->y by updating it…
112                          * Note the bitwise OR instead of logical OR to force evaluation of both statements */
113                         if ((client->x != (client->x = container->x + (container->col * container->width))) |
114                             (client->y != (client->y = container->y + (container->row * container->height +
115                                           (container->height / num_clients) * current_client)))) {
116                                 printf("frame needs to be pushed to %dx%d\n", client->x, client->y);
117                                 /* Note: We can use a pointer to client->x like an array of uint32_ts
118                                    because it is followed by client->y by definition */
119                                 xcb_configure_window(connection, client->frame,
120                                                 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, &(client->x));
121                         }
122
123                         /* TODO: vertical default layout */
124                         if ((client->width != (client->width = container->width)) |
125                             (client->height != (client->height = container->height / num_clients))) {
126                                 xcb_configure_window(connection, client->frame,
127                                                 XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
128                                                 &(client->width));
129
130                                 /* Adjust the position of the child inside its frame.
131                                  * The coordinates of the child are relative to its frame, we
132                                  * add a border of 2 pixel to each value */
133                                 uint32_t mask = XCB_CONFIG_WINDOW_X |
134                                                 XCB_CONFIG_WINDOW_Y |
135                                                 XCB_CONFIG_WINDOW_WIDTH |
136                                                 XCB_CONFIG_WINDOW_HEIGHT;
137                                 uint32_t values[4] = {2,                                              /* x */
138                                                       font->height + 2 + 2,                           /* y */
139                                                       client->width - (2 + 2),                        /* width */
140                                                       client->height - ((font->height + 2 + 2) + 2)}; /* height */
141
142                                 printf("child itself will be at %dx%d with size %dx%d\n",
143                                                 values[0], values[1], values[2], values[3]);
144
145                                 xcb_configure_window(connection, client->child, mask, values);
146                         }
147
148                         decorate_window(connection, client);
149                         current_client++;
150                 }
151         } else {
152                 /* TODO: Implement stacking */
153         }
154 }
155
156 void render_layout(xcb_connection_t *conn) {
157         int cols, rows;
158         int screen;
159         for (screen = 0; screen < num_screens; screen++) {
160                 printf("Rendering screen %d\n", screen);
161                 /* TODO: get the workspace which is active on the screen */
162                 int width = workspaces[screen].width;
163                 int height = workspaces[screen].height;
164
165                 printf("got %d rows and %d cols\n", c_ws->rows, c_ws->cols);
166                 printf("each of them therefore is %d px width and %d px height\n",
167                                 width / c_ws->cols, height / c_ws->rows);
168
169                 /* Go through the whole table and render what’s necessary */
170                 for (cols = 0; cols < c_ws->cols; cols++)
171                         for (rows = 0; rows < c_ws->rows; rows++) {
172                                 Container *con = CUR_TABLE[cols][rows];
173                                 printf("container has %d colspan, %d rowspan\n",
174                                                 con->colspan, con->rowspan);
175                                 /* Update position of the container */
176                                 con->row = rows;
177                                 con->col = cols;
178                                 con->x = workspaces[screen].x;
179                                 con->y = workspaces[screen].y;
180                                 con->width = (width / c_ws->cols) * con->colspan;
181                                 con->height = (height / c_ws->rows) * con->rowspan;
182
183                                 /* Render it */
184                                 render_container(conn, CUR_TABLE[cols][rows]);
185                         }
186         }
187
188         xcb_flush(conn);
189 }