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