Does anyone know X and utf-8? Help us with ui i18n prob.



Hi, all. As I wrote, I finally located the root of the GUI i18n
error. :) (You may already know it, but the symptom is that if the
locale is set, many non-ascii letters in configurator GUI are not
printed.)  It's the communication between gui and sawfish server,
coded in src/libclient.c and src/events.c.

In general, not only configurator, but any sawfish client talks with
the server via client_eval() which is the mere wrapper of
net_server_eval() in libclient.c. There, X event functions are used to
trigger the action of server, and XGetWindowProperty is called to
obtain the return value from server to client. I suspect that the
rewriting of events.c last year which improved utf-8 handling of wm
caused the problem.

Can anyone fix it? It seems to require X event and property knowledge,
and how X treats the encoding. I've attached two patches of last year
which seem to have introduced this problem, hoping they may give
hints. (I don't know X at all. I'm not good at C, but it does not
affect for this issue.)

You can confirm it easily:
1. Export wm-eval in ui/wm.jl,
2. Say, in run-shell in ui/shell.jl, require rep.io.streams and
   sawfish.ui.wm, and eval
    (format standard-error "%s, %s\n"
            "$(D+Q"D$B1+(B" ; or any string
	    (wm-eval "$(D+Q"D$B1+(B")) 
   The former is printed correctly, but the latter which is
   thrown to and back from server gets garbled.
3. wm/customize.jl redirects the output of sawfish-ui to /dev/null, so
   make it spit out to a file.
4. It is triggered when you invoke the configurator.

There may lie other i18n problems, but this must fix most of them.

Chris wrote:
> You shouldn't have written that mail.
!? 
> I'll burst with curiosity until the patch arrives XD
Are you still alive? Sorry, not patch. ;)

Thank you all, especially Wang Diancheng, Chris, and my loyal servants,
git-grep and format-stderr.

Happy sawfish,
Teika (Teika kazura)
commit ea480fda9b32bb6a02f0485a8f4ccf1e4b0dea67
Author: Janek Kozicki <jkozicki src gnome org>
Date:   Sat Jan 19 12:03:08 2008 +0000

    Net wm properties by Rodrigo Gallardo
    
    This patch makes sawfish use the _NET_WM_NAME properties for window names, as
    mandated by the EWMH spec
    (http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html)
    
    This patch is a bit more invasive that it seems requiered, because, to make it
    work properly in my system I had to make sawfish assume all strings are UTF8
    encoded (see the pieces of the patch touching fonts.c)
    
    Please test it and tell me what breaks. If there are no objections to the
    substance of the patch, I'd still like some feedback on what to do with text
    rendering with "normal" xlfd fonts.
    
    
    GSR-FR comment:
    Probably the sanest solution, just next release will have to be marked with a
    huge "Reencode strings in utf-8".
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
    
    svn path=/trunk/; revision=4211

diff --git a/src/display.c b/src/display.c
index 4e79b6a..eb24853 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 5672db7..0efdb41 100644
--- a/src/events.c
+++ b/src/events.c
@@ -476,6 +476,111 @@ 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))
+    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)
+    {
+      if ( str != Qnil && Fequal (w->net_name, str) == Qnil)
+	{
+	  w->net_name = str;
+	  return TRUE;
+	}
+    }
+  
+  if (xproperty.atom == xa_wm_net_icon_name) 
+    {
+      if ( str != Qnil && Fequal (w->net_icon_name, str) == Qnil)
+	{
+	  w->net_icon_name = str;
+	  return TRUE;
+	}
+    }
+  
+  /* No point in updating the rest if we have the _NET ones. They won't
+     be used anyways. */
+  if (w->net_name != Qnil)
+    return FALSE;
+  
+  if (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 (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)
 {
@@ -489,72 +594,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)
@@ -572,7 +614,16 @@ 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..65d0906 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,7 +396,7 @@ 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,
+    XftDrawStringUtf8 (draw, &xft_color, f->font,
 		    x, y, string, length);
 }
 
@@ -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 737038e..734032c 100644
--- a/src/windows.c
+++ b/src/windows.c
@@ -356,6 +356,85 @@ remove_window_frame (Lisp_Window *w)
     }
 }
 
