1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 * Copyright (C) 1998-2002 Tor Lillqvist
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
31 #include <glib/gprintf.h>
33 #include "gdkscreen.h"
34 #include "gdkproperty.h"
35 #include "gdkselection.h"
36 #include "gdkprivate-win32.h"
39 gdk_atom_intern (const gchar *atom_name,
44 static GHashTable *atom_hash = NULL;
47 atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
49 retval = g_hash_table_lookup (atom_hash, atom_name);
52 if (strcmp (atom_name, "PRIMARY") == 0)
53 retval = GDK_SELECTION_PRIMARY;
54 else if (strcmp (atom_name, "SECONDARY") == 0)
55 retval = GDK_SELECTION_SECONDARY;
56 else if (strcmp (atom_name, "CLIPBOARD") == 0)
57 retval = GDK_SELECTION_CLIPBOARD;
58 else if (strcmp (atom_name, "ATOM") == 0)
59 retval = GDK_SELECTION_TYPE_ATOM;
60 else if (strcmp (atom_name, "BITMAP") == 0)
61 retval = GDK_SELECTION_TYPE_BITMAP;
62 else if (strcmp (atom_name, "COLORMAP") == 0)
63 retval = GDK_SELECTION_TYPE_COLORMAP;
64 else if (strcmp (atom_name, "DRAWABLE") == 0)
65 retval = GDK_SELECTION_TYPE_DRAWABLE;
66 else if (strcmp (atom_name, "INTEGER") == 0)
67 retval = GDK_SELECTION_TYPE_INTEGER;
68 else if (strcmp (atom_name, "PIXMAP") == 0)
69 retval = GDK_SELECTION_TYPE_PIXMAP;
70 else if (strcmp (atom_name, "WINDOW") == 0)
71 retval = GDK_SELECTION_TYPE_WINDOW;
72 else if (strcmp (atom_name, "STRING") == 0)
73 retval = GDK_SELECTION_TYPE_STRING;
76 win32_atom = GlobalAddAtom (atom_name);
77 retval = GUINT_TO_POINTER ((guint) win32_atom);
79 g_hash_table_insert (atom_hash,
88 gdk_atom_intern_static_string (const gchar *atom_name)
90 /* on X11 this is supposed to save memory. On win32 there seems to be
91 * no way to make a difference ?
93 return gdk_atom_intern (atom_name, FALSE);
97 gdk_atom_name (GdkAtom atom)
102 if (GDK_SELECTION_PRIMARY == atom) return g_strdup ("PRIMARY");
103 else if (GDK_SELECTION_SECONDARY == atom) return g_strdup ("SECONDARY");
104 else if (GDK_SELECTION_CLIPBOARD == atom) return g_strdup ("CLIPBOARD");
105 else if (GDK_SELECTION_TYPE_ATOM == atom) return g_strdup ("ATOM");
106 else if (GDK_SELECTION_TYPE_BITMAP == atom) return g_strdup ("BITMAP");
107 else if (GDK_SELECTION_TYPE_COLORMAP == atom) return g_strdup ("COLORMAP");
108 else if (GDK_SELECTION_TYPE_DRAWABLE == atom) return g_strdup ("DRAWABLE");
109 else if (GDK_SELECTION_TYPE_INTEGER == atom) return g_strdup ("INTEGER");
110 else if (GDK_SELECTION_TYPE_PIXMAP == atom) return g_strdup ("PIXMAP");
111 else if (GDK_SELECTION_TYPE_WINDOW == atom) return g_strdup ("WINDOW");
112 else if (GDK_SELECTION_TYPE_STRING == atom) return g_strdup ("STRING");
114 win32_atom = GPOINTER_TO_UINT (atom);
116 if (win32_atom < 0xC000)
117 return g_strdup_printf ("#%p", atom);
118 else if (GlobalGetAtomName (win32_atom, name, sizeof (name)) == 0)
120 return g_strdup (name);
124 gdk_property_get (GdkWindow *window,
130 GdkAtom *actual_property_type,
131 gint *actual_format_type,
135 g_return_val_if_fail (window != NULL, FALSE);
136 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
138 if (GDK_WINDOW_DESTROYED (window))
141 g_warning ("gdk_property_get: Not implemented");
147 find_common_locale (const guchar *data,
158 #define ENTRY(lang, sublang) \
159 { MAKELCID (MAKELANGID (LANG_##lang, SUBLANG_##sublang), SORT_DEFAULT), 0 }
160 ENTRY (ENGLISH, DEFAULT),
161 ENTRY (POLISH, DEFAULT),
162 ENTRY (CZECH, DEFAULT),
163 ENTRY (LITHUANIAN, DEFAULT),
164 ENTRY (RUSSIAN, DEFAULT),
165 ENTRY (GREEK, DEFAULT),
166 ENTRY (TURKISH, DEFAULT),
167 ENTRY (HEBREW, DEFAULT),
168 ENTRY (ARABIC, DEFAULT),
169 ENTRY (THAI, DEFAULT),
170 ENTRY (JAPANESE, DEFAULT),
171 ENTRY (CHINESE, CHINESE_SIMPLIFIED),
172 ENTRY (CHINESE, CHINESE_TRADITIONAL),
173 ENTRY (KOREAN, DEFAULT),
177 static gboolean been_here = FALSE;
181 /* For each installed locale: Get the locale's default code page,
182 * and store the list of locales and code pages.
187 for (i = 0; i < G_N_ELEMENTS (locales); i++)
188 if (IsValidLocale (locales[i].lcid, LCID_INSTALLED))
191 if (GetLocaleInfo (locales[i].lcid, LOCALE_IDEFAULTANSICODEPAGE,
195 locales[i].cp = atoi (buf);
196 GDK_NOTE (DND, (GetLocaleInfo (locales[i].lcid,
198 name, sizeof (name)),
199 g_print ("locale %#lx: %s: CP%d\n",
200 (gulong) locales[i].lcid, name,
206 /* Allocate bufp big enough to store data in any code page. Two
207 * bytes for each Unicode char should be enough, Windows code pages
208 * are either single- or double-byte.
210 *bufp = g_malloc ((nchars+1)*2);
212 /* Convert to Windows wide chars into temp buf */
213 wcs = g_utf8_to_utf16 (data, nelements, NULL, NULL, NULL);
215 /* For each code page that is the default for an installed locale: */
216 for (i = 0; i < G_N_ELEMENTS (locales); i++)
221 if (locales[i].cp == 0)
224 /* Convert to that code page into bufp */
226 nbytes = WideCharToMultiByte (locales[i].cp, 0, wcs, -1,
228 NULL, &used_default);
232 /* This locale is good for the string */
234 *lcidp = locales[i].lcid;
247 gdk_property_change (GdkWindow *window,
255 HGLOBAL hdata, hlcid, hutf8;
260 gint i, size, nchars;
261 gchar *prop_name, *type_name;
262 guchar *ucptr, *buf = NULL;
265 enum { SYSTEM_CODEPAGE, UNICODE_TEXT, SINGLE_LOCALE, RICH_TEXT } method;
268 g_return_if_fail (window != NULL);
269 g_return_if_fail (GDK_IS_WINDOW (window));
271 if (GDK_WINDOW_DESTROYED (window))
275 (prop_name = gdk_atom_name (property),
276 type_name = gdk_atom_name (type),
277 g_print ("gdk_property_change: %p %#x (%s) %#x (%s) %s %d*%d bytes: %s\n",
278 GDK_WINDOW_HWND (window),
279 (guint) property, prop_name,
280 (guint) type, type_name,
281 (mode == GDK_PROP_MODE_REPLACE ? "REPLACE" :
282 (mode == GDK_PROP_MODE_PREPEND ? "PREPEND" :
283 (mode == GDK_PROP_MODE_APPEND ? "APPEND" :
286 _gdk_win32_data_to_string (data, MIN (10, format*nelements/8))),
288 g_free (type_name)));
290 /* We should never come here for these types */
291 g_return_if_fail (type != GDK_TARGET_STRING);
292 g_return_if_fail (type != _text);
293 g_return_if_fail (type != _compound_text);
294 g_return_if_fail (type != _save_targets);
296 if (property == _gdk_selection_property
298 && mode == GDK_PROP_MODE_REPLACE)
300 if (type == _utf8_string)
302 if (!OpenClipboard (GDK_WINDOW_HWND (window)))
304 WIN32_API_FAILED ("OpenClipboard");
308 nchars = g_utf8_strlen (data, nelements);
310 /* Check if only ASCII */
311 for (i = 0; i < nelements; i++)
317 /* If UTF-8 and only ASCII, use CF_TEXT and the data as
320 method = SYSTEM_CODEPAGE;
322 for (i = 0; i < nelements; i++)
326 GDK_NOTE (DND, g_print ("... as text: %.40s\n", data));
328 else if (G_WIN32_IS_NT_BASED ())
330 /* On NT, use CF_UNICODETEXT if any non-system codepage
333 method = UNICODE_TEXT;
335 wcptr = g_utf8_to_utf16 (data, nelements, NULL, &wclen, NULL);
337 wclen++; /* Terminating 0 */
339 GDK_NOTE (DND, g_print ("... as Unicode\n"));
341 else if (find_common_locale (data, nelements, nchars, &lcid, &buf, &size))
343 /* On Win9x, if all chars are in the default code page
344 * of some installed locale, use CF_TEXT and CF_LOCALE.
346 method = SINGLE_LOCALE;
347 GDK_NOTE (DND, g_print ("... as text in locale %#lx %d bytes\n",
348 (gulong) lcid, size));
352 /* On Win9x, otherwise use RTF */
354 const guchar *p = data;
356 /* WordPad on XP, at least, doesn't seem to grok \uc0
357 * -encoded Unicode characters. Oh well, use \uc1 then,
358 * with a question mark as the "ANSI" stand-in for each
359 * non-ASCII Unicode character. (WordPad for XP? This
360 * code path is for Win9x! Yes, but I don't have Win9x,
361 * so I use XP to test, using the G_WIN32_PRETEND_WIN9X
362 * environment variable.)
365 rtf = g_string_new ("{\\rtf1\\uc1 ");
367 while (p < data + nelements)
373 rtf = g_string_append_c (rtf, '\\');
374 rtf = g_string_append_c (rtf, *p);
377 else if (*p < 0200 && *p >= ' ')
379 rtf = g_string_append_c (rtf, *p);
387 rtf = g_string_append (rtf, "\\uNNNNN ?");
388 rtf->len -= 7; /* five digits a space and a question mark */
389 q = rtf->str + rtf->len;
390 n = g_sprintf (q, "%d ?", g_utf8_get_char (p));
394 p = g_utf8_next_char (p);
397 rtf = g_string_append (rtf, "}");
399 GDK_NOTE (DND, g_print ("... as RTF: %.40s\n", rtf->str));
402 if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, size)))
404 WIN32_API_FAILED ("GlobalAlloc");
405 if (!CloseClipboard ())
406 WIN32_API_FAILED ("CloseClipboard");
410 g_string_free (rtf, TRUE);
414 ucptr = GlobalLock (hdata);
418 case SYSTEM_CODEPAGE:
420 for (i = 0; i < nelements; i++)
431 memmove (ucptr, wcptr, size);
437 memmove (ucptr, buf, size);
440 /* Set the CF_LOCALE clipboard data, too */
441 if (!(hlcid = GlobalAlloc (GMEM_MOVEABLE, sizeof (LCID))))
442 WIN32_API_FAILED ("GlobalAlloc"), ok = FALSE;
445 lcidptr = GlobalLock (hlcid);
447 GlobalUnlock (hlcid);
448 GDK_NOTE (DND, g_print ("... SetClipboardData(CF_LOCALE,%p)\n",
450 if (!SetClipboardData (CF_LOCALE, hlcid))
451 WIN32_API_FAILED ("SetClipboardData(CF_LOCALE)"), ok = FALSE;
457 memmove (ucptr, rtf->str, size);
458 g_string_free (rtf, TRUE);
460 /* Set the UTF8_STRING clipboard data, too, for other
461 * GTK+ apps to use (won't bother reading RTF).
463 if (!(hutf8 = GlobalAlloc (GMEM_MOVEABLE, nelements)))
464 WIN32_API_FAILED ("GlobalAlloc");
467 guchar *utf8ptr = GlobalLock (hutf8);
468 memmove (utf8ptr, data, nelements);
469 GlobalUnlock (hutf8);
470 GDK_NOTE (DND, g_print ("... SetClipboardData('UTF8_STRING',%p)\n",
472 if (!SetClipboardData (_cf_utf8_string, hutf8))
473 WIN32_API_FAILED ("SetClipboardData('UTF8_STRING')");
478 g_assert_not_reached ();
481 GlobalUnlock (hdata);
482 GDK_NOTE (DND, g_print ("... SetClipboardData(%s,%p)\n",
483 _gdk_win32_cf_to_string (cf), hdata));
484 if (ok && !SetClipboardData (cf, hdata))
485 WIN32_API_FAILED ("SetClipboardData"), ok = FALSE;
487 if (!CloseClipboard ())
488 WIN32_API_FAILED ("CloseClipboard");
492 GDK_NOTE (DND, g_print ("... delayed rendering\n"));
493 /* Delayed Rendering. We can't assign hdata to the clipboard
494 * here as type may be "image/png", "image/jpg", etc. In
495 * this case there's a further conversion afterwards.
497 _delayed_rendering_data = NULL;
498 if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, nelements > 0 ? nelements : 1)))
500 WIN32_API_FAILED ("GlobalAlloc");
503 ucptr = GlobalLock (hdata);
504 memcpy (ucptr, data, nelements);
505 GlobalUnlock (hdata);
506 _delayed_rendering_data = hdata;
510 g_warning ("gdk_property_change: General case not implemented");
514 gdk_property_delete (GdkWindow *window,
519 g_return_if_fail (window != NULL);
520 g_return_if_fail (GDK_IS_WINDOW (window));
523 (prop_name = gdk_atom_name (property),
524 g_print ("gdk_property_delete: %p %#x (%s)\n",
525 GDK_WINDOW_HWND (window),
526 (guint) property, prop_name),
527 g_free (prop_name)));
529 if (property == _gdk_selection_property)
530 _gdk_selection_property_delete (window);
531 else if (property == _wm_transient_for)
532 gdk_window_set_transient_for (window, _gdk_root);
535 prop_name = gdk_atom_name (property);
536 g_warning ("gdk_property_delete: General case (%s) not implemented",
543 for reference copied from gdk/x11/gdkevents-x11.c
545 { "Net/DoubleClickTime", "gtk-double-click-time" },
546 { "Net/DoubleClickDistance", "gtk-double-click-distance" },
547 { "Net/DndDragThreshold", "gtk-dnd-drag-threshold" },
548 { "Gtk/CanChangeAccels", "gtk-can-change-accels" },
549 { "Gtk/ColorPalette", "gtk-color-palette" },
550 { "Gtk/FontName", "gtk-font-name" },
551 { "Gtk/IconSizes", "gtk-icon-sizes" },
552 { "Gtk/KeyThemeName", "gtk-key-theme-name" },
553 { "Gtk/ToolbarStyle", "gtk-toolbar-style" },
554 { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" },
555 { "Gtk/IMPreeditStyle", "gtk-im-preedit-style" },
556 { "Gtk/IMStatusStyle", "gtk-im-status-style" },
557 { "Net/CursorBlink", "gtk-cursor-blink" },
558 { "Net/CursorBlinkTime", "gtk-cursor-blink-time" },
559 { "Net/ThemeName", "gtk-theme-name" },
560 { "Net/IconThemeName", "gtk-icon-theme-name" },
561 { "Gtk/ButtonImages", "gtk-button-images" },
562 { "Gtk/MenuImages", "gtk-menu-images" },
563 { "Xft/Antialias", "gtk-xft-antialias" },
564 { "Xft/Hinting", "gtk-xft-hinting" },
565 { "Xft/HintStyle", "gtk-xft-hintstyle" },
566 { "Xft/RGBA", "gtk-xft-rgba" },
567 { "Xft/DPI", "gtk-xft-dpi" },
569 // more spread in gtk sources
570 gtk-entry-select-on-focus
572 gtk-cursor-blink-time
577 gdk_screen_get_setting (GdkScreen *screen,
581 g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
584 * XXX : if these values get changed through the Windoze UI the
585 * respective gdk_events are not generated yet.
587 if (strcmp ("gtk-theme-name", name) == 0)
589 g_value_set_string (value, "ms-windows");
591 else if (strcmp ("gtk-double-click-time", name) == 0)
593 gint i = GetDoubleClickTime ();
594 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %d\n", name, i));
595 g_value_set_int (value, i);
598 else if (strcmp ("gtk-double-click-distance", name) == 0)
600 gint i = MAX(GetSystemMetrics (SM_CXDOUBLECLK), GetSystemMetrics (SM_CYDOUBLECLK));
601 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %d\n", name, i));
602 g_value_set_int (value, i);
605 else if (strcmp ("gtk-dnd-drag-threshold", name) == 0)
607 gint i = MAX(GetSystemMetrics (SM_CXDRAG), GetSystemMetrics (SM_CYDRAG));
608 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %d\n", name, i));
609 g_value_set_int (value, i);
612 else if (strcmp ("gtk-split-cursor", name) == 0)
614 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : FALSE\n", name));
615 g_value_set_boolean (value, FALSE);
618 else if (strcmp ("gtk-alternative-button-order", name) == 0)
620 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : TRUE\n", name));
621 g_value_set_boolean (value, TRUE);
626 * With 'MS Sans Serif' as windows menu font (default on win98se) you'll get a
628 * WARNING **: Couldn't load font "MS Sans Serif 8" falling back to "Sans 8"
629 * at least with testfilechooser (regardless of the bitmap check below)
630 * so just disabling this code seems to be the best we can do --hb
632 else if (strcmp ("gtk-font-name", name) == 0)
634 NONCLIENTMETRICS ncm;
635 ncm.cbSize = sizeof(NONCLIENTMETRICS);
636 if (SystemParametersInfo (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, FALSE))
638 /* Pango finally uses GetDeviceCaps to scale, we use simple
639 * approximation here.
641 int nHeight = (0 > ncm.lfMenuFont.lfHeight ? -3*ncm.lfMenuFont.lfHeight/4 : 10);
642 if (OUT_STRING_PRECIS == ncm.lfMenuFont.lfOutPrecision)
643 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(%s) : ignoring bitmap font '%s'\n",
644 name, ncm.lfMenuFont.lfFaceName));
645 else if (ncm.lfMenuFont.lfFaceName && strlen(ncm.lfMenuFont.lfFaceName) > 0 &&
646 /* Avoid issues like those described in bug #135098 */
647 g_utf8_validate (ncm.lfMenuFont.lfFaceName, -1, NULL))
649 char* s = g_strdup_printf ("%s %d", ncm.lfMenuFont.lfFaceName, nHeight);
650 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(%s) : %s\n", name, s));
651 g_value_set_string (value, s);
660 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(%s) not handled\n", name));