12 #include <xcb/xcb_event.h>
13 #include <xcb/xcb_ewmh.h>
14 #include <cairo/cairo.h>
17 #define MAX(A, B) ((A) > (B) ? (A) : (B))
19 #define FIFO_PATH "BSPWM_FIFO"
22 #define FONT_FAMILY "sans-serif"
24 #define HORIZONTAL_PADDING 9
34 int font_size = FONT_SIZE;
35 char external_infos[BUFSIZ] = NO_VALUE;
39 int fifo_fd, dpy_fd, sel_fd;
41 xcb_connection_t *dpy;
42 xcb_ewmh_connection_t ewmh;
46 uint16_t screen_width;
47 unsigned int horizontal_padding = HORIZONTAL_PADDING;
52 double text_width(char *s)
55 cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 1, 1);
56 cairo_t *cr = cairo_create(surface);
57 cairo_text_extents_t te;
58 cairo_select_font_face(cr, font_family, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
59 cairo_set_font_size(cr, font_size);
60 cairo_text_extents(cr, s, &te);
63 cairo_surface_destroy(surface);
64 /* fprintf(stderr, "%s\n", cairo_status_to_string(cairo_status(cr))); */
68 void handle_signal(int sig)
70 if (sig == SIGTERM || sig == SIGINT || sig == SIGHUP)
74 void update_window_title(void)
77 xcb_ewmh_get_utf8_strings_reply_t name;
78 uint32_t values[] = {XCB_EVENT_MASK_PROPERTY_CHANGE};
79 uint32_t values_reset[] = {XCB_EVENT_MASK_NO_EVENT};
83 if (xcb_ewmh_get_active_window_reply(&ewmh, xcb_ewmh_get_active_window(&ewmh, default_screen), &win, NULL) == 1
84 && xcb_ewmh_get_wm_name_reply(&ewmh, xcb_ewmh_get_wm_name(&ewmh, win), &name, NULL) == 1) {
85 window_title = strdup(name.strings);
87 xcb_change_window_attributes(dpy, curwin, XCB_CW_EVENT_MASK, values_reset);
90 xcb_generic_error_t *err = xcb_request_check(dpy, xcb_change_window_attributes_checked(dpy, win, XCB_CW_EVENT_MASK, values));
95 window_title = strdup(NO_VALUE);
99 void update_desktop_name(void)
102 xcb_ewmh_get_utf8_strings_reply_t names;
103 unsigned int pos = 0, cnt = 0;
107 if (xcb_ewmh_get_current_desktop_reply(&ewmh, xcb_ewmh_get_current_desktop(&ewmh, default_screen), &cd, NULL) == 1 && xcb_ewmh_get_desktop_names_reply(&ewmh, xcb_ewmh_get_desktop_names(&ewmh, default_screen), &names, NULL) == 1) {
108 while (cnt < cd && pos < names.strings_len) {
109 pos += strlen(names.strings + pos) + 1;
112 desktop_name = strdup(names.strings + pos);
114 desktop_name = strdup(NO_VALUE);
118 void output_infos(void)
120 double left_width = text_width(desktop_name);
121 double center_width = text_width(window_title);
122 double right_width = text_width(external_infos);
123 double available_center = screen_width - (left_width + right_width + 4 * horizontal_padding);
125 int left_pos = horizontal_padding;
126 int center_pos = left_width + 2 * horizontal_padding + (available_center / 2) - (center_width / 2);
127 int right_pos = screen_width - right_width - horizontal_padding;
129 printf("^pa(%i)%s^pa(%i)%s^pa(%i)%s\n", left_pos, desktop_name, center_pos, window_title, right_pos, external_infos);
133 void handle_event(xcb_generic_event_t *evt)
135 xcb_property_notify_event_t *pne;
136 switch (XCB_EVENT_RESPONSE_TYPE(evt)) {
137 case XCB_PROPERTY_NOTIFY:
138 pne = (xcb_property_notify_event_t *) evt;
139 if (pne->atom == ewmh._NET_CURRENT_DESKTOP || pne->atom == ewmh._NET_DESKTOP_NAMES) {
140 update_desktop_name();
142 } else if (pne->atom == ewmh._NET_ACTIVE_WINDOW) {
143 update_window_title();
145 } else if (pne->window != screen->root && (pne->atom == ewmh._NET_WM_NAME || pne->atom == XCB_ATOM_WM_NAME)) {
146 update_window_title();
154 void register_events(void)
156 xcb_generic_error_t *err;
157 uint32_t values[] = {XCB_EVENT_MASK_PROPERTY_CHANGE};
158 err = xcb_request_check(dpy, xcb_change_window_attributes_checked(dpy, screen->root, XCB_CW_EVENT_MASK, values));
165 dpy = xcb_connect(NULL, &default_screen);
166 xcb_intern_atom_cookie_t *ewmh_cookies;
167 ewmh_cookies = xcb_ewmh_init_atoms(dpy, &ewmh);
168 xcb_ewmh_init_atoms_replies(&ewmh, ewmh_cookies, NULL);
169 screen = ewmh.screens[default_screen];
170 screen_width = screen->width_in_pixels;
171 fifo_path = getenv(FIFO_PATH);
172 mkfifo(fifo_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
173 /* http://www.outflux.net/blog/archives/2008/03/09/using-select-on-a-fifo/ */
174 fifo_fd = open(fifo_path, O_RDWR | O_NONBLOCK);
175 dpy_fd = xcb_get_file_descriptor(dpy);
176 sel_fd = MAX(fifo_fd, dpy_fd) + 1;
177 desktop_name = strdup(NO_VALUE);
178 window_title = strdup(NO_VALUE);
179 font_family = strdup(FONT_FAMILY);
184 int main(int argc, char *argv[])
187 xcb_generic_event_t *evt;
188 signal(SIGTERM, handle_signal);
189 signal(SIGINT, handle_signal);
190 signal(SIGHUP, handle_signal);
193 update_desktop_name();
194 update_window_title();
198 font_family = strdup(argv[1]);
200 font_size = atoi(argv[2]);
202 horizontal_padding = atoi(argv[3]);
210 FD_ZERO(&descriptors);
211 FD_SET(fifo_fd, &descriptors);
212 FD_SET(dpy_fd, &descriptors);
214 if (select(sel_fd, &descriptors, NULL, NULL, NULL)) {
215 if (FD_ISSET(dpy_fd, &descriptors)) {
216 while ((evt = xcb_poll_for_event(dpy)) != NULL) {
222 if (FD_ISSET(fifo_fd, &descriptors)) {
223 int bytes = read(fifo_fd, external_infos, sizeof(external_infos));
225 external_infos[bytes] = '\0';