Luis Rodrigo Gallardo Cruz <[EMAIL PROTECTED]> 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); }
