re-add support for legacy window titles (WM_NAME)
This commit is contained in:
parent
fd8735a6fd
commit
dd7acf73e9
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
/* If the client is a dock window, we don’t 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 client’s WM_CLASS property
|
||||
|
|
|
@ -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;
|
||||
|
|
5
src/nc.c
5
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);
|
||||
|
|
64
src/window.c
64
src/window.c
|
@ -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
38
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
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue