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