+/* Queries X properties to get the window {icon,}name */
+static void
+get_window_name(Lisp_Window * w)
+{
+  char *tem;
+  XTextProperty prop;
+
+  /* We only try to use the utf8 properties if our xlib supports them */
+#ifdef X_HAVE_UTF8_STRING
+  if (XGetTextProperty (dpy, w->id, &prop, xa_wm_net_name) && prop.value) {
+    if (prop.nitems > 0)
+      {
+        char **list;
+	int count;
+	prop.nitems = strlen(prop.value);
+	if (Xutf8TextPropertyToTextList (dpy, &prop, &list, &count)
+	    >= Success)
+	  {
+	    if (count > 0)
+	      w->net_name = rep_string_dup (list[0]);
+	    XFreeStringList (list);
+	  }
+      }
+  }
+
+  if (XGetTextProperty (dpy, w->id, &prop, xa_wm_net_icon_name) && prop.value) {
+    if (prop.nitems > 0)
+      {
+        char **list;
+	int count;
+	prop.nitems = strlen(prop.value);
+	if (Xutf8TextPropertyToTextList (dpy, &prop, &list, &count)
+	    >= Success)
+	  {
+	    if (count > 0)
+	      w->net_icon_name = rep_string_dup (list[0]);
+	    XFreeStringList (list);
+	  }
+      }
+  }
+
+  /* If we got the _NET names, there's no point in querying the others, 
+     as they won't be used anyways. */
+  if (w->net_name != Qnil)
+    return;
+
+#endif
+
+  if (XGetWMName (dpy, w->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 (g_locale_to_utf8(list[0],
+							   -1, NULL, NULL, NULL));
+	      XFreeStringList (list);
+	    }
+	}
+      XFree (prop.value);
+    }
+  w->full_name = w->name;
+  
+  if (XGetIconName (dpy, w->id, &tem))
+    {
+      w->icon_name = rep_string_dup (g_locale_to_utf8(tem,
+						      -1, NULL, NULL, NULL));
+      XFree (tem);
+    }
+  else
+    w->icon_name = w->name;
+
+}
+
 /* Add the top-level window ID to the manager's data structures */
 Lisp_Window *
 add_window (Window id)
@@ -369,7 +448,6 @@ add_window (Window id)
 	XWindowChanges xwc;
 	u_int xwcm;
 	long supplied;
-	XTextProperty prop;
 
 	DB(("add_window (%lx)\n", id));
 
@@ -389,6 +467,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 +481,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))
@@ -700,8 +756,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,
@@ -724,8 +782,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,
@@ -1420,6 +1480,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);
 }
 
commit 4192c2c43653b4f66377c81c26a86027064aa99b
Author: Janek Kozicki <jkozicki src gnome org>
Date:   Mon Feb 18 19:27:47 2008 +0000

    patch by Timo Korvola, "Utf 8 names fix",
    
    Patch against 1.3.2. To illustrate the difference, run Sawfish in a non-UTF-8
    locale but with a title font capable of displaying Unicode (I use Freemono),
    start a uxterm and gucharmap, then try xterm -T 'funny characters' and konsole
    -T 'funny characters', where the funny characters are not representable in the
    locale of Sawfish. With the Net_wm_names patch, only konsole gets its title
    rendered correctly but xterm does not. With the attached patch, both windows
    get correct titles.
    
    http://mail.gnome.org/archives/sawfish-list/2008-January/msg00063.html
    http://mail.gnome.org/archives/sawfish-list/2007-October/msg00018.html
    
    
    svn path=/trunk/; revision=4223

diff --git a/src/events.c b/src/events.c
index c86b4fc..4633057 100644
--- a/src/events.c
+++ b/src/events.c
@@ -480,106 +480,110 @@ motion_notify (XEvent *ev)
 
 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))
-    return FALSE;
-
-  tprop.value = prop;
-  tprop.encoding = actual;
-  tprop.format = format;
-  tprop.nitems = strlen (prop);
-
-  if (actual == xa_compound_text || actual == XA_STRING) 
+    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))
     {
-      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);
+        XFree (prop);
+        return FALSE;
     }
 
+    tprop.value = prop;
+    tprop.encoding = actual;
+    tprop.format = format;
+    tprop.nitems = strlen (prop);
+
 #ifdef X_HAVE_UTF8_STRING
-  if (actual == xa_utf8_string) 
+    if (actual == xa_compound_text || actual == XA_STRING
+        || 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);
+    }
+#else
+    if (actual == xa_compound_text || actual == XA_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);
+        convert_status = XmbTextPropertyToTextList (dpy, &tprop, &text_list,
+                                                    &count);
+        if (convert_status >= Success) 
+        {
+            if (count > 0)
+            {
+                char * utf8str = g_locale_to_utf8(text_list[0], -1,
+                                                  NULL, NULL, NULL);
+                if (utf8str)
+                {
+                    str = rep_string_dup (utf8str);
+                    g_free (utf8str);
+                }
+            }
+            XFreeStringList(text_list);
+        }
     }
 #endif
 
-  XFree (prop);
+    XFree (prop);
   
-  if (str == Qnil)
-    return FALSE;
+    if (str == Qnil)
+        return FALSE;
 
