]> git.sur5r.net Git - i3/i3/blob - i3bar/src/xcb.c
Change the indention-style
[i3/i3] / i3bar / src / xcb.c
1 #include <xcb/xcb.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <i3/ipc.h>
6
7 #include "xcb.h"
8 #include "outputs.h"
9 #include "workspaces.h"
10 #include "ipc.h"
11
12 xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS];
13
14 uint32_t get_colorpixel(const char *s) {
15     char strings[3][3] = { { s[0], s[1], '\0'} ,
16                            { s[2], s[3], '\0'} ,
17                            { s[4], s[5], '\0'} };
18     uint8_t r = strtol(strings[0], NULL, 16);
19     uint8_t g = strtol(strings[1], NULL, 16);
20     uint8_t b = strtol(strings[2], NULL, 16);
21     return (r << 16 | g << 8 | b);
22 }
23
24 void handle_button(xcb_button_press_event_t *event) {
25     i3_ws *cur_ws;
26     i3_output *walk;
27     xcb_window_t bar = event->event;
28     SLIST_FOREACH(walk, outputs, slist) {
29         if (walk->bar == bar) {
30             break;
31         }
32     }
33
34     if (walk == NULL) {
35         printf("Unknown Bar klicked!\n");
36         return;
37     }
38
39     TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) {
40         if (cur_ws->visible) {
41             break;
42         }
43     }
44
45     if (cur_ws == NULL) {
46         printf("No Workspace active?\n");
47         return;
48     }
49
50     int32_t x = event->event_x;
51
52     printf("Got Button %d\n", event->detail);
53
54     switch (event->detail) {
55         case 1:
56             TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) {
57                 printf("x = %d\n", x);
58                 if (x < cur_ws->name_width + 10) {
59                     break;
60                 }
61                 x -= cur_ws->name_width + 10;
62             }
63             if (cur_ws == NULL) {
64                 return;
65             }
66             break;
67         case 4:
68             if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head)) {
69                 cur_ws = TAILQ_FIRST(walk->workspaces);
70             } else {
71                 cur_ws = TAILQ_NEXT(cur_ws, tailq);
72             }
73             break;
74         case 5:
75             if (cur_ws == TAILQ_FIRST(walk->workspaces)) {
76                 cur_ws = TAILQ_LAST(walk->workspaces, ws_head);
77             } else {
78                 cur_ws = TAILQ_PREV(cur_ws, ws_head, tailq);
79             }
80             break;
81     }
82
83     char buffer[50];
84     snprintf(buffer, 50, "%d", cur_ws->num);
85     i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, buffer);
86 }
87
88 void handle_xcb_event(xcb_generic_event_t *event) {
89     switch (event->response_type & ~0x80) {
90         case XCB_EXPOSE:
91             draw_buttons();
92             break;
93         case XCB_BUTTON_PRESS:
94             handle_button((xcb_button_press_event_t*) event);
95             break;
96     }
97 }
98
99 int get_string_width(char *string) {
100     xcb_query_text_extents_cookie_t cookie;
101     xcb_query_text_extents_reply_t *reply;
102     xcb_generic_error_t *error;
103     int width;
104
105     cookie = xcb_query_text_extents(xcb_connection, xcb_font, strlen(string), (xcb_char2b_t*) string);
106     if ((reply= xcb_query_text_extents_reply(xcb_connection, cookie, &error)) == NULL) {
107         printf("ERROR: Could not get text extents!");
108         return 7;
109     }
110
111     width = reply->overall_width;
112     free(reply);
113     return width;
114 }
115
116 void init_xcb() {
117     /* FIXME: xcb_connect leaks Memory */
118     xcb_connection = xcb_connect(NULL, NULL);
119     if (xcb_connection_has_error(xcb_connection)) {
120         printf("Cannot open display\n");
121         exit(EXIT_FAILURE);
122     }
123     printf("Connected to xcb\n");
124
125     /* We have to request the atoms we need */
126     #define ATOM_DO(name) atom_cookies[name] = xcb_intern_atom(xcb_connection, 0, strlen(#name), #name);
127         #include "xcb_atoms.def"
128
129     xcb_screens = xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)).data;
130     xcb_root = xcb_screens->root;
131
132     xcb_font = xcb_generate_id(xcb_connection);
133     char *fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1";
134     xcb_open_font(xcb_connection,
135                   xcb_font,
136                   strlen(fontname),
137                   fontname);
138
139     xcb_list_fonts_with_info_cookie_t cookie;
140     cookie = xcb_list_fonts_with_info(xcb_connection,
141                                       1,
142                                       strlen(fontname),
143                                       fontname);
144     xcb_list_fonts_with_info_reply_t *reply;
145     reply = xcb_list_fonts_with_info_reply(xcb_connection,
146                                            cookie,
147                                            NULL);
148     font_height = reply->font_ascent + reply->font_descent;
149     printf("Calculated Font-height: %d\n", font_height);
150
151
152     /* FIXME: Maybe we can push that further backwards */
153     get_atoms();
154 }
155
156 void clean_xcb() {
157     xcb_disconnect(xcb_connection);
158 }
159
160 void get_atoms() {
161     xcb_intern_atom_reply_t *reply;
162     #define ATOM_DO(name) reply = xcb_intern_atom_reply(xcb_connection, atom_cookies[name], NULL); \
163         atoms[name] = reply->atom; \
164         free(reply);
165
166     #include "xcb_atoms.def"
167     printf("Got Atoms\n");
168 }
169
170 void destroy_windows() {
171     i3_output *walk;
172     if (outputs == NULL) {
173         return;
174     }
175     SLIST_FOREACH(walk, outputs, slist) {
176         if (walk->bar == XCB_NONE) {
177             continue;
178         }
179         xcb_destroy_window(xcb_connection, walk->bar);
180         walk->bar = XCB_NONE;
181     }
182 }
183
184 void create_windows() {
185     uint32_t mask;
186     uint32_t values[2];
187
188     i3_output *walk;
189     SLIST_FOREACH(walk, outputs, slist) {
190         if (!walk->active) {
191             continue;
192         }
193         printf("Creating Window for output %s\n", walk->name);
194
195         walk->bar = xcb_generate_id(xcb_connection);
196         mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
197         values[0] = xcb_screens->black_pixel;
198         values[1] = XCB_EVENT_MASK_EXPOSURE |
199                     XCB_EVENT_MASK_BUTTON_PRESS;
200         xcb_create_window(xcb_connection,
201                           xcb_screens->root_depth,
202                           walk->bar,
203                           xcb_root,
204                           walk->rect.x, walk->rect.y,
205                           walk->rect.w, font_height + 6,
206                           1,
207                           XCB_WINDOW_CLASS_INPUT_OUTPUT,
208                           xcb_screens->root_visual,
209                           mask,
210                           values);
211
212         xcb_change_property(xcb_connection,
213                             XCB_PROP_MODE_REPLACE,
214                             walk->bar,
215                             atoms[_NET_WM_WINDOW_TYPE],
216                             atoms[ATOM],
217                             32,
218                             1,
219                             (unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]);
220
221         walk->bargc = xcb_generate_id(xcb_connection);
222         mask = XCB_GC_FONT;
223         values[0] = xcb_font;
224         xcb_create_gc(xcb_connection,
225                       walk->bargc,
226                       walk->bar,
227                       mask,
228                       values);
229
230         xcb_map_window(xcb_connection, walk->bar);
231     }
232     xcb_flush(xcb_connection);
233 }
234
235 void draw_buttons() {
236     printf("Drawing Buttons...\n");
237     int i = 0;
238     i3_output *outputs_walk;
239     SLIST_FOREACH(outputs_walk, outputs, slist) {
240         if (!outputs_walk->active) {
241             printf("Output %s inactive, skipping...\n", outputs_walk->name);
242             continue;
243         }
244         if (outputs_walk->bar == XCB_NONE) {
245             create_windows();
246         }
247         uint32_t color = get_colorpixel("000000");
248         xcb_change_gc(xcb_connection,
249                       outputs_walk->bargc,
250                       XCB_GC_FOREGROUND,
251                       &color);
252         xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, font_height + 6 };
253         xcb_poly_fill_rectangle(xcb_connection,
254                                 outputs_walk->bar,
255                                 outputs_walk->bargc,
256                                 1,
257                                 &rect);
258         i3_ws *ws_walk;
259         TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
260             printf("Drawing Button for WS %s at x = %d\n", ws_walk->name, i);
261             uint32_t color = get_colorpixel("240000");
262             if (ws_walk->visible) {
263                 color = get_colorpixel("480000");
264             }
265             if (ws_walk->urgent) {
266                 printf("WS %s is urgent!\n", ws_walk->name);
267                 color = get_colorpixel("002400");
268             }
269             xcb_change_gc(xcb_connection,
270                           outputs_walk->bargc,
271                           XCB_GC_FOREGROUND,
272                           &color);
273             xcb_change_gc(xcb_connection,
274                           outputs_walk->bargc,
275                           XCB_GC_BACKGROUND,
276                           &color);
277             xcb_rectangle_t rect = { i + 1, 1, ws_walk->name_width + 8, font_height + 4 };
278             xcb_poly_fill_rectangle(xcb_connection,
279                                     outputs_walk->bar,
280                                     outputs_walk->bargc,
281                                     1,
282                                     &rect);
283             color = get_colorpixel("FFFFFF");
284             xcb_change_gc(xcb_connection,
285                           outputs_walk->bargc,
286                           XCB_GC_FOREGROUND,
287                           &color);
288             xcb_image_text_8(xcb_connection,
289                              strlen(ws_walk->name),
290                              outputs_walk->bar,
291                              outputs_walk->bargc,
292                              i + 5, font_height + 1,
293                              ws_walk->name);
294             i += 10 + ws_walk->name_width;
295         }
296         i = 0;
297     }
298     xcb_flush(xcb_connection);
299 }