diff options
Diffstat (limited to 'gdk/win32/gdkproperty-win32.c')
-rw-r--r-- | gdk/win32/gdkproperty-win32.c | 321 |
1 files changed, 283 insertions, 38 deletions
diff --git a/gdk/win32/gdkproperty-win32.c b/gdk/win32/gdkproperty-win32.c index caaa13cc6f..1609d90ff9 100644 --- a/gdk/win32/gdkproperty-win32.c +++ b/gdk/win32/gdkproperty-win32.c @@ -1,5 +1,6 @@ /* GDK - The GIMP Drawing Kit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-2002 Tor Lillqvist * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,6 +26,8 @@ */ #include <string.h> +#include <stdlib.h> +#include <stdio.h> #include "gdkproperty.h" #include "gdkselection.h" @@ -34,9 +37,9 @@ GdkAtom gdk_atom_intern (const gchar *atom_name, gint only_if_exists) { + ATOM win32_atom; GdkAtom retval; static GHashTable *atom_hash = NULL; - ATOM win32_atom; if (!atom_hash) atom_hash = g_hash_table_new (g_str_hash, g_str_equal); @@ -68,17 +71,12 @@ gdk_atom_intern (const gchar *atom_name, retval = GDK_SELECTION_TYPE_STRING; else { - win32_atom = GlobalFindAtom (atom_name); - if (only_if_exists && retval == 0) - win32_atom = 0; - else - win32_atom = GlobalAddAtom (atom_name); + win32_atom = GlobalAddAtom (atom_name); retval = GUINT_TO_POINTER ((guint) win32_atom); } - if (retval != GDK_NONE) - g_hash_table_insert (atom_hash, - g_strdup (atom_name), - retval); + g_hash_table_insert (atom_hash, + g_strdup (atom_name), + retval); } return retval; @@ -87,8 +85,8 @@ gdk_atom_intern (const gchar *atom_name, gchar * gdk_atom_name (GdkAtom atom) { - gchar name[256]; ATOM win32_atom; + gchar name[256]; if (GDK_SELECTION_PRIMARY == atom) return g_strdup ("PRIMARY"); else if (GDK_SELECTION_SECONDARY == atom) return g_strdup ("SECONDARY"); @@ -134,6 +132,108 @@ gdk_property_get (GdkWindow *window, return FALSE; } +static gboolean +find_common_locale (const guchar *data, + gint nelements, + gint nchars, + LCID *lcidp, + guchar **bufp, + gint *sizep) +{ + static struct { + LCID lcid; + UINT cp; + } locales[] = { +#define ENTRY(lang, sublang) \ + { MAKELCID (MAKELANGID (LANG_##lang, SUBLANG_##sublang), SORT_DEFAULT), 0 } + ENTRY (ENGLISH, DEFAULT), + ENTRY (POLISH, DEFAULT), + ENTRY (CZECH, DEFAULT), + ENTRY (LITHUANIAN, DEFAULT), + ENTRY (RUSSIAN, DEFAULT), + ENTRY (GREEK, DEFAULT), + ENTRY (TURKISH, DEFAULT), + ENTRY (HEBREW, DEFAULT), + ENTRY (ARABIC, DEFAULT), + ENTRY (THAI, DEFAULT), + ENTRY (JAPANESE, DEFAULT), + ENTRY (CHINESE, CHINESE_SIMPLIFIED), + ENTRY (CHINESE, CHINESE_TRADITIONAL), + ENTRY (KOREAN, DEFAULT), +#undef ENTRY + }; + + static gboolean been_here = FALSE; + gint i; + wchar_t *wcs; + + /* For each installed locale: Get the locale's default code page, + * and store the list of locales and code pages. + */ + if (!been_here) + { + been_here = TRUE; + for (i = 0; i < G_N_ELEMENTS (locales); i++) + if (IsValidLocale (locales[i].lcid, LCID_INSTALLED)) + { + gchar buf[10]; + if (GetLocaleInfo (locales[i].lcid, LOCALE_IDEFAULTANSICODEPAGE, + buf, sizeof (buf))) + { + gchar name[100]; + locales[i].cp = atoi (buf); + GDK_NOTE (DND, (GetLocaleInfo (locales[i].lcid, + LOCALE_SENGLANGUAGE, + name, sizeof (name)), + g_print ("locale %#lx: %s: CP%d\n", + (gulong) locales[i].lcid, name, + locales[i].cp))); + } + } + } + + /* Allocate bufp big enough to store data in any code page. Two + * bytes for each Unicode char should be enough, Windows code pages + * are either single- or double-byte. + */ + *bufp = g_malloc ((nchars+1) * 2); + wcs = g_new (wchar_t, nchars+1); + + /* Convert to Windows wide chars into temp buf */ + _gdk_utf8_to_ucs2 (wcs, data, nelements, nchars); + wcs[nchars] = 0; + + /* For each code page that is the default for an installed locale: */ + for (i = 0; i < G_N_ELEMENTS (locales); i++) + { + BOOL used_default; + int nbytes; + + if (locales[i].cp == 0) + continue; + + /* Convert to that code page into bufp */ + + nbytes = WideCharToMultiByte (locales[i].cp, 0, wcs, -1, + *bufp, (nchars+1)*2, + NULL, &used_default); + + if (!used_default) + { + /* This locale is good for the string */ + g_free (wcs); + *lcidp = locales[i].lcid; + *sizep = nbytes; + return TRUE; + } + } + + g_free (*bufp); + g_free (wcs); + + return FALSE; +} + void gdk_property_change (GdkWindow *window, GdkAtom property, @@ -143,10 +243,17 @@ gdk_property_change (GdkWindow *window, const guchar *data, gint nelements) { - HGLOBAL hdata; - gint i, length; + HGLOBAL hdata, hlcid, hutf8; + UINT cf = 0; + LCID lcid; + LCID *lcidptr; + GString *rtf = NULL; + gint i, size, nchars; gchar *prop_name, *type_name; - guchar *ptr; + guchar *ucptr, *buf = NULL; + wchar_t *wcptr; + enum { PLAIN_ASCII, UNICODE_TEXT, SINGLE_LOCALE, RICH_TEXT } method; + gboolean ok = TRUE; g_return_if_fail (window != NULL); g_return_if_fail (GDK_IS_WINDOW (window)); @@ -154,7 +261,7 @@ gdk_property_change (GdkWindow *window, if (GDK_WINDOW_DESTROYED (window)) return; - GDK_NOTE (MISC, + GDK_NOTE (DND, (prop_name = gdk_atom_name (property), type_name = gdk_atom_name (type), g_print ("gdk_property_change: %#x %#x (%s) %#x (%s) %s %d*%d bytes %.10s\n", @@ -174,40 +281,178 @@ gdk_property_change (GdkWindow *window, && format == 8 && mode == GDK_PROP_MODE_REPLACE) { - length = nelements; - for (i = 0; i < nelements; i++) - if (data[i] == '\n') - length++; -#if 1 - GDK_NOTE (MISC, g_print ("...OpenClipboard(%#x)\n", - (guint) GDK_WINDOW_HWND (window))); if (!OpenClipboard (GDK_WINDOW_HWND (window))) { WIN32_API_FAILED ("OpenClipboard"); return; } -#endif - hdata = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE, length + 1); - ptr = GlobalLock (hdata); - GDK_NOTE (MISC, g_print ("...hdata=%#x, ptr=%p\n", (guint) hdata, ptr)); + /* Check if only ASCII */ for (i = 0; i < nelements; i++) + if (data[i] >= 0200) + break; + + if (i == nelements) + nchars = nelements; + else + nchars = g_utf8_strlen (data, nelements); + + GDK_NOTE (DND, g_print ("...nchars:%d\n", nchars)); + + if (i == nelements) + { + /* If only ASCII, use CF_TEXT and the data as such. */ + method = PLAIN_ASCII; + size = nelements; + for (i = 0; i < nelements; i++) + if (data[i] == '\n') + size++; + size++; + GDK_NOTE (DND, g_print ("...as text: %.40s\n", data)); + } + else if (IS_WIN_NT ()) + { + /* On NT, use CF_UNICODETEXT if any non-ASCII char present */ + method = UNICODE_TEXT; + size = (nchars + 1) * 2; + GDK_NOTE (DND, g_print ("...as Unicode\n")); + } + else if (find_common_locale (data, nelements, nchars, &lcid, &buf, &size)) + { + /* On Win9x, if all chars are in the default code page of + * some installed locale, use CF_TEXT and CF_LOCALE. + */ + method = SINGLE_LOCALE; + GDK_NOTE (DND, g_print ("...as text in locale %#lx %d bytes\n", + (gulong) lcid, size)); + } + else + { + /* On Win9x, otherwise use RTF */ + + const guchar *p = data; + + method = RICH_TEXT; + rtf = g_string_new ("{\\rtf1\\uc0 "); + + while (p < data + nelements) + { + if (*p == '{' || + *p == '\\' || + *p == '}') + { + rtf = g_string_append_c (rtf, '\\'); + rtf = g_string_append_c (rtf, *p); + p++; + } + else if (*p < 0200) + { + rtf = g_string_append_c (rtf, *p); + p++; + } + else + { + guchar *q; + gint n; + + rtf = g_string_append (rtf, "\\uNNNNN "); + rtf->len -= 6; /* five digits and a space */ + q = rtf->str + rtf->len; + n = sprintf (q, "%d ", g_utf8_get_char (p)); + g_assert (n <= 6); + rtf->len += n; + + p = g_utf8_next_char (p); + } + } + rtf = g_string_append (rtf, "}"); + size = rtf->len + 1; + GDK_NOTE (DND, g_print ("...as RTF: %.40s\n", rtf->str)); + } + + if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, size))) { - if (*data == '\n') - *ptr++ = '\r'; - *ptr++ = *data++; + WIN32_API_FAILED ("GlobalAlloc"); + if (!CloseClipboard ()) + WIN32_API_FAILED ("CloseClipboard"); + if (buf != NULL) + g_free (buf); + if (rtf != NULL) + g_string_free (rtf, TRUE); + return; + } + + ucptr = GlobalLock (hdata); + + switch (method) + { + case PLAIN_ASCII: + cf = CF_TEXT; + for (i = 0; i < nelements; i++) + { + if (*data == '\n') + *ucptr++ = '\r'; + *ucptr++ = data[i]; + } + *ucptr++ = '\0'; + break; + + case UNICODE_TEXT: + cf = CF_UNICODETEXT; + wcptr = (wchar_t *) ucptr; + if (_gdk_utf8_to_ucs2 (wcptr, data, nelements, nchars) == -1) + g_warning ("_gdk_utf8_to_ucs2() failed"); + wcptr[nchars] = 0; + break; + + case SINGLE_LOCALE: + cf = CF_TEXT; + memmove (ucptr, buf, size); + g_free (buf); + + /* Set the CF_LOCALE clipboard data, too */ + if (!(hlcid = GlobalAlloc (GMEM_MOVEABLE, sizeof (LCID)))) + WIN32_API_FAILED ("GlobalAlloc"), ok = FALSE; + if (ok) + { + lcidptr = GlobalLock (hlcid); + *lcidptr = lcid; + GlobalUnlock (hlcid); + if (!SetClipboardData (CF_LOCALE, hlcid)) + WIN32_API_FAILED ("SetClipboardData (CF_LOCALE)"), ok = FALSE; + } + break; + + case RICH_TEXT: + cf = cf_rtf; + memmove (ucptr, rtf->str, size); + g_string_free (rtf, TRUE); + + /* Set the UTF8_STRING clipboard data, too, for other + * GTK+ apps to use (won't bother reading RTF). + */ + if (!(hutf8 = GlobalAlloc (GMEM_MOVEABLE, nelements))) + WIN32_API_FAILED ("GlobalAlloc"); + else + { + guchar *utf8ptr = GlobalLock (hutf8); + memmove (utf8ptr, data, nelements); + GlobalUnlock (hutf8); + if (!SetClipboardData (cf_utf8_string, hutf8)) + WIN32_API_FAILED ("SetClipboardData (UTF8_STRING)"); + } + break; + + default: + g_assert_not_reached (); } - *ptr++ = '\0'; + GlobalUnlock (hdata); - GDK_NOTE (MISC, g_print ("...SetClipboardData(CF_TEXT, %#x)\n", - (guint) hdata)); - if (!SetClipboardData(CF_TEXT, hdata)) - WIN32_API_FAILED ("SetClipboardData"); -#if 1 - GDK_NOTE (MISC, g_print ("...CloseClipboard()\n")); + if (ok && !SetClipboardData (cf, hdata)) + WIN32_API_FAILED ("SetClipboardData"), ok = FALSE; + if (!CloseClipboard ()) WIN32_API_FAILED ("CloseClipboard"); -#endif } else g_warning ("gdk_property_change: General case not implemented"); @@ -222,7 +467,7 @@ gdk_property_delete (GdkWindow *window, g_return_if_fail (window != NULL); g_return_if_fail (GDK_IS_WINDOW (window)); - GDK_NOTE (MISC, + GDK_NOTE (DND, (prop_name = gdk_atom_name (property), g_print ("gdk_property_delete: %#x %#x (%s)\n", (window ? (guint) GDK_WINDOW_HWND (window) : 0), |