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