]> git.sur5r.net Git - i3/i3/commitdiff
re-add support for legacy window titles (WM_NAME)
authorMichael Stapelberg <michael@stapelberg.de>
Tue, 13 Apr 2010 15:46:54 +0000 (17:46 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Tue, 13 Apr 2010 15:46:54 +0000 (17:46 +0200)
include/data.h
include/handlers.h
include/window.h
src/handlers.c
src/manage.c
src/nc.c
src/window.c
src/x.c

index 154c0828d6b10b1cc6799516cf787ff01e66af2e..565dbaac0e54e77fd99eb990c537347e6e9ca83a 100644 (file)
@@ -247,11 +247,21 @@ struct xoutput {
 struct Window {
     xcb_window_t id;
 
-    const char *class_class;
-    const char *class_instance;
-    const char *name_ucs2;
-    const char *name_utf8;
+    char *class_class;
+    char *class_instance;
+
+    /** The name of the window as it will be passod to X11 (in UCS2 if the
+     * application supports _NET_WM_NAME, in COMPOUND_TEXT otherwise). */
+    char *name_x;
+
+    /** The name of the window as used in JSON (in UTF-8 if the application
+     * supports _NET_WM_NAME, in COMPOUND_TEXT otherwise) */
+    char *name_json;
+
+    /** The length of the name in glyphs (not bytes) */
     int name_len;
+
+    /** Whether the application used _NET_WM_NAME */
     bool uses_net_wm_name;
 };
 
index ecfa6a5316fee68e16b3bc382375164b19624a59..f4aaf58224c9760fe80c418a0a17025cdf3546b7 100644 (file)
@@ -115,17 +115,9 @@ int handle_destroy_notify_event(void *data, xcb_connection_t *conn,
 int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state,
                              xcb_window_t window, xcb_atom_t atom,
                              xcb_get_property_reply_t *prop);
-#if 0
 /**
- * We handle legacy window names (titles) which are in COMPOUND_TEXT
- * encoding. However, we just pass them along, so when containing non-ASCII
- * characters, those will be rendering incorrectly. In order to correctly
- * render unicode window titles in i3, an application has to set _NET_WM_NAME,
- * which is in UTF-8 encoding.
- *
- * On every update, a message is put out to the user, so he may improve the
- * situation and update applications which display filenames in their title to
- * correctly use _NET_WM_NAME and therefore support unicode.
+ * Handles legacy window name updates (WM_NAME), see also src/window.c,
+ * window_update_name_legacy().
  *
  */
 int handle_windowname_change_legacy(void *data, xcb_connection_t *conn,
@@ -133,6 +125,7 @@ int handle_windowname_change_legacy(void *data, xcb_connection_t *conn,
                                     xcb_atom_t atom, xcb_get_property_reply_t
                                     *prop);
 
+#if 0
 /**
  * Store the window classes for jumping to them later.
  *
index d2b3e9dcd98b3b680bc530b71ca6d01addee7830..a126a36c99f426c92e7b933b745ff8fcb5e52333 100644 (file)
@@ -3,5 +3,6 @@
 
 void window_update_class(i3Window *win, xcb_get_property_reply_t *prop);
 void window_update_name(i3Window *win, xcb_get_property_reply_t *prop);
+void window_update_name_legacy(i3Window *win, xcb_get_property_reply_t *prop);
 
 #endif
index 2f89afe9b4f81d11db7cab1541b17b1dcfc5c3f8..b56095409440fdcfc8ef26c885e6877d76de4bea 100644 (file)
@@ -582,74 +582,24 @@ int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state,
 
     return 1;
 }
-#if 0
+
 /*
- * We handle legacy window names (titles) which are in COMPOUND_TEXT encoding. However, we
- * just pass them along, so when containing non-ASCII characters, those will be rendering
- * incorrectly. In order to correctly render unicode window titles in i3, an application
- * has to set _NET_WM_NAME, which is in UTF-8 encoding.
- *
- * On every update, a message is put out to the user, so he may improve the situation and
- * update applications which display filenames in their title to correctly use
- * _NET_WM_NAME and therefore support unicode.
+ * Handles legacy window name updates (WM_NAME), see also src/window.c,
+ * window_update_name_legacy().
  *
  */
 int handle_windowname_change_legacy(void *data, xcb_connection_t *conn, uint8_t state,
                                 xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) {
-        if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
-                DLOG("prop == NULL\n");
-                return 1;
-        }
-        Client *client = table_get(&by_child, window);
-        if (client == NULL)
-                return 1;
-
-        /* Client capable of _NET_WM_NAME, ignore legacy name changes */
-        if (client->uses_net_wm_name)
-                return 1;
-
-        /* Save the old pointer to make the update atomic */
-        char *new_name;
-        if (asprintf(&new_name, "%.*s", xcb_get_property_value_length(prop), (char*)xcb_get_property_value(prop)) == -1) {
-                perror("Could not get old name");
-                DLOG("Could not get old name\n");
-                return 1;
-        }
-        /* Convert it to UCS-2 here for not having to convert it later every time we want to pass it to X */
-        LOG("WM_NAME changed to \"%s\"\n", new_name);
-
-        /* Check if they are the same and don’t update if so. */
-        if (client->name != NULL &&
-            strlen(new_name) == strlen(client->name) &&
-            strcmp(client->name, new_name) == 0) {
-                free(new_name);
-                return 1;
-        }
-
-        LOG("Using legacy window title. Note that in order to get Unicode window titles in i3, "
-            "the application has to set _NET_WM_NAME which is in UTF-8 encoding.\n");
-
-        char *old_name = client->name;
-        client->name = new_name;
-        client->name_len = -1;
-
-        if (old_name != NULL)
-                free(old_name);
+    Con *con;
+    if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
+        return 1;
 
-        /* If the client is a dock window, we don’t need to render anything */
-        if (client->dock)
-                return 1;
+    window_update_name_legacy(con->window, prop);
 
-        if (client->container != NULL &&
-            (client->container->mode == MODE_STACK ||
-             client->container->mode == MODE_TABBED))
-                render_container(conn, client->container);
-        else decorate_window(conn, client, client->frame, client->titlegc, 0, 0);
-        xcb_flush(conn);
+    x_push_changes(croot);
 
-        return 1;
+    return 1;
 }
-#endif
 
 /*
  * Updates the client’s WM_CLASS property
index 7ffcd61e84d3775c69595e6b1a3f1916f2fbc343..49f10599f3c7e6904d9dac1cf8d0bd6080f874c9 100644 (file)
@@ -129,6 +129,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
 
     /* update as much information as possible so far (some replies may be NULL) */
     window_update_class(cwindow, xcb_get_property_reply(conn, class_cookie, NULL));
+    window_update_name_legacy(cwindow, xcb_get_property_reply(conn, title_cookie, NULL));
     window_update_name(cwindow, xcb_get_property_reply(conn, utf8_title_cookie, NULL));
 
     Con *nc;
index 7b2b126ac6c507ec7a066c6eb8d7f8f54207149e..e1b8a409291d318959b39b52b3133bcd485edded 100644 (file)
--- a/src/nc.c
+++ b/src/nc.c
@@ -347,8 +347,13 @@ int main(int argc, char *argv[]) {
     GET_ATOM(_NET_ACTIVE_WINDOW);
     GET_ATOM(_NET_WORKAREA);
 
+    /* Watch _NET_WM_NAME (title of the window encoded in UTF-8) */
     xcb_property_set_handler(&prophs, atoms[_NET_WM_NAME], 128, handle_windowname_change, NULL);
 
+    /* Watch WM_NAME (title of the window encoded in COMPOUND_TEXT) */
+    xcb_watch_wm_name(&prophs, 128, handle_windowname_change_legacy, NULL);
+
+
     keysyms = xcb_key_symbols_alloc(conn);
 
     xcb_get_numlock_mask(conn);
index ac6f45a09449c22ddebe537b0e84fa6ebfb02451..93812b3f875bc5c4df761038300a0cc4fd73c446 100644 (file)
@@ -7,6 +7,11 @@
  */
 #include "all.h"
 
+/*
+ * Updates the WM_CLASS (consisting of the class and instance) for the
+ * given window.
+ *
+ */
 void window_update_class(i3Window *win, xcb_get_property_reply_t *prop) {
     if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
         DLOG("empty property, not updating\n");
@@ -23,24 +28,71 @@ void window_update_class(i3Window *win, xcb_get_property_reply_t *prop) {
 
     win->class_instance = strdup(new_class);
     if ((strlen(new_class) + 1) < xcb_get_property_value_length(prop))
-            win->class_class = strdup(new_class + strlen(new_class) + 1);
+        win->class_class = strdup(new_class + strlen(new_class) + 1);
     else win->class_class = NULL;
     LOG("WM_CLASS changed to %s (instance), %s (class)\n",
         win->class_instance, win->class_class);
 }
 
+/*
+ * Updates the name by using _NET_WM_NAME (encoded in UTF-8) for the given
+ * window. Further updates using window_update_name_legacy will be ignored.
+ *
+ */
 void window_update_name(i3Window *win, xcb_get_property_reply_t *prop) {
     if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
         DLOG("_NET_WM_NAME not specified, not changing\n");
-        return 1;
+        return;
     }
 
     /* Save the old pointer to make the update atomic */
-    int new_len;
-    asprintf(&win->name_utf8, "%.*s", xcb_get_property_value_length(prop), (char*)xcb_get_property_value(prop));
+    char *new_name;
+    if (asprintf(&new_name, "%.*s", xcb_get_property_value_length(prop),
+                 (char*)xcb_get_property_value(prop)) == -1) {
+        perror("asprintf()");
+        DLOG("Could not get window name\n");
+    }
     /* Convert it to UCS-2 here for not having to convert it later every time we want to pass it to X */
-    win->name_ucs2 = convert_utf8_to_ucs2(win->name_utf8, &win->name_len);
-    LOG("_NET_WM_NAME changed to \"%s\"\n", win->name_utf8);
+    FREE(win->name_x);
+    FREE(win->name_json);
+    win->name_json = new_name;
+    win->name_x = convert_utf8_to_ucs2(win->name_json, &win->name_len);
+    LOG("_NET_WM_NAME changed to \"%s\"\n", win->name_json);
 
     win->uses_net_wm_name = true;
 }
+
+/*
+ * Updates the name by using WM_NAME (encoded in COMPOUND_TEXT). We do not
+ * touch what the client sends us but pass it to xcb_image_text_8. To get
+ * proper unicode rendering, the application has to use _NET_WM_NAME (see
+ * window_update_name()).
+ *
+ */
+void window_update_name_legacy(i3Window *win, xcb_get_property_reply_t *prop) {
+    if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
+        DLOG("prop == NULL\n");
+        return;
+    }
+
+    /* ignore update when the window is known to already have a UTF-8 name */
+    if (win->uses_net_wm_name)
+        return;
+
+    char *new_name;
+    if (asprintf(&new_name, "%.*s", xcb_get_property_value_length(prop),
+                 (char*)xcb_get_property_value(prop)) == -1) {
+        perror("asprintf()");
+        DLOG("Could not get legacy window name\n");
+        return;
+    }
+
+    LOG("Using legacy window title. Note that in order to get Unicode window "
+        "titles in i3, the application has to set _NET_WM_NAME (UTF-8)\n");
+
+    FREE(win->name_x);
+    FREE(win->name_json);
+    win->name_x = new_name;
+    win->name_json = strdup(new_name);
+    win->name_len = strlen(new_name);
+}
diff --git a/src/x.c b/src/x.c
index ee0bd07d8d8912294d6b2b3dac4c8869745c0250..347b8f7649849934b716552a2869e09dad81a7ad 100644 (file)
--- a/src/x.c
+++ b/src/x.c
@@ -153,28 +153,40 @@ void x_draw_decoration(Con *con) {
     xcb_rectangle_t drect = { con->deco_rect.x, con->deco_rect.y, con->deco_rect.width, con->deco_rect.height };
     xcb_poly_fill_rectangle(conn, parent->frame, parent->gc, 1, &drect);
 
-    if (con->window == NULL) {
+    if (con->window == NULL)
         return;
-    }
 
-    if (con->window->name_ucs2 == NULL) {
+    i3Window *win = con->window;
+
+    if (win->name_x == NULL) {
         LOG("not rendering decoration, not yet known\n");
         return;
     }
 
 
-    LOG("should render text %s onto %p / %s\n", con->window->name_utf8, parent, parent->name);
+    LOG("should render text %s onto %p / %s\n", win->name_json, parent, parent->name);
 
     xcb_change_gc_single(conn, parent->gc, XCB_GC_FOREGROUND, get_colorpixel("#FFFFFF"));
-    xcb_image_text_16(
-        conn,
-        con->window->name_len,
-        parent->frame,
-        parent->gc,
-        con->deco_rect.x,
-        con->deco_rect.y + 14,
-        (xcb_char2b_t*)con->window->name_ucs2
-    );
+    if (win->uses_net_wm_name)
+        xcb_image_text_16(
+            conn,
+            win->name_len,
+            parent->frame,
+            parent->gc,
+            con->deco_rect.x,
+            con->deco_rect.y + 14, /* TODO: hardcoded */
+            (xcb_char2b_t*)win->name_x
+        );
+    else
+        xcb_image_text_8(
+            conn,
+            win->name_len,
+            parent->frame,
+            parent->gc,
+            con->deco_rect.x,
+            con->deco_rect.y + 14, /* TODO: hardcoded */
+            win->name_x
+        );
 }
 
 /*