From 6f630a33356507df6816e3d5c40250265838ba03 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 8 Mar 2009 00:49:11 +0100 Subject: [PATCH] Implement UTF-8-clean window titles --- include/data.h | 3 +-- include/util.h | 1 + src/handlers.c | 6 ++---- src/layout.c | 10 +++++----- src/mainx.c | 3 +++ src/util.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 58 insertions(+), 11 deletions(-) diff --git a/include/data.h b/include/data.h index e2d59f88..c5dbf67e 100644 --- a/include/data.h +++ b/include/data.h @@ -213,9 +213,8 @@ struct Client { reservation */ int desired_height; - /* Name */ + /* Name (= window title) */ char *name; - int name_len; /* fullscreen is pretty obvious */ bool fullscreen; diff --git a/include/util.h b/include/util.h index c17f7d01..31beeb80 100644 --- a/include/util.h +++ b/include/util.h @@ -34,6 +34,7 @@ void *scalloc(size_t size); char *sstrdup(const char *str); void start_application(const char *command); void check_error(xcb_connection_t *conn, xcb_void_cookie_t cookie, char *err_message); +char *convert_utf8_to_ucs2(char *input, int *real_strlen); void remove_client_from_container(xcb_connection_t *conn, Client *client, Container *container); void set_focus(xcb_connection_t *conn, Client *client); void leave_stack_mode(xcb_connection_t *conn, Container *container); diff --git a/src/handlers.c b/src/handlers.c index fbc507ea..3158a551 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -486,10 +486,8 @@ int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state, if (client->name != NULL) free(client->name); - client->name_len = xcb_get_property_value_length(prop); - client->name = smalloc(client->name_len); - strncpy(client->name, xcb_get_property_value(prop), client->name_len); - LOG("rename to \"%.*s\".\n", client->name_len, client->name); + asprintf(&(client->name), "%.*s", xcb_get_property_value_length(prop), xcb_get_property_value(prop)); + LOG("rename to \"%s\".\n", client->name); if (client->container->mode == MODE_STACK) render_container(conn, client->container); diff --git a/src/layout.c b/src/layout.c index 912673b2..190dc04a 100644 --- a/src/layout.c +++ b/src/layout.c @@ -167,11 +167,11 @@ void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t draw uint32_t values[] = { text_color, background_color, font->id }; xcb_change_gc(conn, gc, mask, values); - /* TODO: utf8? */ - char *label; - asprintf(&label, "%.*s", client->name_len, client->name); - xcb_image_text_8(conn, strlen(label), drawable, gc, 3 /* X */, offset + font->height /* Y = baseline of font */, label); - free(label); + int real_strlen; + char *ucs2_label = convert_utf8_to_ucs2(client->name, &real_strlen); + xcb_image_text_16(conn, real_strlen, drawable, gc, 3 /* X */, + offset + font->height /* Y = baseline of font */, (xcb_char2b_t*)ucs2_label); + free(ucs2_label); } /* diff --git a/src/mainx.c b/src/mainx.c index e72f161a..55136576 100644 --- a/src/mainx.c +++ b/src/mainx.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -308,6 +309,8 @@ int main(int argc, char *argv[], char *env[]) { xcb_window_t root; xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS]; + setlocale(LC_ALL, ""); + /* Disable output buffering to make redirects in .xsession actually useful for debugging */ if (!isatty(fileno(stdout))) setbuf(stdout, NULL); diff --git a/src/util.c b/src/util.c index c1cb9571..388d1d00 100644 --- a/src/util.c +++ b/src/util.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "i3.h" #include "data.h" @@ -25,6 +26,8 @@ #include "util.h" #include "xcb.h" +static iconv_t conversion_descriptor = 0; + int min(int a, int b) { return (a < b ? a : b); } @@ -135,6 +138,49 @@ void check_error(xcb_connection_t *conn, xcb_void_cookie_t cookie, char *err_mes } } +/* + * Converts the given string to UCS-2 big endian for use with + * xcb_image_text_16(). The amount of real glyphs is stored in real_strlen, + * a buffer containing the UCS-2 encoded string (16 bit per glyph) is + * returned. It has to be freed when done. + * + */ +char *convert_utf8_to_ucs2(char *input, int *real_strlen) { + size_t input_size = strlen(input) + 1; + /* UCS-2 consumes exactly two bytes for each glyph */ + int buffer_size = input_size * 2; + printf("reserving %d bytes\n", buffer_size); + + char *buffer = smalloc(buffer_size); + size_t output_size = buffer_size; + /* We need to use an additional pointer, because iconv() modifies it */ + char *output = buffer; + + /* We convert the input into UCS-2 big endian */ + if (conversion_descriptor == 0) { + conversion_descriptor = iconv_open("UCS-2BE", "UTF-8"); + if (conversion_descriptor == 0) { + fprintf(stderr, "error opening the conversion context\n"); + exit(1); + } + } + + /* Get the conversion descriptor back to original state */ + iconv(conversion_descriptor, NULL, NULL, NULL, NULL); + + /* Convert our text */ + int rc = iconv(conversion_descriptor, &input, &input_size, &output, &output_size); + if (rc == (size_t)-1) { + fprintf(stderr, "Converting to UCS-2 failed\n"); + perror("erron\n"); + exit(1); + } + + *real_strlen = ((buffer_size - output_size) / 2) - 1; + + return buffer; +} + /* * Removes the given client from the container, either because it will be inserted into another * one or because it was unmapped