Draw nice borders. Looks like wmii now :P

This commit is contained in:
Michael Stapelberg 2009-02-10 00:39:48 +01:00
parent 90e3541c94
commit 2562502316
3 changed files with 104 additions and 37 deletions

7
data.h
View File

@ -59,11 +59,12 @@ struct Client {
/* Backpointer. A client is inside a container */ /* Backpointer. A client is inside a container */
Container *container; Container *container;
int width, height;
/* XCB contexts */ /* XCB contexts */
xcb_gcontext_t titlegc; xcb_window_t frame; /* Our window: The frame around the client */
xcb_window_t window; xcb_gcontext_t titlegc; /* The titlebars graphic context inside the frame */
xcb_window_t child; xcb_window_t child; /* The clients window */
/* The following entry provides the necessary list pointers to use Client with LIST_* macros */ /* The following entry provides the necessary list pointers to use Client with LIST_* macros */
CIRCLEQ_ENTRY(Client) clients; CIRCLEQ_ENTRY(Client) clients;

1
font.c
View File

@ -21,6 +21,7 @@ void check_error(xcb_connection_t *connection, xcb_void_cookie_t cookie, char *e
Font *load_font(xcb_connection_t *c, const char *pattern) { Font *load_font(xcb_connection_t *c, const char *pattern) {
/* TODO: this function should be caching */
Font *new = malloc(sizeof(Font)); Font *new = malloc(sizeof(Font));
xcb_list_fonts_with_info_cookie_t cookie = xcb_list_fonts_with_info(c, 1, strlen(pattern), pattern); xcb_list_fonts_with_info_cookie_t cookie = xcb_list_fonts_with_info(c, 1, strlen(pattern), pattern);

133
mainx.c
View File

@ -301,15 +301,29 @@ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *c, xcb_win
/* /*
* Returns the colorpixel to use for the given RGB color code * Returns the colorpixel to use for the given hex color (think of HTML).
*
* The hex_color has to start with #, for example #FF00FF.
*
* NOTE that get_colorpixel() does _NOT_ check the given color code for validity.
* This has to be done by the caller.
* *
*/ */
uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, int r, int g, int b) { uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex) {
#define RGB_8_TO_16(i) (65535 * ((i) & 0xFF) / 255)
char strgroups[3][3] = {{hex[1], hex[2], '\0'},
{hex[3], hex[4], '\0'},
{hex[5], hex[6], '\0'}};
int rgb16[3] = {RGB_8_TO_16(strtol(strgroups[0], NULL, 16)),
RGB_8_TO_16(strtol(strgroups[1], NULL, 16)),
RGB_8_TO_16(strtol(strgroups[2], NULL, 16))};
xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
xcb_colormap_t colormapId = xcb_generate_id(conn); xcb_colormap_t colormapId = xcb_generate_id(conn);
xcb_create_colormap(conn, XCB_COLORMAP_ALLOC_NONE, colormapId, window, root_screen->root_visual); xcb_create_colormap(conn, XCB_COLORMAP_ALLOC_NONE, colormapId, window, root_screen->root_visual);
xcb_alloc_color_reply_t *reply = xcb_alloc_color_reply(conn, xcb_alloc_color(conn, colormapId, r, g, b), NULL); xcb_alloc_color_reply_t *reply = xcb_alloc_color_reply(conn,
xcb_alloc_color(conn, colormapId, rgb16[0], rgb16[1], rgb16[2]), NULL);
if (!reply) { if (!reply) {
printf("color fail\n"); printf("color fail\n");
@ -318,6 +332,7 @@ uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, int r, int
uint32_t pixel = reply->pixel; uint32_t pixel = reply->pixel;
free(reply); free(reply);
xcb_free_colormap(conn, colormapId);
return pixel; return pixel;
} }
@ -329,26 +344,65 @@ void decorate_window(xcb_connection_t *conn, Client *client) {
uint32_t mask = 0; uint32_t mask = 0;
uint32_t values[3]; uint32_t values[3];
xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
Font *font = load_font(conn, pattern);
uint32_t background_color,
text_color,
border_color;
if (client->container->currently_focused == client) {
background_color = get_colorpixel(conn, client->frame, "#285577");
text_color = get_colorpixel(conn, client->frame, "#ffffff");
border_color = get_colorpixel(conn, client->frame, "#4c7899");
} else {
background_color = get_colorpixel(conn, client->frame, "#222222");
text_color = get_colorpixel(conn, client->frame, "#888888");
border_color = get_colorpixel(conn, client->frame, "#333333");
}
/* Our plan is the following:
- Draw a rect around the whole client in background_color
- Draw two lines in a lighter color
- Draw the windows title
Note that xcb_image_text apparently adds 1xp border around the font? Can anyone confirm this?
*/
/* Draw a green rectangle around the window */
mask = XCB_GC_FOREGROUND;
values[0] = background_color;
xcb_change_gc(conn, client->titlegc, mask, values);
xcb_rectangle_t rect = {0, 0, client->width, client->height};
xcb_poly_fill_rectangle(conn, client->frame, client->titlegc, 1, &rect);
/* Draw the lines */
/* TODO: this needs to be more beautiful somewhen. maybe stdarg + change_gc(gc, ...) ? */
#define DRAW_LINE(colorpixel, x, y, to_x, to_y) { \
uint32_t draw_values[1]; \
draw_values[0] = colorpixel; \
xcb_change_gc(conn, client->titlegc, XCB_GC_FOREGROUND, draw_values); \
xcb_point_t points[] = {{x, y}, {to_x, to_y}}; \
xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, client->frame, client->titlegc, 2, points); \
}
DRAW_LINE(border_color, 2, 0, client->width, 0);
DRAW_LINE(border_color, 2, font->height + 3, 2 + client->width, font->height + 3);
/* Draw the font */
mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
Font *font = load_font(conn, pattern); values[0] = text_color;
values[1] = background_color;
values[0] = root_screen->black_pixel;
if (client->container->currently_focused == client) {
printf("oh, currently active = %p\n", client);
values[1] = get_colorpixel(conn, client->window, 65535, 0, 0);
}else values[1] = get_colorpixel(conn, client->window, 0, 0, 65535);
values[2] = font->id; values[2] = font->id;
xcb_change_gc(conn, client->titlegc, mask, values); xcb_change_gc(conn, client->titlegc, mask, values);
/* TODO: utf8? */ /* TODO: utf8? */
//char *label = "i3 rocks :>";
char *label; char *label;
asprintf(&label, "gots win %08x", client->window); asprintf(&label, "gots win %08x", client->frame);
xcb_void_cookie_t textCookie = xcb_image_text_8_checked (conn, strlen (label), client->window, client->titlegc, 2, 2 + font->height, label ); xcb_void_cookie_t text_cookie = xcb_image_text_8_checked(conn, strlen(label), client->frame,
client->titlegc, 3 /* X */, font->height /* Y = baseline of font */, label);
free(label);
} }
void render_container(xcb_connection_t *connection, Container *container) { void render_container(xcb_connection_t *connection, Container *container) {
@ -358,7 +412,7 @@ void render_container(xcb_connection_t *connection, Container *container) {
XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_Y |
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_WIDTH |
XCB_CONFIG_WINDOW_HEIGHT; XCB_CONFIG_WINDOW_HEIGHT;
Font *font = load_font(connection, pattern);
if (container->mode == MODE_DEFAULT) { if (container->mode == MODE_DEFAULT) {
int num_clients = 0; int num_clients = 0;
@ -381,14 +435,18 @@ void render_container(xcb_connection_t *connection, Container *container) {
printf("frame will be at %dx%d with size %dx%d\n", printf("frame will be at %dx%d with size %dx%d\n",
values[0], values[1], values[2], values[3]); values[0], values[1], values[2], values[3]);
/* TODO: update only if necessary */ client->width = values[2];
xcb_configure_window(connection, client->window, mask, values); client->height = values[3];
/* The coordinates of the child are relative to its frame */ /* TODO: update only if necessary */
xcb_configure_window(connection, client->frame, mask, values);
/* The coordinates of the child are relative to its frame, we
* add a border of 2 pixel to each value */
values[0] = 2; values[0] = 2;
values[1] = 20; values[1] = font->height + 2 + 2;
values[2] -= 2; values[2] -= values[0] + 2;
values[3] -= 20; values[3] -= values[1] + 2;
printf("child itself will be at %dx%d with size %dx%d\n", printf("child itself will be at %dx%d with size %dx%d\n",
values[0], values[1], values[2], values[3]); values[0], values[1], values[2], values[3]);
@ -455,8 +513,10 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
CUR_CELL->currently_focused = new; CUR_CELL->currently_focused = new;
new->container = CUR_CELL; new->container = CUR_CELL;
new->window = xcb_generate_id(conn); new->frame = xcb_generate_id(conn);
new->child = child; new->child = child;
new->width = width;
new->height = height;
/* TODO: what do these mean? */ /* TODO: what do these mean? */
mask |= XCB_CW_BACK_PIXEL; mask |= XCB_CW_BACK_PIXEL;
@ -469,12 +529,12 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
values[2] = XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE values[2] = XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE
| XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_ENTER_WINDOW; | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_ENTER_WINDOW;
printf("Reparenting 0x%08x under 0x%08x.\n", child, new->window); printf("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
/* Yo dawg, I heard you like windows, so I create a window around your window… */ /* Yo dawg, I heard you like windows, so I create a window around your window… */
xcb_create_window(conn, xcb_create_window(conn,
depth, depth,
new->window, new->frame,
root, root,
x, x,
y, y,
@ -488,22 +548,22 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child); xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child);
/* Map the window on the screen (= make it visible) */ /* Map the window on the screen (= make it visible) */
xcb_map_window(conn, new->window); xcb_map_window(conn, new->frame);
/* Generate a graphics context for the titlebar */ /* Generate a graphics context for the titlebar */
new->titlegc = xcb_generate_id(conn); new->titlegc = xcb_generate_id(conn);
xcb_create_gc(conn, new->titlegc, new->window, 0, 0); xcb_create_gc(conn, new->titlegc, new->frame, 0, 0);
/* Draw decorations */ /* Draw decorations */
decorate_window(conn, new); decorate_window(conn, new);
/* Put our data structure (Client) into the table */ /* Put our data structure (Client) into the table */
table_put(byParent, new->window, new); table_put(byParent, new->frame, new);
table_put(byChild, child, new); table_put(byChild, child, new);
/* Moves the original window into the new frame we've created for it */ /* Moves the original window into the new frame we've created for it */
/* TODO: hmm, LEFT/TOP needs to go */ Font *font = load_font(conn, pattern);
xcb_reparent_window(conn, child, new->window, LEFT - 1, TOP - 1); xcb_reparent_window(conn, child, new->frame, 0, font->height);
/* We are interested in property changes */ /* We are interested in property changes */
mask = XCB_CW_EVENT_MASK; mask = XCB_CW_EVENT_MASK;
@ -513,7 +573,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
xcb_change_window_attributes(conn, child, mask, values); xcb_change_window_attributes(conn, child, mask, values);
/* TODO: At the moment, new windows just get focus */ /* TODO: At the moment, new windows just get focus */
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, new->window, XCB_CURRENT_TIME); xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, new->frame, XCB_CURRENT_TIME);
render_layout(conn); render_layout(conn);
@ -739,7 +799,8 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press
*/ */
static int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_event_t *event) { static int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_event_t *event) {
/* This was either a focus for a clients parent (= titlebar)… */ /* This was either a focus for a clients parent (= titlebar)… */
Client *client = table_get(byParent, event->event); Client *client = table_get(byParent, event->event),
*old_client;
/* …or the client itself */ /* …or the client itself */
if (client == NULL) if (client == NULL)
client = table_get(byChild, event->event); client = table_get(byChild, event->event);
@ -751,10 +812,14 @@ static int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_
} }
/* Update container */ /* Update container */
old_client = client->container->currently_focused;
client->container->currently_focused = client; client->container->currently_focused = client;
/* Set focus to the entered window, and flush xcb buffer immediately */ /* Set focus to the entered window, and flush xcb buffer immediately */
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, client->child, XCB_CURRENT_TIME); xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, client->child, XCB_CURRENT_TIME);
/* Update last/current clients titlebar */
decorate_window(conn, old_client);
decorate_window(conn, client);
xcb_flush(conn); xcb_flush(conn);
return 1; return 1;
@ -798,11 +863,11 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *c, xcb_unmap_notify_
root = xcb_setup_roots_iterator(xcb_get_setup(c)).data->root; root = xcb_setup_roots_iterator(xcb_get_setup(c)).data->root;
printf("child of 0x%08x.\n", client->window); printf("child of 0x%08x.\n", client->frame);
xcb_reparent_window(c, client->child, root, 0, 0); xcb_reparent_window(c, client->child, root, 0, 0);
xcb_destroy_window(c, client->window); xcb_destroy_window(c, client->frame);
xcb_flush(c); xcb_flush(c);
table_remove(byParent, client->window); table_remove(byParent, client->frame);
free(client); free(client);
render_layout(c); render_layout(c);