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_name (GdkAtom atom)
93 if (GDK_SELECTION_PRIMARY == atom) return g_strdup ("PRIMARY");
94 else if (GDK_SELECTION_SECONDARY == atom) return g_strdup ("SECONDARY");
95 else if (GDK_SELECTION_CLIPBOARD == atom) return g_strdup ("CLIPBOARD");
96 else if (GDK_SELECTION_TYPE_ATOM == atom) return g_strdup ("ATOM");
97 else if (GDK_SELECTION_TYPE_BITMAP == atom) return g_strdup ("BITMAP");
98 else if (GDK_SELECTION_TYPE_COLORMAP == atom) return g_strdup ("COLORMAP");
99 else if (GDK_SELECTION_TYPE_DRAWABLE == atom) return g_strdup ("DRAWABLE");
100 else if (GDK_SELECTION_TYPE_INTEGER == atom) return g_strdup ("INTEGER");
101 else if (GDK_SELECTION_TYPE_PIXMAP == atom) return g_strdup ("PIXMAP");
102 else if (GDK_SELECTION_TYPE_WINDOW == atom) return g_strdup ("WINDOW");
103 else if (GDK_SELECTION_TYPE_STRING == atom) return g_strdup ("STRING");
105 win32_atom = GPOINTER_TO_UINT (atom);
107 if (win32_atom < 0xC000)
108 return g_strdup_printf ("#%p", atom);
109 else if (GlobalGetAtomName (win32_atom, name, sizeof (name)) == 0)
111 return g_strdup (name);
115 gdk_property_get (GdkWindow *window,
121 GdkAtom *actual_property_type,
122 gint *actual_format_type,
126 g_return_val_if_fail (window != NULL, FALSE);
127 g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
129 if (GDK_WINDOW_DESTROYED (window))
132 g_warning ("gdk_property_get: Not implemented");
138 find_common_locale (const guchar *data,
149 #define ENTRY(lang, sublang) \
150 { MAKELCID (MAKELANGID (LANG_##lang, SUBLANG_##sublang), SORT_DEFAULT), 0 }
151 ENTRY (ENGLISH, DEFAULT),
152 ENTRY (POLISH, DEFAULT),
153 ENTRY (CZECH, DEFAULT),
154 ENTRY (LITHUANIAN, DEFAULT),
155 ENTRY (RUSSIAN, DEFAULT),
156 ENTRY (GREEK, DEFAULT),
157 ENTRY (TURKISH, DEFAULT),
158 ENTRY (HEBREW, DEFAULT),
159 ENTRY (ARABIC, DEFAULT),
160 ENTRY (THAI, DEFAULT),
161 ENTRY (JAPANESE, DEFAULT),
162 ENTRY (CHINESE, CHINESE_SIMPLIFIED),
163 ENTRY (CHINESE, CHINESE_TRADITIONAL),
164 ENTRY (KOREAN, DEFAULT),
168 static gboolean been_here = FALSE;
172 /* For each installed locale: Get the locale's default code page,
173 * and store the list of locales and code pages.
178 for (i = 0; i < G_N_ELEMENTS (locales); i++)
179 if (IsValidLocale (locales[i].lcid, LCID_INSTALLED))
182 if (GetLocaleInfo (locales[i].lcid, LOCALE_IDEFAULTANSICODEPAGE,
186 locales[i].cp = atoi (buf);
187 GDK_NOTE (DND, (GetLocaleInfo (locales[i].lcid,
189 name, sizeof (name)),
190 g_print ("locale %#lx: %s: CP%d\n",
191 (gulong) locales[i].lcid, name,
197 /* Allocate bufp big enough to store data in any code page. Two
198 * bytes for each Unicode char should be enough, Windows code pages
199 * are either single- or double-byte.
201 *bufp = g_malloc ((nchars+1)*2);
203 /* Convert to Windows wide chars into temp buf */
204 wcs = g_utf8_to_utf16 (data, nelements, NULL, NULL, NULL);
206 /* For each code page that is the default for an installed locale: */
207 for (i = 0; i < G_N_ELEMENTS (locales); i++)
212 if (locales[i].cp == 0)
215 /* Convert to that code page into bufp */
217 nbytes = WideCharToMultiByte (locales[i].cp, 0, wcs, -1,
219 NULL, &used_default);
223 /* This locale is good for the string */
225 *lcidp = locales[i].lcid;
238 gdk_property_change (GdkWindow *window,
246 HGLOBAL hdata, hlcid, hutf8;
251 gint i, size, nchars;
252 gchar *prop_name, *type_name;
253 guchar *ucptr, *buf = NULL;
256 enum { SYSTEM_CODEPAGE, UNICODE_TEXT, SINGLE_LOCALE, RICH_TEXT } method;
259 g_return_if_fail (window != NULL);
260 g_return_if_fail (GDK_IS_WINDOW (window));
262 if (GDK_WINDOW_DESTROYED (window))
266 (prop_name = gdk_atom_name (property),
267 type_name = gdk_atom_name (type),
268 g_print ("gdk_property_change: %p %#x (%s) %#x (%s) %s %d*%d bytes: %s\n",
269 GDK_WINDOW_HWND (window),
270 (guint) property, prop_name,
271 (guint) type, type_name,
272 (mode == GDK_PROP_MODE_REPLACE ? "REPLACE" :
273 (mode == GDK_PROP_MODE_PREPEND ? "PREPEND" :
274 (mode == GDK_PROP_MODE_APPEND ? "APPEND" :
277 _gdk_win32_data_to_string (data, MIN (10, format*nelements/8))),
279 g_free (type_name)));
281 if (property == _gdk_selection_property
283 && mode == GDK_PROP_MODE_REPLACE)
285 if ((type == GDK_TARGET_STRING && GetACP () == 1252) ||
286 type == _utf8_string)
288 if (!OpenClipboard (GDK_WINDOW_HWND (window)))
290 WIN32_API_FAILED ("OpenClipboard");
294 if (type == _utf8_string)
296 /* Check if only ASCII */
297 for (i = 0; i < nelements; i++)
301 else /* if (type == GDK_TARGET_STRING) */
303 /* Check that no 0200..0240 chars present, as they
304 * differ between ISO-8859-1 and CP1252.
306 for (i = 0; i < nelements; i++)
307 if (data[i] >= 0200 && data[i] < 0240)
310 nchars = g_utf8_strlen (data, nelements);
314 /* If UTF-8 and only ASCII, or if STRING (ISO-8859-1)
315 * and system codepage is CP1252, use CF_TEXT and the
318 method = SYSTEM_CODEPAGE;
320 for (i = 0; i < nelements; i++)
324 GDK_NOTE (DND, g_print ("... as text: %.40s\n", data));
326 else if (G_WIN32_IS_NT_BASED ())
328 /* On NT, use CF_UNICODETEXT if any non-system codepage
331 method = UNICODE_TEXT;
333 wcptr = g_utf8_to_utf16 (data, nelements, NULL, &wclen, NULL);
335 wclen++; /* Terminating 0 */
337 GDK_NOTE (DND, g_print ("... as Unicode\n"));
339 else if (find_common_locale (data, nelements, nchars, &lcid, &buf, &size))
341 /* On Win9x, if all chars are in the default code page
342 * of some installed locale, use CF_TEXT and CF_LOCALE.
344 method = SINGLE_LOCALE;
345 GDK_NOTE (DND, g_print ("... as text in locale %#lx %d bytes\n",
346 (gulong) lcid, size));
350 /* On Win9x, otherwise use RTF */
352 const guchar *p = data;
355 rtf = g_string_new ("{\\rtf1\\uc0 ");
357 while (p < data + nelements)
363 rtf = g_string_append_c (rtf, '\\');
364 rtf = g_string_append_c (rtf, *p);
367 else if (*p < 0200 && *p >= ' ')
369 rtf = g_string_append_c (rtf, *p);
377 rtf = g_string_append (rtf, "\\uNNNNN ");
378 rtf->len -= 6; /* five digits and a space */
379 q = rtf->str + rtf->len;
380 n = g_sprintf (q, "%d ", g_utf8_get_char (p));
384 p = g_utf8_next_char (p);
387 rtf = g_string_append (rtf, "}");
389 GDK_NOTE (DND, g_print ("... as RTF: %.40s\n", rtf->str));
392 if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, size)))
394 WIN32_API_FAILED ("GlobalAlloc");
395 if (!CloseClipboard ())
396 WIN32_API_FAILED ("CloseClipboard");
400 g_string_free (rtf, TRUE);
404 ucptr = GlobalLock (hdata);
408 case SYSTEM_CODEPAGE:
410 for (i = 0; i < nelements; i++)
421 memmove (ucptr, wcptr, size);
427 memmove (ucptr, buf, size);
430 /* Set the CF_LOCALE clipboard data, too */
431 if (!(hlcid = GlobalAlloc (GMEM_MOVEABLE, sizeof (LCID))))
432 WIN32_API_FAILED ("GlobalAlloc"), ok = FALSE;
435 lcidptr = GlobalLock (hlcid);
437 GlobalUnlock (hlcid);
438 if (!SetClipboardData (CF_LOCALE, hlcid))
439 WIN32_API_FAILED ("SetClipboardData (CF_LOCALE)"), ok = FALSE;
445 memmove (ucptr, rtf->str, size);
446 g_string_free (rtf, TRUE);
448 /* Set the UTF8_STRING clipboard data, too, for other
449 * GTK+ apps to use (won't bother reading RTF).
451 if (!(hutf8 = GlobalAlloc (GMEM_MOVEABLE, nelements)))
452 WIN32_API_FAILED ("GlobalAlloc");
455 guchar *utf8ptr = GlobalLock (hutf8);
456 memmove (utf8ptr, data, nelements);
457 GlobalUnlock (hutf8);
458 if (!SetClipboardData (_cf_utf8_string, hutf8))
459 WIN32_API_FAILED ("SetClipboardData (UTF8_STRING)");
464 g_assert_not_reached ();
467 GlobalUnlock (hdata);
468 if (ok && !SetClipboardData (cf, hdata))
469 WIN32_API_FAILED ("SetClipboardData"), ok = FALSE;
471 if (!CloseClipboard ())
472 WIN32_API_FAILED ("CloseClipboard");
476 /* Delayed Rendering. We can't assign hdata to the clipboard
477 * here as type may be "image/png", "image/jpg", etc. In
478 * this case there's a further conversion afterwards.
480 _delayed_rendering_data = NULL;
481 if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, nelements > 0 ? nelements : 1)))
483 WIN32_API_FAILED ("GlobalAlloc");
486 ucptr = GlobalLock (hdata);
487 memcpy (ucptr, data, nelements);
488 GlobalUnlock (hdata);
489 _delayed_rendering_data = hdata;
493 g_warning ("gdk_property_change: General case not implemented");
497 gdk_property_delete (GdkWindow *window,
502 g_return_if_fail (window != NULL);
503 g_return_if_fail (GDK_IS_WINDOW (window));
506 (prop_name = gdk_atom_name (property),
507 g_print ("gdk_property_delete: %p %#x (%s)\n",
508 GDK_WINDOW_HWND (window),
509 (guint) property, prop_name),
510 g_free (prop_name)));
512 if (property == _gdk_selection_property)
513 _gdk_selection_property_delete (window);
514 else if (property == _wm_transient_for)
515 gdk_window_set_transient_for (window, _gdk_root);
518 prop_name = gdk_atom_name (property);
519 g_warning ("gdk_property_delete: General case (%s) not implemented",
526 for reference copied from gdk/x11/gdkevents-x11.c
528 { "Net/DoubleClickTime", "gtk-double-click-time" },
529 { "Net/DoubleClickDistance", "gtk-double-click-distance" },
530 { "Net/DndDragThreshold", "gtk-dnd-drag-threshold" },
531 { "Gtk/CanChangeAccels", "gtk-can-change-accels" },
532 { "Gtk/ColorPalette", "gtk-color-palette" },
533 { "Gtk/FontName", "gtk-font-name" },
534 { "Gtk/IconSizes", "gtk-icon-sizes" },
535 { "Gtk/KeyThemeName", "gtk-key-theme-name" },
536 { "Gtk/ToolbarStyle", "gtk-toolbar-style" },
537 { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" },
538 { "Gtk/IMPreeditStyle", "gtk-im-preedit-style" },
539 { "Gtk/IMStatusStyle", "gtk-im-status-style" },
540 { "Net/CursorBlink", "gtk-cursor-blink" },
541 { "Net/CursorBlinkTime", "gtk-cursor-blink-time" },
542 { "Net/ThemeName", "gtk-theme-name" },
543 { "Net/IconThemeName", "gtk-icon-theme-name" },
544 { "Gtk/ButtonImages", "gtk-button-images" },
545 { "Gtk/MenuImages", "gtk-menu-images" },
546 { "Xft/Antialias", "gtk-xft-antialias" },
547 { "Xft/Hinting", "gtk-xft-hinting" },
548 { "Xft/HintStyle", "gtk-xft-hintstyle" },
549 { "Xft/RGBA", "gtk-xft-rgba" },
550 { "Xft/DPI", "gtk-xft-dpi" },
552 // more spread in gtk sources
553 gtk-entry-select-on-focus
555 gtk-cursor-blink-time
560 gdk_screen_get_setting (GdkScreen *screen,
564 g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
567 * XXX : if these values get changed through the Windoze UI the
568 * respective gdk_events are not generated yet.
570 if (strcmp ("gtk-theme-name", name) == 0)
572 g_value_set_string (value, "ms-windows");
574 else if (strcmp ("gtk-double-click-time", name) == 0)
576 gint i = GetDoubleClickTime ();
577 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %d\n", name, i));
578 g_value_set_int (value, i);
581 else if (strcmp ("gtk-double-click-distance", name) == 0)
583 gint i = MAX(GetSystemMetrics (SM_CXDOUBLECLK), GetSystemMetrics (SM_CYDOUBLECLK));
584 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %d\n", name, i));
585 g_value_set_int (value, i);
588 else if (strcmp ("gtk-dnd-drag-threshold", name) == 0)
590 gint i = MAX(GetSystemMetrics (SM_CXDRAG), GetSystemMetrics (SM_CYDRAG));
591 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %d\n", name, i));
592 g_value_set_int (value, i);
595 else if (strcmp ("gtk-split-cursor", name) == 0)
597 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : FALSE\n", name));
598 g_value_set_boolean (value, FALSE);
603 * With 'MS Sans Serif' as windows menu font (default on win98se) you'll get a
605 * WARNING **: Couldn't load font "MS Sans Serif 8" falling back to "Sans 8"
606 * at least with testfilechooser (regardless of the bitmap check below)
607 * so just disabling this code seems to be the best we can do --hb
609 else if (strcmp ("gtk-font-name", name) == 0)
611 NONCLIENTMETRICS ncm;
612 ncm.cbSize = sizeof(NONCLIENTMETRICS);
613 if (SystemParametersInfo (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, FALSE))
615 /* Pango finally uses GetDeviceCaps to scale, we use simple
616 * approximation here.
618 int nHeight = (0 > ncm.lfMenuFont.lfHeight ? -3*ncm.lfMenuFont.lfHeight/4 : 10);
619 if (OUT_STRING_PRECIS == ncm.lfMenuFont.lfOutPrecision)
620 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(%s) : ignoring bitmap font '%s'\n",
621 name, ncm.lfMenuFont.lfFaceName));
622 else if (ncm.lfMenuFont.lfFaceName && strlen(ncm.lfMenuFont.lfFaceName) > 0 &&
623 /* Avoid issues like those described in bug #135098 */
624 g_utf8_validate (ncm.lfMenuFont.lfFaceName, -1, NULL))
626 char* s = g_strdup_printf ("%s %d", ncm.lfMenuFont.lfFaceName, nHeight);
627 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(%s) : %s\n", name, s));
628 g_value_set_string (value, s);
637 GDK_NOTE(MISC, g_print("gdk_screen_get_setting(%s) not handled\n", name));