-  if (xproperty.atom == xa_wm_net_name)
+    if (xproperty.atom == xa_wm_net_name
+        && str != Qnil && Fequal (w->net_name, str) == Qnil)
     {
-      if ( str != Qnil && Fequal (w->net_name, str) == Qnil)
-	{
-	  w->net_name = str;
-	  return TRUE;
-	}
+        w->net_name = str;
+        return TRUE;
     }
   
-  if (xproperty.atom == xa_wm_net_icon_name) 
+    if (xproperty.atom == xa_wm_net_icon_name
+        && str != Qnil && Fequal (w->net_icon_name, str) == Qnil)
     {
-      if ( str != Qnil && Fequal (w->net_icon_name, str) == Qnil)
-	{
-	  w->net_icon_name = str;
-	  return TRUE;
-	}
+        w->net_icon_name = str;
+        return TRUE;
     }
   
-  /* No point in updating the rest if we have the _NET ones. They won't
-     be used anyways. */
-  if (w->net_name != Qnil)
-    return FALSE;
-  
-  if (xproperty.atom == XA_WM_NAME)
+    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 (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 (xproperty.atom == XA_WM_ICON_NAME)
+    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;
-	}
-    }	  
+        if (str == Qnil)
+            str = rep_null_string ();
+        if (Fequal (w->icon_name, str) == Qnil)
+        {
+            w->icon_name = str;
+            return TRUE;
+        }
+    }    
 
-  return FALSE;
+    return FALSE;
 }
 
 static void
@@ -615,16 +619,15 @@ property_notify (XEvent *ev)
 	    break;
 
 	default:
-
-	    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 (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/windows.c b/src/windows.c
index 3f5d1c4..ee20705 100644
--- a/src/windows.c
+++ b/src/windows.c
@@ -357,85 +357,73 @@ remove_window_frame (Lisp_Window *w)
     }
 }
 
+
+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);
+#ifdef X_HAVE_UTF8_STRING
+        if (Xutf8TextPropertyToTextList (dpy, prop, &list, &count) >= Success)
+        {
+            if (count > 0)
+                rval = rep_string_dup (list[0]);
+            XFreeStringList (list);
+        }
+#else
+        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);
+        }
+#endif
+    }
+    return rval;
+}
+
+
 /* Queries X properties to get the window {icon,}name */
 static void
-get_window_name(Lisp_Window * w)
+get_window_name(Lisp_Window *w)
 {
-  char *tem;
-  XTextProperty prop;
+    XTextProperty prop;
 
-  /* We only try to use the utf8 properties if our xlib supports them */
+    /* 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) && prop.value) {
-    if (prop.nitems > 0)
-      {
-        char **list;
-	int count;
-	prop.nitems = strlen(prop.value);
-	if (Xutf8TextPropertyToTextList (dpy, &prop, &list, &count)
-	    >= Success)
-	  {
-	    if (count > 0)
-	      w->net_name = rep_string_dup (list[0]);
-	    XFreeStringList (list);
-	  }
-      }
-  }
-
-  if (XGetTextProperty (dpy, w->id, &prop, xa_wm_net_icon_name) && prop.value) {
-    if (prop.nitems > 0)
-      {
-        char **list;
-	int count;
-	prop.nitems = strlen(prop.value);
-	if (Xutf8TextPropertyToTextList (dpy, &prop, &list, &count)
-	    >= Success)
-	  {
-	    if (count > 0)
-	      w->net_icon_name = rep_string_dup (list[0]);
-	    XFreeStringList (list);
-	  }
-      }
-  }
-
-  /* If we got the _NET names, there's no point in querying the others, 
-     as they won't be used anyways. */
-  if (w->net_name != Qnil)
-    return;
-
+    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 (XGetWMName (dpy, w->id, &prop) && prop.value)
+    if (w->net_name == Qnil && XGetWMName (dpy, w->id, &prop))
     {
-      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 (g_locale_to_utf8(list[0],
-							   -1, NULL, NULL, NULL));
-	      XFreeStringList (list);
-	    }
-	}
-      XFree (prop.value);
+        repv name = text_prop_to_utf8 (&prop);
+        if (name != Qnil)
+            w->name = name;
     }
-  w->full_name = w->name;
+    w->full_name = w->name;
   
-  if (XGetIconName (dpy, w->id, &tem))
-    {
-      w->icon_name = rep_string_dup (g_locale_to_utf8(tem,
-						      -1, NULL, NULL, NULL));
-      XFree (tem);
-    }
-  else
-    w->icon_name = w->name;
-
+    if (w->net_icon_name == Qnil && XGetWMIconName (dpy, w->id, &prop))
+        w->icon_name = text_prop_to_utf8 (&prop);
+    if (w->icon_name == Qnil)
+        w->icon_name = w->name;
 }
 
+
 /* Add the top-level window ID to the manager's data structures */
 Lisp_Window *
 add_window (Window id)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]