re-add support for legacy window titles (WM_NAME)

This commit is contained in:
Michael Stapelberg 2010-04-13 17:46:54 +02:00
parent fd8735a6fd
commit dd7acf73e9
8 changed files with 118 additions and 94 deletions

View 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;
};

View 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.
*

View 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

View 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 dont 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);
/* If the client is a dock window, we dont need to render anything */
if (client->dock)
return 1;
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);
Con *con;
if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
return 1;
window_update_name_legacy(con->window, prop);
x_push_changes(croot);
return 1;
}
#endif
/*
* Updates the clients WM_CLASS property

View 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;

View File

@ -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);

View 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);
}

38
src/x.c
View File

@ -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
);
}
/*