]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkproperty-win32.c
Work on OLE2-based generic DND
[~andy/gtk] / gdk / win32 / gdkproperty-win32.c
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
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 /*
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/. 
26  */
27
28 #include "config.h"
29 #include <string.h>
30 #include <stdlib.h>
31 #include <glib/gprintf.h>
32
33 #include "gdkscreen.h"
34 #include "gdkproperty.h"
35 #include "gdkselection.h"
36 #include "gdkprivate-win32.h"
37
38 GdkAtom
39 gdk_atom_intern (const gchar *atom_name,
40                  gint         only_if_exists)
41 {
42   ATOM win32_atom;
43   GdkAtom retval;
44   static GHashTable *atom_hash = NULL;
45   
46   if (!atom_hash)
47     atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
48
49   retval = g_hash_table_lookup (atom_hash, atom_name);
50   if (!retval)
51     {
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;
74       else
75         {
76           win32_atom = GlobalAddAtom (atom_name);
77           retval = GUINT_TO_POINTER ((guint) win32_atom);
78         }
79       g_hash_table_insert (atom_hash, 
80                            g_strdup (atom_name), 
81                            retval);
82     }
83
84   return retval;
85 }
86
87 GdkAtom
88 gdk_atom_intern_static_string (const gchar *atom_name)
89 {
90   /* on X11 this is supposed to save memory. On win32 there seems to be
91    * no way to make a difference ?
92    */
93   return gdk_atom_intern (atom_name, FALSE);
94 }
95
96 gchar *
97 gdk_atom_name (GdkAtom atom)
98 {
99   ATOM win32_atom;
100   gchar name[256];
101
102   if (GDK_NONE == atom) return g_strdup ("<none>");
103   else if (GDK_SELECTION_PRIMARY == atom) return g_strdup ("PRIMARY");
104   else if (GDK_SELECTION_SECONDARY == atom) return g_strdup ("SECONDARY");
105   else if (GDK_SELECTION_CLIPBOARD == atom) return g_strdup ("CLIPBOARD");
106   else if (GDK_SELECTION_TYPE_ATOM == atom) return g_strdup ("ATOM");
107   else if (GDK_SELECTION_TYPE_BITMAP == atom) return g_strdup ("BITMAP");
108   else if (GDK_SELECTION_TYPE_COLORMAP == atom) return g_strdup ("COLORMAP");
109   else if (GDK_SELECTION_TYPE_DRAWABLE == atom) return g_strdup ("DRAWABLE");
110   else if (GDK_SELECTION_TYPE_INTEGER == atom) return g_strdup ("INTEGER");
111   else if (GDK_SELECTION_TYPE_PIXMAP == atom) return g_strdup ("PIXMAP");
112   else if (GDK_SELECTION_TYPE_WINDOW == atom) return g_strdup ("WINDOW");
113   else if (GDK_SELECTION_TYPE_STRING == atom) return g_strdup ("STRING");
114   
115   win32_atom = GPOINTER_TO_UINT (atom);
116   
117   if (win32_atom < 0xC000)
118     return g_strdup_printf ("#%p", atom);
119   else if (GlobalGetAtomName (win32_atom, name, sizeof (name)) == 0)
120     return NULL;
121   return g_strdup (name);
122 }
123
124 gint
125 gdk_property_get (GdkWindow   *window,
126                   GdkAtom      property,
127                   GdkAtom      type,
128                   gulong       offset,
129                   gulong       length,
130                   gint         pdelete,
131                   GdkAtom     *actual_property_type,
132                   gint        *actual_format_type,
133                   gint        *actual_length,
134                   guchar     **data)
135 {
136   g_return_val_if_fail (window != NULL, FALSE);
137   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
138
139   if (GDK_WINDOW_DESTROYED (window))
140     return FALSE;
141
142   g_warning ("gdk_property_get: Not implemented");
143
144   return FALSE;
145 }
146
147 void
148 gdk_property_change (GdkWindow    *window,
149                      GdkAtom       property,
150                      GdkAtom       type,
151                      gint          format,
152                      GdkPropMode   mode,
153                      const guchar *data,
154                      gint          nelements)
155 {
156   HGLOBAL hdata;
157   gint i, size;
158   guchar *ucptr, *buf = NULL;
159   wchar_t *wcptr, *p;
160   glong wclen;
161
162   g_return_if_fail (window != NULL);
163   g_return_if_fail (GDK_IS_WINDOW (window));
164
165   if (GDK_WINDOW_DESTROYED (window))
166     return;
167
168   GDK_NOTE (DND, {
169       gchar *prop_name = gdk_atom_name (property);
170       gchar *type_name = gdk_atom_name (type);
171       
172       g_print ("gdk_property_change: %p %s %s %s %d*%d bits: %s\n",
173                GDK_WINDOW_HWND (window),
174                prop_name,
175                type_name,
176                (mode == GDK_PROP_MODE_REPLACE ? "REPLACE" :
177                 (mode == GDK_PROP_MODE_PREPEND ? "PREPEND" :
178                  (mode == GDK_PROP_MODE_APPEND ? "APPEND" :
179                   "???"))),
180                format, nelements,
181                _gdk_win32_data_to_string (data, MIN (10, format*nelements/8)));
182       g_free (prop_name);
183       g_free (type_name);
184     });
185
186   /* We should never come here for these types */
187   g_return_if_fail (type != GDK_TARGET_STRING);
188   g_return_if_fail (type != _text);
189   g_return_if_fail (type != _compound_text);
190   g_return_if_fail (type != _save_targets);
191
192   if (property == _gdk_selection &&
193       format == 8 &&
194       mode == GDK_PROP_MODE_REPLACE)
195     {
196       if (type == _utf8_string)
197         {
198           if (!OpenClipboard (GDK_WINDOW_HWND (window)))
199             {
200               WIN32_API_FAILED ("OpenClipboard");
201               return;
202             }
203
204           wcptr = g_utf8_to_utf16 ((char *) data, nelements, NULL, &wclen, NULL);
205
206           wclen++;              /* Terminating 0 */
207           size = wclen * 2;
208           for (i = 0; i < wclen; i++)
209             if (wcptr[i] == '\n')
210               size += 2;
211           
212           if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, size)))
213             {
214               WIN32_API_FAILED ("GlobalAlloc");
215               if (!CloseClipboard ())
216                 WIN32_API_FAILED ("CloseClipboard");
217               g_free (buf);
218               return;
219             }
220
221           ucptr = GlobalLock (hdata);
222
223           p = (wchar_t *) ucptr;
224           for (i = 0; i < wclen; i++)
225             {
226               if (wcptr[i] == '\n')
227                 *p++ = '\r';
228               *p++ = wcptr[i];
229             }
230           g_free (wcptr);
231
232           GlobalUnlock (hdata);
233           GDK_NOTE (DND, g_print ("... SetClipboardData(CF_UNICODETEXT,%p)\n",
234                                   hdata));
235           if (!SetClipboardData (CF_UNICODETEXT, hdata))
236             WIN32_API_FAILED ("SetClipboardData");
237       
238           if (!CloseClipboard ())
239             WIN32_API_FAILED ("CloseClipboard");
240         }
241       else
242         {
243           /* We use delayed rendering for everything else than
244            * text. We can't assign hdata to the clipboard here as type
245            * may be "image/png", "image/jpg", etc. In this case
246            * there's a further conversion afterwards.
247            */
248           GDK_NOTE (DND, g_print ("... delayed rendering\n"));
249           _delayed_rendering_data = NULL;
250           if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, nelements > 0 ? nelements : 1)))
251             {
252               WIN32_API_FAILED ("GlobalAlloc");
253               return;
254             }
255           ucptr = GlobalLock (hdata);
256           memcpy (ucptr, data, nelements);
257           GlobalUnlock (hdata);
258           _delayed_rendering_data = hdata;
259         }
260     }
261   else if (property == _gdk_ole2_dnd)
262     {
263       /* Will happen only if gdkdnd-win32.c has OLE2 dnd support compiled in */
264       _gdk_win32_ole2_dnd_property_change (type, format, data, nelements);
265     }
266   else
267     g_warning ("gdk_property_change: General case not implemented");
268 }
269
270 void
271 gdk_property_delete (GdkWindow *window,
272                      GdkAtom    property)
273 {
274   gchar *prop_name;
275
276   g_return_if_fail (window != NULL);
277   g_return_if_fail (GDK_IS_WINDOW (window));
278
279   GDK_NOTE (DND, {
280       prop_name = gdk_atom_name (property);
281
282       g_print ("gdk_property_delete: %p %s\n",
283                GDK_WINDOW_HWND (window),
284                prop_name);
285       g_free (prop_name);
286     });
287
288   if (property == _gdk_selection)
289     _gdk_selection_property_delete (window);
290   else if (property == _wm_transient_for)
291     gdk_window_set_transient_for (window, _gdk_root);
292   else
293     {
294       prop_name = gdk_atom_name (property);
295       g_warning ("gdk_property_delete: General case (%s) not implemented",
296                  prop_name);
297       g_free (prop_name);
298     }
299 }
300
301 /*
302   For reference, from gdk/x11/gdksettings.c:
303
304   "Net/DoubleClickTime\0"     "gtk-double-click-time\0"
305   "Net/DoubleClickDistance\0" "gtk-double-click-distance\0"
306   "Net/DndDragThreshold\0"    "gtk-dnd-drag-threshold\0"
307   "Net/CursorBlink\0"         "gtk-cursor-blink\0"
308   "Net/CursorBlinkTime\0"     "gtk-cursor-blink-time\0"
309   "Net/ThemeName\0"           "gtk-theme-name\0"
310   "Net/IconThemeName\0"       "gtk-icon-theme-name\0"
311   "Gtk/CanChangeAccels\0"     "gtk-can-change-accels\0"
312   "Gtk/ColorPalette\0"        "gtk-color-palette\0"
313   "Gtk/FontName\0"            "gtk-font-name\0"
314   "Gtk/IconSizes\0"           "gtk-icon-sizes\0"
315   "Gtk/KeyThemeName\0"        "gtk-key-theme-name\0"
316   "Gtk/ToolbarStyle\0"        "gtk-toolbar-style\0"
317   "Gtk/ToolbarIconSize\0"     "gtk-toolbar-icon-size\0"
318   "Gtk/IMPreeditStyle\0"      "gtk-im-preedit-style\0"
319   "Gtk/IMStatusStyle\0"       "gtk-im-status-style\0"
320   "Gtk/Modules\0"             "gtk-modules\0"
321   "Gtk/FileChooserBackend\0"  "gtk-file-chooser-backend\0"
322   "Gtk/ButtonImages\0"        "gtk-button-images\0"
323   "Gtk/MenuImages\0"          "gtk-menu-images\0"
324   "Gtk/MenuBarAccel\0"        "gtk-menu-bar-accel\0"
325   "Gtk/CursorThemeName\0"     "gtk-cursor-theme-name\0"
326   "Gtk/CursorThemeSize\0"     "gtk-cursor-theme-size\0"
327   "Gtk/ShowInputMethodMenu\0" "gtk-show-input-method-menu\0"
328   "Gtk/ShowUnicodeMenu\0"     "gtk-show-unicode-menu\0"
329   "Gtk/TimeoutInitial\0"      "gtk-timeout-initial\0"
330   "Gtk/TimeoutRepeat\0"       "gtk-timeout-repeat\0"
331   "Gtk/ColorScheme\0"         "gtk-color-scheme\0"
332   "Gtk/EnableAnimations\0"    "gtk-enable-animations\0"
333   "Xft/Antialias\0"           "gtk-xft-antialias\0"
334   "Xft/Hinting\0"             "gtk-xft-hinting\0"
335   "Xft/HintStyle\0"           "gtk-xft-hintstyle\0"
336   "Xft/RGBA\0"                "gtk-xft-rgba\0"
337   "Xft/DPI\0"                 "gtk-xft-dpi\0"
338   "Net/FallbackIconTheme\0"   "gtk-fallback-icon-theme\0"
339   "Gtk/TouchscreenMode\0"     "gtk-touchscreen-mode\0"
340   "Gtk/EnableAccels\0"        "gtk-enable-accels\0"
341   "Gtk/EnableMnemonics\0"     "gtk-enable-mnemonics\0"
342   "Gtk/ScrolledWindowPlacement\0" "gtk-scrolled-window-placement\0"
343   "Gtk/IMModule\0"            "gtk-im-module\0"
344   "Fontconfig/Timestamp\0"    "gtk-fontconfig-timestamp\0"
345   "Net/SoundThemeName\0"      "gtk-sound-theme-name\0"
346   "Net/EnableInputFeedbackSounds\0" "gtk-enable-input-feedback-sounds\0"
347   "Net/EnableEventSounds\0"  "gtk-enable-event-sounds\0";
348
349   More, from various places in gtk sources:
350
351   gtk-entry-select-on-focus
352   gtk-split-cursor
353
354 */
355 gboolean
356 gdk_screen_get_setting (GdkScreen   *screen,
357                         const gchar *name,
358                         GValue      *value)
359 {
360   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
361
362   /*
363    * XXX : if these values get changed through the Windoze UI the
364    *       respective gdk_events are not generated yet.
365    */
366   if (strcmp ("gtk-theme-name", name) == 0) 
367     {
368       g_value_set_string (value, "ms-windows");
369     }
370   else if (strcmp ("gtk-double-click-time", name) == 0)
371     {
372       gint i = GetDoubleClickTime ();
373       GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %d\n", name, i));
374       g_value_set_int (value, i);
375       return TRUE;
376     }
377   else if (strcmp ("gtk-double-click-distance", name) == 0)
378     {
379       gint i = MAX(GetSystemMetrics (SM_CXDOUBLECLK), GetSystemMetrics (SM_CYDOUBLECLK));
380       GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %d\n", name, i));
381       g_value_set_int (value, i);
382       return TRUE;
383     }
384   else if (strcmp ("gtk-dnd-drag-threshold", name) == 0)
385     {
386       gint i = MAX(GetSystemMetrics (SM_CXDRAG), GetSystemMetrics (SM_CYDRAG));
387       GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : %d\n", name, i));
388       g_value_set_int (value, i);
389       return TRUE;
390     }
391   else if (strcmp ("gtk-split-cursor", name) == 0)
392     {
393       GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : FALSE\n", name));
394       g_value_set_boolean (value, FALSE);
395       return TRUE;
396     }
397   else if (strcmp ("gtk-alternative-button-order", name) == 0)
398     {
399       GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : TRUE\n", name));
400       g_value_set_boolean (value, TRUE);
401       return TRUE;
402     }
403   else if (strcmp ("gtk-alternative-sort-arrows", name) == 0)
404     {
405       GDK_NOTE(MISC, g_print("gdk_screen_get_setting(\"%s\") : TRUE\n", name));
406       g_value_set_boolean (value, TRUE);
407       return TRUE;
408     }
409 #if 0
410   /*
411    * With 'MS Sans Serif' as windows menu font (default on win98se) you'll get a 
412    * bunch of :
413    *   WARNING **: Couldn't load font "MS Sans Serif 8" falling back to "Sans 8"
414    * at least with testfilechooser (regardless of the bitmap check below)
415    * so just disabling this code seems to be the best we can do --hb
416    */
417   else if (strcmp ("gtk-font-name", name) == 0)
418     {
419       NONCLIENTMETRICS ncm;
420       ncm.cbSize = sizeof(NONCLIENTMETRICS);
421       if (SystemParametersInfo (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, FALSE))
422         {
423           /* Pango finally uses GetDeviceCaps to scale, we use simple
424            * approximation here.
425            */
426           int nHeight = (0 > ncm.lfMenuFont.lfHeight ? -3*ncm.lfMenuFont.lfHeight/4 : 10);
427           if (OUT_STRING_PRECIS == ncm.lfMenuFont.lfOutPrecision)
428             GDK_NOTE(MISC, g_print("gdk_screen_get_setting(%s) : ignoring bitmap font '%s'\n", 
429                                    name, ncm.lfMenuFont.lfFaceName));
430           else if (ncm.lfMenuFont.lfFaceName && strlen(ncm.lfMenuFont.lfFaceName) > 0 &&
431                    /* Avoid issues like those described in bug #135098 */
432                    g_utf8_validate (ncm.lfMenuFont.lfFaceName, -1, NULL))
433             {
434               char* s = g_strdup_printf ("%s %d", ncm.lfMenuFont.lfFaceName, nHeight);
435               GDK_NOTE(MISC, g_print("gdk_screen_get_setting(%s) : %s\n", name, s));
436               g_value_set_string (value, s);
437
438               g_free(s);
439               return TRUE;
440             }
441         }
442     }
443 #endif
444
445   return FALSE;
446 }