Re: Using _NET_WM properties for window names
- From: Timo Korvola <Timo Korvola iki fi>
- To: sawfish-list gnome org
- Subject: Re: Using _NET_WM properties for window names
- Date: Wed, 31 Oct 2007 20:01:26 +0200
Luis Rodrigo Gallardo Cruz <rodrigo nul-unu com> writes:
> The idea itself ought to be uncontroversial.
Actually, I am not entirely convinced of the usefulness of these
properties. Are there characters in UTF-8 that cannot be
represented as COMPOUND_TEXT?
> In order to get everything working I made sawfish assume
> all strings to be rendered to the screen are encoded as UTF-8.
That is useful regardless of the _NET_WM properties, because the host
encoding Sawfish happens to be using may not be able to represent all
necessary characters even if COMPOUND_TEXT is. Unfortunately this
change is clumsy to implement and without benefit if
Xutf8TextPropertyToTextList is not available. With
XmbTextPropertyToTextList conversion has to go via the local encoding
anyway.
> Anyways, I'm requesting feedback on the patch.
What version is it against? It did not apply cleanly to the trunk.
Anyway, I applied the rejects by hand, fixed some errors and just
cleaned it up a bit. This patch is against the current trunk (r4204).
Alternatively you can pull branch utf-8-names from
http://www.iki.fi/tkorvola/sawfish.git.
--
Timo Korvola <URL:http://www.iki.fi/tkorvola>
diff --git a/src/display.c b/src/display.c
index 4e79b6a..48fdce5 100644
--- a/src/display.c
+++ b/src/display.c
@@ -55,7 +55,8 @@ int preferred_depth;
/* some atoms that may be useful.. */
Atom xa_wm_state, xa_wm_change_state, xa_wm_protocols, xa_wm_delete_window,
- xa_wm_colormap_windows, xa_wm_take_focus, xa_compound_text;
+ xa_wm_colormap_windows, xa_wm_take_focus, xa_compound_text,
+ xa_wm_net_name, xa_wm_net_icon_name, xa_utf8_string;
DEFSYM(display_name, "display-name");
DEFSYM(canonical_display_name, "canonical-display-name");
@@ -335,6 +336,9 @@ sys_init(char *program_name)
xa_wm_colormap_windows = XInternAtom (dpy, "WM_COLORMAP_WINDOWS", False);
xa_wm_take_focus = XInternAtom (dpy, "WM_TAKE_FOCUS", False);
xa_compound_text = XInternAtom (dpy, "COMPOUND_TEXT", False);
+ xa_wm_net_name = XInternAtom (dpy, "_NET_WM_NAME", False);
+ xa_wm_net_icon_name = XInternAtom (dpy, "_NET_WM_ICON_NAME", False);
+ xa_utf8_string = XInternAtom (dpy, "UTF8_STRING", False);
if (!XShapeQueryExtension (dpy, &shape_event_base,
&shape_error_base))
diff --git a/src/events.c b/src/events.c
index 34f753e..14bb15e 100644
--- a/src/events.c
+++ b/src/events.c
@@ -475,6 +475,108 @@ motion_notify (XEvent *ev)
a motion event is actually evaluated) */
}
+
+static bool
+update_window_name(Lisp_Window * w, XPropertyEvent xproperty) {
+ u_char *prop;
+ Atom actual;
+ int format;
+ long nitems, bytes_after;
+ char **text_list;
+ XTextProperty tprop;
+ int count;
+ repv str = Qnil;
+ int convert_status;
+
+ if (xproperty.state != PropertyNewValue
+ || XGetWindowProperty (dpy, w->id, xproperty.atom,
+ 0, 200, False, AnyPropertyType, &actual,
+ &format, &nitems,
+ &bytes_after, &prop) != Success
+ || actual == None)
+ return FALSE;
+
+ if (format != 8 || WINDOW_IS_GONE_P (w))
+ {
+ XFree (prop);
+ return FALSE;
+ }
+
+ tprop.value = prop;
+ tprop.encoding = actual;
+ tprop.format = format;
+ tprop.nitems = strlen (prop);
+
+ if (actual == xa_compound_text || actual == XA_STRING)
+ {
+ convert_status = XmbTextPropertyToTextList (dpy, &tprop, &text_list,
+ &count);
+ if (convert_status >= Success && count > 0)
+ {
+ char * utf8str = g_locale_to_utf8(text_list[0], -1,
+ NULL, NULL, NULL);
+ if (utf8str)
+ str = rep_string_dup (utf8str);
+ }
+ XFreeStringList(text_list);
+ }
+
+#ifdef X_HAVE_UTF8_STRING
+ if (actual == xa_utf8_string)
+ {
+ convert_status = Xutf8TextPropertyToTextList (dpy, &tprop, &text_list,
+ &count);
+ if (convert_status >= Success && count > 0)
+ str = rep_string_dup (text_list[0]);
+ XFreeStringList(text_list);
+ }
+#endif
+
+ XFree (prop);
+
+ if (str == Qnil)
+ return FALSE;
+
+ if (xproperty.atom == xa_wm_net_name
+ && str != Qnil && Fequal (w->net_name, str) == Qnil)
+ {
+ w->net_name = str;
+ return TRUE;
+ }
+
+ if (xproperty.atom == xa_wm_net_icon_name
+ && str != Qnil && Fequal (w->net_icon_name, str) == Qnil)
+ {
+ w->net_icon_name = str;
+ return TRUE;
+ }
+
+ if (w->net_name == Qnil && xproperty.atom == XA_WM_NAME)
+ {
+ if (str == Qnil)
+ str = rep_null_string ();
+ if (Fequal (w->name, str) == Qnil
+ || Fequal (w->full_name, str) == Qnil)
+ {
+ w->full_name = w->name = str;
+ return TRUE;
+ }
+ }
+
+ if (w->net_icon_name == Qnil && xproperty.atom == XA_WM_ICON_NAME)
+ {
+ if (str == Qnil)
+ str = rep_null_string ();
+ if (Fequal (w->icon_name, str) == Qnil)
+ {
+ w->icon_name = str;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
static void
property_notify (XEvent *ev)
{
@@ -488,72 +590,9 @@ property_notify (XEvent *ev)
switch (ev->xproperty.atom)
{
- u_char *prop;
- Atom actual;
- int format;
- long nitems, bytes_after;
long supplied;
bool old_urgency, new_urgency;
- case XA_WM_NAME:
- case XA_WM_ICON_NAME:
- if (ev->xproperty.state == PropertyNewValue
- && XGetWindowProperty (dpy, w->id, ev->xproperty.atom,
- 0, 200, False, AnyPropertyType, &actual,
- &format, &nitems,
- &bytes_after, &prop) == Success
- && actual != None)
- {
- if (format == 8 && !WINDOW_IS_GONE_P (w))
- {
- repv str = Qnil;
- if (actual == xa_compound_text || actual == XA_STRING)
- {
- char **text_list;
- XTextProperty tprop;
- int count;
- tprop.value = prop;
- tprop.encoding = actual;
- tprop.format = format;
- tprop.nitems = strlen (prop);
- if (XmbTextPropertyToTextList (dpy, &tprop,
- &text_list, &count)
- >= Success)
- {
- if (count > 0)
- str = rep_string_dup (text_list[0]);
- XFreeStringList(text_list);
- }
- }
- if (str == Qnil)
- str = rep_null_string ();
-
- if (ev->xproperty.atom == XA_WM_NAME)
- {
- if (Fequal (w->name, str) == Qnil
- || Fequal (w->full_name, str) == Qnil)
- {
- w->full_name = w->name = str;
- need_refresh = TRUE;
- }
- else
- changed = FALSE;
- }
- else
- {
- if (Fequal (w->icon_name, str) == Qnil)
- {
- w->icon_name = str;
- need_refresh = TRUE;
- }
- else
- changed = FALSE;
- }
- }
- XFree (prop);
- }
- break;
-
case XA_WM_HINTS:
old_urgency = w->wmhints != 0 && w->wmhints->flags & XUrgencyHint;
if (w->wmhints != 0)
@@ -571,7 +610,15 @@ property_notify (XEvent *ev)
break;
default:
- if (ev->xproperty.atom == xa_wm_colormap_windows)
+ if (ev->xproperty.atom == XA_WM_NAME ||
+ ev->xproperty.atom == XA_WM_ICON_NAME ||
+ ev->xproperty.atom == xa_wm_net_name ||
+ ev->xproperty.atom == xa_wm_net_icon_name )
+ {
+ need_refresh = changed =
+ update_window_name(w, ev->xproperty);
+ }
+ else if (ev->xproperty.atom == xa_wm_colormap_windows)
{
if (w->n_cmap_windows > 0)
XFree (w->cmap_windows);
diff --git a/src/fonts.c b/src/fonts.c
index 474aa62..9195733 100644
--- a/src/fonts.c
+++ b/src/fonts.c
@@ -311,7 +311,11 @@ fontset_finalize (Lisp_Font *f)
static int
fontset_measure (Lisp_Font *f, u_char *string, size_t length)
{
+#ifdef X_HAVE_UTF8_STRING
+ return Xutf8TextEscapement (f->font, string, length);
+#else
return XmbTextEscapement (f->font, string, length);
+#endif
}
static void
@@ -322,8 +326,11 @@ fontset_draw (Lisp_Font *f, u_char *string, size_t length,
gcv.foreground = fg->pixel;
XChangeGC (dpy, gc, GCForeground, &gcv);
-
+#ifdef X_HAVE_UTF8_STRING
+ Xutf8DrawString (dpy, id, f->font, gc, x, y, string, length);
+#else
XmbDrawString (dpy, id, f->font, gc, x, y, string, length);
+#endif
}
static const Lisp_Font_Class fontset_class = {
@@ -365,7 +372,7 @@ xft_measure (Lisp_Font *f, u_char *string, size_t length)
{
XGlyphInfo info;
- XftTextExtents8 (dpy, f->font, string, length, &info);
+ XftTextExtentsUtf8 (dpy, f->font, string, length, &info);
return info.xOff;
}
@@ -389,8 +396,8 @@ xft_draw (Lisp_Font *f, u_char *string, size_t length,
xft_color.color.blue = fg->blue;
xft_color.color.alpha = fg->alpha;
- XftDrawString8 (draw, &xft_color, f->font,
- x, y, string, length);
+ XftDrawStringUtf8 (draw, &xft_color, f->font,
+ x, y, string, length);
}
static const Lisp_Font_Class xft_class = {
@@ -475,24 +482,14 @@ pango_finalize (Lisp_Font *f)
static int
pango_measure (Lisp_Font *f, u_char *string, size_t length)
{
- gsize r, w;
- u_char *utf8str;
PangoLayout *layout;
PangoRectangle rect;
- utf8str = g_locale_to_utf8 (string, length, &r, &w, NULL);
- if (utf8str != NULL)
- {
- string = utf8str;
- length = w;
- }
-
layout = pango_layout_new (pango_context);
pango_layout_set_text (layout, string, length);
pango_layout_get_extents (layout, NULL, &rect);
- g_free (utf8str);
g_object_unref (layout);
return rect.width / PANGO_SCALE;
@@ -529,8 +526,6 @@ pango_draw (Lisp_Font *f, u_char *string, size_t length,
{
static XftDraw *draw;
XftColor xft_color;
- gsize r, w;
- u_char *utf8str;
PangoLayout *layout;
PangoLayoutIter *iter;
@@ -545,13 +540,6 @@ pango_draw (Lisp_Font *f, u_char *string, size_t length,
xft_color.color.blue = fg->blue;
xft_color.color.alpha = fg->alpha;
- utf8str = g_locale_to_utf8 (string, length, &r, &w, NULL);
- if (utf8str != NULL)
- {
- string = utf8str;
- length = w;
- }
-
layout = pango_layout_new (pango_context);
pango_layout_set_text (layout, string, length);
iter = pango_layout_get_iter (layout);
@@ -565,7 +553,6 @@ pango_draw (Lisp_Font *f, u_char *string, size_t length,
line, x + rect.x / PANGO_SCALE, y);
} while (pango_layout_iter_next_line (iter));
- g_free (utf8str);
g_object_unref (layout);
pango_layout_iter_free (iter);
}
diff --git a/src/sawmill.h b/src/sawmill.h
index 2cff9f3..08caa31 100644
--- a/src/sawmill.h
+++ b/src/sawmill.h
@@ -147,6 +147,7 @@ typedef struct lisp_window {
Window *cmap_windows;
int n_cmap_windows;
repv full_name, name, icon_name;
+ repv net_name, net_icon_name;
int frame_vis;
repv icon_image;
diff --git a/src/sawmill_subrs.h b/src/sawmill_subrs.h
index 19c7a50..4dfa62d 100644
--- a/src/sawmill_subrs.h
+++ b/src/sawmill_subrs.h
@@ -57,7 +57,7 @@ extern Visual *preferred_visual;
extern Window root_window, no_focus_window;
extern Atom xa_wm_state, xa_wm_change_state, xa_wm_protocols,
xa_wm_delete_window, xa_wm_colormap_windows, xa_wm_take_focus,
- xa_compound_text;
+ xa_compound_text, xa_wm_net_name, xa_wm_net_icon_name, xa_utf8_string;
extern int shape_event_base, shape_error_base;
extern repv Qdisplay_name, Qcanonical_display_name;
extern bool sys_init (char *program_name);
diff --git a/src/windows.c b/src/windows.c
index 0c4f925..d35ab6f 100644
--- a/src/windows.c
+++ b/src/windows.c
@@ -356,6 +356,80 @@ remove_window_frame (Lisp_Window *w)
}
}
+
+#ifdef X_HAVE_UTF8_STRING
+static repv
+text_prop_to_utf8 (XTextProperty *prop)
+{
+ repv rval = Qnil;
+ if (prop->value && prop->nitems > 0)
+ {
+ char **list;
+ int count;
+ prop->nitems = strlen(prop->value);
+ if (Xutf8TextPropertyToTextList (dpy, prop, &list, &count) >= Success)
+ {
+ if (count > 0)
+ rval = rep_string_dup (list[0]);
+ XFreeStringList (list);
+ }
+ }
+ return rval;
+}
+#else
+static repv
+text_prop_to_utf8 (XTextProperty *prop)
+{
+ if (prop->value && prop->nitems > 0)
+ {
+ repv rval = Qnil;
+ char **list;
+ int count;
+ prop.nitems = strlen(prop.value);
+ if (XmbTextPropertyToTextList (dpy, &prop, &list, &count)
+ >= Success)
+ {
+ if (count > 0) {
+ gchar *ustr = g_locale_to_utf8(list[0], -1, NULL, NULL, NULL);
+ if (ustr)
+ {
+ rval = rep_string_dup(ustr);
+ g_free (ustr);
+ }
+ }
+ XFreeStringList (list);
+ }
+ }
+ return rval;
+}
+#endif
+
+
+/* Queries X properties to get the window {icon,}name */
+static void
+get_window_name(Lisp_Window *w)
+{
+ XTextProperty prop;
+
+ /* We only try to use the utf8 properties if our xlib supports them.
+ Otherwise conversion would have to go via the current locale, which
+ might lose some characters. */
+#ifdef X_HAVE_UTF8_STRING
+ if (XGetTextProperty (dpy, w->id, &prop, xa_wm_net_name))
+ w->net_name = text_prop_to_utf8 (&prop);
+ if (XGetTextProperty (dpy, w->id, &prop, xa_wm_net_icon_name))
+ w->net_icon_name = text_prop_to_utf8 (&prop);
+#endif
+
+ if (w->net_name == Qnil && XGetWMName (dpy, w->id, &prop))
+ w->net_name = text_prop_to_utf8 (&prop);
+ w->full_name = w->name;
+
+ if (w->net_icon_name == Qnil && XGetWMIconName (dpy, w->id, &prop))
+ w->icon_name = text_prop_to_utf8 (&prop);
+}
+
+
/* Add the top-level window ID to the manager's data structures */
Lisp_Window *
add_window (Window id)
@@ -369,7 +443,6 @@ add_window (Window id)
XWindowChanges xwc;
u_int xwcm;
long supplied;
- XTextProperty prop;
DB(("add_window (%lx)\n", id));
@@ -389,6 +462,8 @@ add_window (Window id)
w->frame_style = Qnil;;
w->icon_image = rep_NULL;
w->name = rep_null_string ();
+ w->net_name = Qnil;
+ w->net_icon_name = Qnil;
/* have to put it somewhere until it finds the right place */
insert_in_stacking_list_above_all (w);
@@ -401,31 +476,7 @@ add_window (Window id)
DB((" orig: width=%d height=%d x=%d y=%d\n",
w->attr.width, w->attr.height, w->attr.x, w->attr.y));
- if (XGetWMName (dpy, id, &prop) && prop.value)
- {
- if (prop.nitems > 0)
- {
- char **list;
- int count;
- prop.nitems = strlen(prop.value);
- if (XmbTextPropertyToTextList (dpy, &prop, &list, &count)
- >= Success)
- {
- if (count > 0)
- w->name = rep_string_dup (list[0]);
- XFreeStringList (list);
- }
- }
- XFree (prop.value);
- }
- w->full_name = w->name;
- if (XGetIconName (dpy, id, &tem))
- {
- w->icon_name = rep_string_dup (tem);
- XFree (tem);
- }
- else
- w->icon_name = w->name;
+ get_window_name(w);
w->wmhints = XGetWMHints (dpy, id);
if (!XGetWMNormalHints (dpy, w->id, &w->hints, &supplied))
@@ -699,8 +750,10 @@ window-name WINDOW
Return the name of window object WINDOW.
::end:: */
{
+ Lisp_Window * w;
rep_DECLARE1(win, WINDOWP);
- return VWIN(win)->name;
+ w = VWIN(win);
+ return w->net_name != Qnil ? w->net_name : w->name;
}
DEFUN("window-full-name", Fwindow_full_name, Swindow_full_name,
@@ -723,8 +776,10 @@ window-icon-name WINDOW
Return the name of window object WINDOW's icon.
::end:: */
{
+ Lisp_Window * w;
rep_DECLARE1(win, WINDOWP);
- return VWIN(win)->icon_name;
+ w = VWIN(win);
+ return w->net_icon_name != Qnil ? w->net_icon_name : w->icon_name;
}
DEFUN("window-mapped-p", Fwindow_mapped_p, Swindow_mapped_p,
@@ -1419,6 +1474,8 @@ window_mark (repv win)
rep_MARKVAL(VWIN(win)->name);
rep_MARKVAL(VWIN(win)->full_name);
rep_MARKVAL(VWIN(win)->icon_name);
+ rep_MARKVAL(VWIN(win)->net_name);
+ rep_MARKVAL(VWIN(win)->net_icon_name);
rep_MARKVAL(VWIN(win)->icon_image);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]