]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkselection-win32.c
x11: Use boolean instead of enum for errors in xsettings code
[~andy/gtk] / gdk / win32 / gdkselection-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
30 #include "gdkproperty.h"
31 #include "gdkselection.h"
32 #include "gdkdisplay.h"
33 #include "gdkprivate-win32.h"
34 #include "gdkwin32.h"
35
36 /* We emulate the GDK_SELECTION window properties of windows (as used
37  * in the X11 backend) by using a hash table from window handles to
38  * GdkSelProp structs.
39  */
40
41 typedef struct {
42   guchar *data;
43   gsize length;
44   gint format;
45   GdkAtom type;
46 } GdkSelProp;
47
48 static GHashTable *sel_prop_table = NULL;
49
50 static GdkSelProp *dropfiles_prop = NULL;
51
52 /* We store the owner of each selection in this table. Obviously, this only
53  * is valid intra-app, and in fact it is necessary for the intra-app DND to work.
54  */
55 static GHashTable *sel_owner_table = NULL;
56
57 /* GdkAtoms for well-known image formats */
58 static GdkAtom *known_pixbuf_formats;
59 static int n_known_pixbuf_formats;
60
61 /* GdkAtoms for well-known text formats */
62 static GdkAtom text_plain;
63 static GdkAtom text_plain_charset_utf_8;
64 static GdkAtom text_plain_charset_CP1252;
65
66 void
67 _gdk_win32_selection_init (void)
68 {
69   GSList *pixbuf_formats;
70   GSList *rover;
71
72   sel_prop_table = g_hash_table_new (NULL, NULL);
73   sel_owner_table = g_hash_table_new (NULL, NULL);
74   _format_atom_table = g_hash_table_new (NULL, NULL);
75
76   pixbuf_formats = gdk_pixbuf_get_formats ();
77
78   n_known_pixbuf_formats = 0;
79   for (rover = pixbuf_formats; rover != NULL; rover = rover->next)
80     {
81       gchar **mime_types =
82         gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) rover->data);
83
84       gchar **mime_type;
85
86       for (mime_type = mime_types; *mime_type != NULL; mime_type++)
87         n_known_pixbuf_formats++;
88     }
89
90   known_pixbuf_formats = g_new (GdkAtom, n_known_pixbuf_formats);
91
92   n_known_pixbuf_formats = 0;
93   for (rover = pixbuf_formats; rover != NULL; rover = rover->next)
94     {
95       gchar **mime_types =
96         gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) rover->data);
97
98       gchar **mime_type;
99
100       for (mime_type = mime_types; *mime_type != NULL; mime_type++)
101         known_pixbuf_formats[n_known_pixbuf_formats++] = gdk_atom_intern (*mime_type, FALSE);
102     }
103
104   g_slist_free (pixbuf_formats);
105   
106   text_plain = gdk_atom_intern ("text/plain", FALSE);
107   text_plain_charset_utf_8= gdk_atom_intern ("text/plain;charset=utf-8", FALSE);
108   text_plain_charset_CP1252 = gdk_atom_intern ("text/plain;charset=CP1252", FALSE);
109
110   g_hash_table_replace (_format_atom_table,
111                         GINT_TO_POINTER (_cf_png),
112                         _image_png);
113
114   g_hash_table_replace (_format_atom_table,
115                         GINT_TO_POINTER (CF_DIB),
116                         _image_bmp);
117 }
118
119 /* The specifications for COMPOUND_TEXT and STRING specify that C0 and
120  * C1 are not allowed except for \n and \t, however the X conversions
121  * routines for COMPOUND_TEXT only enforce this in one direction,
122  * causing cut-and-paste of \r and \r\n separated text to fail.
123  * This routine strips out all non-allowed C0 and C1 characters
124  * from the input string and also canonicalizes \r, and \r\n to \n
125  */
126 static gchar * 
127 sanitize_utf8 (const gchar *src,
128                gint         length)
129 {
130   GString *result = g_string_sized_new (length + 1);
131   const gchar *p = src;
132   const gchar *endp = src + length;
133
134   while (p < endp)
135     {
136       if (*p == '\r')
137         {
138           p++;
139           if (*p == '\n')
140             p++;
141
142           g_string_append_c (result, '\n');
143         }
144       else
145         {
146           gunichar ch = g_utf8_get_char (p);
147           char buf[7];
148           gint buflen;
149           
150           if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0)))
151             {
152               buflen = g_unichar_to_utf8 (ch, buf);
153               g_string_append_len (result, buf, buflen);
154             }
155
156           p = g_utf8_next_char (p);
157         }
158     }
159   g_string_append_c (result, '\0');
160
161   return g_string_free (result, FALSE);
162 }
163
164 static gchar *
165 _gdk_utf8_to_string_target_internal (const gchar *str,
166                                      gint         length)
167 {
168   GError *error = NULL;
169   
170   gchar *tmp_str = sanitize_utf8 (str, length);
171   gchar *result =  g_convert_with_fallback (tmp_str, -1,
172                                             "ISO-8859-1", "UTF-8",
173                                             NULL, NULL, NULL, &error);
174   if (!result)
175     {
176       g_warning ("Error converting from UTF-8 to STRING: %s",
177                  error->message);
178       g_error_free (error);
179     }
180   
181   g_free (tmp_str);
182   return result;
183 }
184
185 static void
186 selection_property_store (GdkWindow *owner,
187                           GdkAtom    type,
188                           gint       format,
189                           guchar    *data,
190                           gint       length)
191 {
192   GdkSelProp *prop;
193
194   g_return_if_fail (type != GDK_TARGET_STRING);
195
196   prop = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (owner));
197
198   if (prop != NULL)
199     {
200       g_free (prop->data);
201       g_free (prop);
202       g_hash_table_remove (sel_prop_table, GDK_WINDOW_HWND (owner));
203     }
204
205   prop = g_new (GdkSelProp, 1);
206
207   prop->data = data;
208   prop->length = length;
209   prop->format = format;
210   prop->type = type;
211
212   g_hash_table_insert (sel_prop_table, GDK_WINDOW_HWND (owner), prop);
213 }
214
215 void
216 _gdk_dropfiles_store (gchar *data)
217 {
218   if (data != NULL)
219     {
220       g_assert (dropfiles_prop == NULL);
221
222       dropfiles_prop = g_new (GdkSelProp, 1);
223       dropfiles_prop->data = (guchar *) data;
224       dropfiles_prop->length = strlen (data) + 1;
225       dropfiles_prop->format = 8;
226       dropfiles_prop->type = _text_uri_list;
227     }
228   else
229     {
230       if (dropfiles_prop != NULL)
231         {
232           g_free (dropfiles_prop->data);
233           g_free (dropfiles_prop);
234         }
235       dropfiles_prop = NULL;
236     }
237 }
238
239 static gchar *
240 get_mapped_gdk_atom_name (GdkAtom gdk_target)
241 {
242   if (gdk_target == _image_png)
243     return g_strdup ("PNG");
244
245   if (gdk_target == _image_jpeg)
246     return g_strdup ("JFIF");
247   
248   if (gdk_target == _image_gif)
249     return g_strdup ("GIF");
250   
251   return gdk_atom_name (gdk_target);
252 }
253
254 gboolean
255 _gdk_win32_display_set_selection_owner (GdkDisplay *display,
256                                         GdkWindow  *owner,
257                                         GdkAtom     selection,
258                                         guint32     time,
259                                         gboolean    send_event)
260 {
261   HWND hwnd;
262   GdkEvent tmp_event;
263
264   g_return_val_if_fail (display == _gdk_display, FALSE);
265   g_return_val_if_fail (selection != GDK_NONE, FALSE);
266
267   GDK_NOTE (DND, {
268       gchar *sel_name = gdk_atom_name (selection);
269
270       g_print ("gdk_selection_owner_set_for_display: %p %s\n",
271                (owner ? GDK_WINDOW_HWND (owner) : NULL),
272                sel_name);
273       g_free (sel_name);
274     });
275
276   if (selection != GDK_SELECTION_CLIPBOARD)
277     {
278       if (owner != NULL)
279         g_hash_table_insert (sel_owner_table, selection, GDK_WINDOW_HWND (owner));
280       else
281         g_hash_table_remove (sel_owner_table, selection);
282       return TRUE;
283     }
284
285   /* Rest of this function handles the CLIPBOARD selection */
286   if (owner != NULL)
287     {
288       if (GDK_WINDOW_DESTROYED (owner))
289         return FALSE;
290
291       hwnd = GDK_WINDOW_HWND (owner);
292     }
293   else
294     hwnd = NULL;
295
296   if (!API_CALL (OpenClipboard, (hwnd)))
297     return FALSE;
298
299   _ignore_destroy_clipboard = TRUE;
300   GDK_NOTE (DND, g_print ("... EmptyClipboard()\n"));
301   if (!API_CALL (EmptyClipboard, ()))
302     {
303       _ignore_destroy_clipboard = FALSE;
304       API_CALL (CloseClipboard, ());
305       return FALSE;
306     }
307   _ignore_destroy_clipboard = FALSE;
308
309   if (!API_CALL (CloseClipboard, ()))
310     return FALSE;
311
312   if (owner != NULL)
313     {
314       /* Send ourselves a selection request message so that
315        * gdk_property_change will be called to store the clipboard
316        * data.
317        */
318       GDK_NOTE (DND, g_print ("... sending GDK_SELECTION_REQUEST to ourselves\n"));
319       tmp_event.selection.type = GDK_SELECTION_REQUEST;
320       tmp_event.selection.window = owner;
321       tmp_event.selection.send_event = FALSE;
322       tmp_event.selection.selection = selection;
323       tmp_event.selection.target = _utf8_string;
324       tmp_event.selection.property = _gdk_selection;
325       tmp_event.selection.requestor = gdk_win32_handle_table_lookup (hwnd);
326       tmp_event.selection.time = time;
327
328       gdk_event_put (&tmp_event);
329     }
330
331   return TRUE;
332 }
333
334 GdkWindow*
335 _gdk_win32_display_get_selection_owner (GdkDisplay *display,
336                                         GdkAtom     selection)
337 {
338   GdkWindow *window;
339
340   g_return_val_if_fail (display == _gdk_display, NULL);
341   g_return_val_if_fail (selection != GDK_NONE, NULL);
342
343   if (selection == GDK_SELECTION_CLIPBOARD)
344     {
345       HWND owner = GetClipboardOwner ();
346
347       if (owner == NULL)
348         return NULL;
349
350       return gdk_win32_handle_table_lookup (owner);
351     }
352
353   window = gdk_win32_window_lookup_for_display (display,
354                                                 g_hash_table_lookup (sel_owner_table, selection));
355
356   GDK_NOTE (DND, {
357       gchar *sel_name = gdk_atom_name (selection);
358       
359       g_print ("gdk_selection_owner_get: %s = %p\n",
360                sel_name,
361                (window ? GDK_WINDOW_HWND (window) : NULL));
362       g_free (sel_name);
363     });
364
365   return window;
366 }
367
368 static void
369 generate_selection_notify (GdkWindow *requestor,
370                            GdkAtom    selection,
371                            GdkAtom    target,
372                            GdkAtom    property,
373                            guint32    time)
374 {
375   GdkEvent tmp_event;
376
377   tmp_event.selection.type = GDK_SELECTION_NOTIFY;
378   tmp_event.selection.window = requestor;
379   tmp_event.selection.send_event = FALSE;
380   tmp_event.selection.selection = selection;
381   tmp_event.selection.target = target;
382   tmp_event.selection.property = property;
383   tmp_event.selection.requestor = 0;
384   tmp_event.selection.time = time;
385
386   gdk_event_put (&tmp_event);
387 }
388
389 void
390 _gdk_win32_display_convert_selection (GdkDisplay *display,
391                                       GdkWindow *requestor,
392                                       GdkAtom    selection,
393                                       GdkAtom    target,
394                                       guint32    time)
395 {
396   HGLOBAL hdata;
397   GdkAtom property = _gdk_selection;
398
399   g_return_if_fail (selection != GDK_NONE);
400   g_return_if_fail (requestor != NULL);
401
402   if (GDK_WINDOW_DESTROYED (requestor))
403     return;
404
405   GDK_NOTE (DND, {
406       gchar *sel_name = gdk_atom_name (selection);
407       gchar *tgt_name = gdk_atom_name (target);
408       
409       g_print ("gdk_selection_convert: %p %s %s\n",
410                GDK_WINDOW_HWND (requestor),
411                sel_name, tgt_name);
412       g_free (sel_name);
413       g_free (tgt_name);
414     });
415
416   if (selection == GDK_SELECTION_CLIPBOARD && target == _targets)
417     {
418       gint ntargets, fmt;
419       GdkAtom *targets;
420       gboolean has_text = FALSE;
421       gboolean has_png = FALSE;
422       gboolean has_bmp = FALSE;
423
424       if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
425         return;
426
427       targets = g_new (GdkAtom, CountClipboardFormats ());
428       ntargets = 0;
429
430       for (fmt = 0; 0 != (fmt = EnumClipboardFormats (fmt)); )
431         {
432           if (fmt == _cf_png)
433             {
434               targets[ntargets++] = _image_png;
435               has_png = TRUE;
436             }
437         }
438
439       for (fmt = 0; 0 != (fmt = EnumClipboardFormats (fmt)); )
440         {
441           gchar sFormat[80];
442
443           if (fmt == CF_UNICODETEXT || fmt == CF_TEXT)
444             {
445               /* Advertise text to GDK always as UTF8_STRING */
446               if (!has_text)
447                 targets[ntargets++] = _utf8_string;
448               has_text = TRUE;
449             }
450           else if (fmt == _cf_png)
451             {
452               /* Already handled above */
453             }
454           else if (fmt == CF_DIB ||
455                    fmt == CF_DIBV5)
456             {
457               /* Don't bother telling that a bitmap is present if there is
458                * also PNG, which is much more reliable in transferring
459                * transparency.
460                */
461               if (!has_bmp && !has_png)
462                 targets[ntargets++] = _image_bmp;
463               has_bmp = TRUE;
464             }
465           else if (fmt == _cf_jfif)
466             {
467               /* Ditto for JPEG */
468               if (!has_png)
469                 targets[ntargets++] = _image_jpeg;
470             }
471           else if (fmt == _cf_gif)
472             {
473               /* Ditto for GIF.
474                */
475               if (!has_png)
476                 targets[ntargets++] = _image_gif;
477             }
478           else if (GetClipboardFormatName (fmt, sFormat, 80) > 0)
479             {
480               if (strcmp (sFormat, "image/bmp") == 0 ||
481                   strcmp (sFormat, "image/x-bmp") == 0 ||
482                   strcmp (sFormat, "image/x-MS-bmp") == 0 ||
483                   strcmp (sFormat, "image/x-icon") == 0 ||
484                   strcmp (sFormat, "image/x-ico") == 0 ||
485                   strcmp (sFormat, "image/x-win-bitmap") == 0)
486                 {
487                   /* Ignore these (from older GTK+ versions
488                    * presumably), as the same image in the CF_DIB
489                    * format will also be on the clipboard anyway.
490                    */
491                 }
492               else
493                 targets[ntargets++] = gdk_atom_intern (sFormat, FALSE);
494             }
495         }
496
497       GDK_NOTE (DND, {
498           int i;
499           
500           g_print ("... ");
501           for (i = 0; i < ntargets; i++)
502             {
503               gchar *atom_name = gdk_atom_name (targets[i]);
504
505               g_print ("%s", atom_name);
506               g_free (atom_name);
507               if (i < ntargets - 1)
508                 g_print (", ");
509             }
510           g_print ("\n");
511         });
512
513       if (ntargets > 0)
514         selection_property_store (requestor, GDK_SELECTION_TYPE_ATOM,
515                                   32, (guchar *) targets,
516                                   ntargets * sizeof (GdkAtom));
517       else
518         property = GDK_NONE;
519
520       API_CALL (CloseClipboard, ());
521     }
522   else if (selection == GDK_SELECTION_CLIPBOARD && target == _utf8_string)
523     {
524       /* Converting the CLIPBOARD selection means he wants the
525        * contents of the clipboard. Get the clipboard data, and store
526        * it for later.
527        */
528       if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
529         return;
530
531       if ((hdata = GetClipboardData (CF_UNICODETEXT)) != NULL)
532         {
533           wchar_t *ptr, *wcs, *p, *q;
534           guchar *data;
535           glong length, wclen;
536
537           if ((ptr = GlobalLock (hdata)) != NULL)
538             {
539               length = GlobalSize (hdata);
540               
541               GDK_NOTE (DND, g_print ("... CF_UNICODETEXT: %ld bytes\n",
542                                       length));
543
544               /* Strip out \r */
545               wcs = g_new (wchar_t, length / 2 + 1);
546               p = ptr;
547               q = wcs;
548               wclen = 0;
549               while (p < ptr + length / 2)
550                 {
551                   if (*p != '\r')
552                     {
553                       *q++ = *p;
554                       wclen++;
555                     }
556                   p++;
557                 }
558
559               data = g_utf16_to_utf8 (wcs, wclen, NULL, NULL, NULL);
560               g_free (wcs);
561
562               if (data)
563                 selection_property_store (requestor, _utf8_string, 8,
564                                           data, strlen (data) + 1);
565               GlobalUnlock (hdata);
566             }
567         }
568       else
569         property = GDK_NONE;
570
571       API_CALL (CloseClipboard, ());
572     }
573   else if (selection == GDK_SELECTION_CLIPBOARD && target == _image_bmp)
574     {
575       if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
576         return;
577
578       if ((hdata = GetClipboardData (CF_DIB)) != NULL)
579         {
580           BITMAPINFOHEADER *bi;
581
582           if ((bi = GlobalLock (hdata)) != NULL)
583             {
584               /* Need to add a BMP file header so gdk-pixbuf can load
585                * it.
586                *
587                * If the data is from Mozilla Firefox or IE7, and
588                * starts with an "old fashioned" BITMAPINFOHEADER,
589                * i.e. with biSize==40, and biCompression == BI_RGB and
590                * biBitCount==32, we assume that the "extra" byte in
591                * each pixel in fact is alpha.
592                *
593                * The gdk-pixbuf bmp loader doesn't trust 32-bit BI_RGB
594                * bitmaps to in fact have alpha, so we have to convince
595                * it by changing the bitmap header to a version 5
596                * BI_BITFIELDS one with explicit alpha mask indicated.
597                *
598                * The RGB bytes that are in bitmaps on the clipboard
599                * originating from Firefox or IE7 seem to be
600                * premultiplied with alpha. The gdk-pixbuf bmp loader
601                * of course doesn't expect that, so we have to undo the
602                * premultiplication before feeding the bitmap to the
603                * bmp loader.
604                *
605                * Note that for some reason the bmp loader used to want
606                * the alpha bytes in its input to actually be
607                * 255-alpha, but here we assume that this has been
608                * fixed before this is committed.
609                */
610               BITMAPFILEHEADER *bf;
611               gpointer data;
612               gint data_length = GlobalSize (hdata);
613               gint new_length;
614               gboolean make_dibv5 = FALSE;
615
616               GDK_NOTE (DND, g_print ("... CF_DIB: %d bytes\n", data_length));
617
618               if (bi->biSize == sizeof (BITMAPINFOHEADER) &&
619                   bi->biPlanes == 1 &&
620                   bi->biBitCount == 32 &&
621                   bi->biCompression == BI_RGB &&
622 #if 0
623                   /* Maybe check explicitly for Mozilla or IE7?
624                    *
625                    * If the clipboard format
626                    * application/x-moz-nativeimage is present, that is
627                    * a reliable indicator that the data is offered by
628                    * Mozilla one would think. For IE7,
629                    * UniformResourceLocatorW is presumably not that
630                    * uniqie, so probably need to do some
631                    * GetClipboardOwner(), GetWindowThreadProcessId(),
632                    * OpenProcess(), GetModuleFileNameEx() dance to
633                    * check?
634                    */
635                   (IsClipboardFormatAvailable
636                    (RegisterClipboardFormat ("application/x-moz-nativeimage")) ||
637                    IsClipboardFormatAvailable
638                    (RegisterClipboardFormat ("UniformResourceLocatorW"))) &&
639 #endif
640                   TRUE)
641                 {
642                   /* We turn the BITMAPINFOHEADER into a
643                    * BITMAPV5HEADER before feeding it to gdk-pixbuf.
644                    */
645                   new_length = (data_length +
646                                 sizeof (BITMAPFILEHEADER) +
647                                 (sizeof (BITMAPV5HEADER) - sizeof (BITMAPINFOHEADER)));
648                   make_dibv5 = TRUE;
649                 }
650               else
651                 {
652                   new_length = data_length + sizeof (BITMAPFILEHEADER);
653                 }
654               
655               data = g_try_malloc (new_length);
656
657               if (data)
658                 {
659                   bf = (BITMAPFILEHEADER *)data;
660                   bf->bfType = 0x4d42; /* "BM" */
661                   bf->bfSize = new_length;
662                   bf->bfReserved1 = 0;
663                   bf->bfReserved2 = 0;
664
665                   if (make_dibv5)
666                     {
667                       BITMAPV5HEADER *bV5 = (BITMAPV5HEADER *) ((char *) data + sizeof (BITMAPFILEHEADER));
668                       guchar *p;
669                       int i;
670
671                       bV5->bV5Size = sizeof (BITMAPV5HEADER);
672                       bV5->bV5Width = bi->biWidth;
673                       bV5->bV5Height = bi->biHeight;
674                       bV5->bV5Planes = 1;
675                       bV5->bV5BitCount = 32;
676                       bV5->bV5Compression = BI_BITFIELDS;
677                       bV5->bV5SizeImage = 4 * bV5->bV5Width * ABS (bV5->bV5Height);
678                       bV5->bV5XPelsPerMeter = bi->biXPelsPerMeter;
679                       bV5->bV5YPelsPerMeter = bi->biYPelsPerMeter;
680                       bV5->bV5ClrUsed = 0;
681                       bV5->bV5ClrImportant = 0;
682                       /* Now the added mask fields */
683                       bV5->bV5RedMask   = 0x00ff0000;
684                       bV5->bV5GreenMask = 0x0000ff00;
685                       bV5->bV5BlueMask  = 0x000000ff;
686                       bV5->bV5AlphaMask = 0xff000000;
687                       ((char *) &bV5->bV5CSType)[3] = 's';
688                       ((char *) &bV5->bV5CSType)[2] = 'R';
689                       ((char *) &bV5->bV5CSType)[1] = 'G';
690                       ((char *) &bV5->bV5CSType)[0] = 'B';
691                       /* Ignore colorspace and profile fields */
692                       bV5->bV5Intent = LCS_GM_GRAPHICS;
693                       bV5->bV5Reserved = 0;
694
695                       bf->bfOffBits = (sizeof (BITMAPFILEHEADER) +
696                                        bV5->bV5Size);
697
698                       p = ((guchar *) data) + sizeof (BITMAPFILEHEADER) + sizeof (BITMAPV5HEADER);
699                       memcpy (p, ((char *) bi) + bi->biSize,
700                               data_length - sizeof (BITMAPINFOHEADER));
701
702                       for (i = 0; i < bV5->bV5SizeImage/4; i++)
703                         {
704                           if (p[3] != 0)
705                             {
706                               gdouble inverse_alpha = 255./p[3];
707                               
708                               p[0] = p[0] * inverse_alpha + 0.5;
709                               p[1] = p[1] * inverse_alpha + 0.5;
710                               p[2] = p[2] * inverse_alpha + 0.5;
711                             }
712
713                           p += 4;
714                         }
715                     }
716                   else
717                     {
718                       bf->bfOffBits = (sizeof (BITMAPFILEHEADER) +
719                                        bi->biSize +
720                                        bi->biClrUsed * sizeof (RGBQUAD));
721
722                       if (bi->biCompression == BI_BITFIELDS && bi->biBitCount >= 16)
723                         {
724                           /* Screenshots taken with PrintScreen or
725                            * Alt + PrintScreen are found on the clipboard in
726                            * this format. In this case the BITMAPINFOHEADER is
727                            * followed by three DWORD specifying the masks of the
728                            * red green and blue components, so adjust the offset
729                            * accordingly. */
730                           bf->bfOffBits += (3 * sizeof (DWORD));
731                         }
732
733                       memcpy ((char *) data + sizeof (BITMAPFILEHEADER),
734                               bi,
735                               data_length);
736                     }
737
738                   selection_property_store (requestor, _image_bmp, 8,
739                                             data, new_length);
740                 }
741               GlobalUnlock (hdata);
742             }
743       }
744
745       API_CALL (CloseClipboard, ());
746     }
747   else if (selection == GDK_SELECTION_CLIPBOARD)
748     {
749       gchar *mapped_target_name;
750       UINT fmt = 0;
751
752       if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
753         return;
754
755       mapped_target_name = get_mapped_gdk_atom_name (target);
756
757       /* Check if it's available. We could simply call
758        * GetClipboardData (RegisterClipboardFormat (targetname)), but
759        * the global custom format ID space is limited,
760        * (0xC000~0xFFFF), and we better not waste an format ID if we
761        * are just a requestor.
762        */
763       for ( ; 0 != (fmt = EnumClipboardFormats (fmt)); )
764         {
765           char sFormat[80];
766
767           if (GetClipboardFormatName (fmt, sFormat, 80) > 0 && 
768               strcmp (sFormat, mapped_target_name) == 0)
769             {
770               if ((hdata = GetClipboardData (fmt)) != NULL)
771                 {
772                   /* Simply get it without conversion */
773                   guchar *ptr;
774                   gint length;
775
776                   if ((ptr = GlobalLock (hdata)) != NULL)
777                     {
778                       length = GlobalSize (hdata);
779               
780                       GDK_NOTE (DND, g_print ("... %s: %d bytes\n", mapped_target_name, length));
781               
782                       selection_property_store (requestor, target, 8,
783                                                 g_memdup (ptr, length), length);
784                       GlobalUnlock (hdata);
785                       break;
786                     }
787                 }
788             }
789         }
790       g_free (mapped_target_name);
791       API_CALL (CloseClipboard, ());
792     }
793   else if (selection == _gdk_win32_dropfiles)
794     {
795       /* This means he wants the names of the dropped files.
796        * gdk_dropfiles_filter already has stored the text/uri-list
797        * data temporarily in dropfiles_prop.
798        */
799       if (dropfiles_prop != NULL)
800         {
801           selection_property_store
802             (requestor, dropfiles_prop->type, dropfiles_prop->format,
803              dropfiles_prop->data, dropfiles_prop->length);
804           g_free (dropfiles_prop);
805           dropfiles_prop = NULL;
806         }
807     }
808   else
809     property = GDK_NONE;
810
811   /* Generate a selection notify message so that we actually fetch the
812    * data (if property == _gdk_selection) or indicating failure (if
813    * property == GDK_NONE).
814    */
815   generate_selection_notify (requestor, selection, target, property, time);
816 }
817
818 gint
819 _gdk_win32_display_get_selection_property (GdkDisplay *display,
820                                            GdkWindow  *requestor,
821                                            guchar    **data,
822                                            GdkAtom    *ret_type,
823                                            gint       *ret_format)
824 {
825   GdkSelProp *prop;
826
827   g_return_val_if_fail (requestor != NULL, 0);
828   g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
829
830   if (GDK_WINDOW_DESTROYED (requestor))
831     return 0;
832   
833   GDK_NOTE (DND, g_print ("gdk_selection_property_get: %p",
834                            GDK_WINDOW_HWND (requestor)));
835
836   prop = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (requestor));
837
838   if (prop == NULL)
839     {
840       GDK_NOTE (DND, g_print (" (nothing)\n"));
841       *data = NULL;
842
843       return 0;
844     }
845
846   *data = g_malloc (prop->length + 1);
847   (*data)[prop->length] = '\0';
848   if (prop->length > 0)
849     memmove (*data, prop->data, prop->length);
850
851   GDK_NOTE (DND, {
852       gchar *type_name = gdk_atom_name (prop->type);
853
854       g_print (" %s format:%d length:%d\n", type_name, prop->format, prop->length);
855       g_free (type_name);
856     });
857
858   if (ret_type)
859     *ret_type = prop->type;
860
861   if (ret_format)
862     *ret_format = prop->format;
863
864   return prop->length;
865 }
866
867 void
868 _gdk_selection_property_delete (GdkWindow *window)
869 {
870   GDK_NOTE (DND, g_print ("_gdk_selection_property_delete: %p (no-op)\n",
871                            GDK_WINDOW_HWND (window)));
872
873 #if 0
874   prop = g_hash_table_lookup (sel_prop_table, GDK_WINDOW_HWND (window));
875   if (prop != NULL)
876     {
877       g_free (prop->data);
878       g_free (prop);
879       g_hash_table_remove (sel_prop_table, GDK_WINDOW_HWND (window));
880     }
881 #endif
882 }
883
884 void
885 _gdk_win32_display_send_selection_notify (GdkDisplay   *display,
886                                           GdkWindow    *requestor,
887                                           GdkAtom       selection,
888                                           GdkAtom       target,
889                                           GdkAtom       property,
890                                           guint32       time)
891 {
892   g_return_if_fail (display == _gdk_display);
893
894   GDK_NOTE (DND, {
895       gchar *sel_name = gdk_atom_name (selection);
896       gchar *tgt_name = gdk_atom_name (target);
897       gchar *prop_name = gdk_atom_name (property);
898       
899       g_print ("gdk_selection_send_notify_for_display: %p %s %s %s (no-op)\n",
900                requestor, sel_name, tgt_name, prop_name);
901       g_free (sel_name);
902       g_free (tgt_name);
903       g_free (prop_name);
904     });
905 }
906
907 /* It's hard to say whether implementing this actually is of any use
908  * on the Win32 platform? gtk calls only
909  * gdk_text_property_to_utf8_list_for_display().
910  */
911 gint
912 gdk_text_property_to_text_list_for_display (GdkDisplay   *display,
913                                             GdkAtom       encoding,
914                                             gint          format, 
915                                             const guchar *text,
916                                             gint          length,
917                                             gchar      ***list)
918 {
919   gchar *result;
920   const gchar *charset;
921   gchar *source_charset;
922
923   g_return_val_if_fail (display == _gdk_display, 0);
924
925   GDK_NOTE (DND, {
926       gchar *enc_name = gdk_atom_name (encoding);
927       
928       g_print ("gdk_text_property_to_text_list_for_display: %s %d %.20s %d\n",
929                enc_name, format, text, length);
930       g_free (enc_name);
931     });
932     
933   if (!list)
934     return 0;
935
936   if (encoding == GDK_TARGET_STRING)
937     source_charset = g_strdup ("ISO-8859-1");
938   else if (encoding == _utf8_string)
939     source_charset = g_strdup ("UTF-8");
940   else
941     source_charset = gdk_atom_name (encoding);
942     
943   g_get_charset (&charset);
944
945   result = g_convert (text, length, charset, source_charset,
946                       NULL, NULL, NULL);
947   g_free (source_charset);
948
949   if (!result)
950     return 0;
951
952   *list = g_new (gchar *, 1);
953   **list = result;
954   
955   return 1;
956 }
957
958 void
959 gdk_free_text_list (gchar **list)
960 {
961   g_return_if_fail (list != NULL);
962
963   g_free (*list);
964   g_free (list);
965 }
966
967 static gint
968 make_list (const gchar  *text,
969            gint          length,
970            gboolean      latin1,
971            gchar      ***list)
972 {
973   GSList *strings = NULL;
974   gint n_strings = 0;
975   gint i;
976   const gchar *p = text;
977   const gchar *q;
978   GSList *tmp_list;
979   GError *error = NULL;
980
981   while (p < text + length)
982     {
983       gchar *str;
984       
985       q = p;
986       while (*q && q < text + length)
987         q++;
988
989       if (latin1)
990         {
991           str = g_convert (p, q - p,
992                            "UTF-8", "ISO-8859-1",
993                            NULL, NULL, &error);
994
995           if (!str)
996             {
997               g_warning ("Error converting selection from STRING: %s",
998                          error->message);
999               g_error_free (error);
1000             }
1001         }
1002       else
1003         str = g_strndup (p, q - p);
1004
1005       if (str)
1006         {
1007           strings = g_slist_prepend (strings, str);
1008           n_strings++;
1009         }
1010
1011       p = q + 1;
1012     }
1013
1014   if (list)
1015     *list = g_new (gchar *, n_strings + 1);
1016
1017   (*list)[n_strings] = NULL;
1018   
1019   i = n_strings;
1020   tmp_list = strings;
1021   while (tmp_list)
1022     {
1023       if (list)
1024         (*list)[--i] = tmp_list->data;
1025       else
1026         g_free (tmp_list->data);
1027
1028       tmp_list = tmp_list->next;
1029     }
1030
1031   g_slist_free (strings);
1032
1033   return n_strings;
1034 }
1035
1036 gint
1037 _gdk_win32_display_text_property_to_utf8_list (GdkDisplay    *display,
1038                                                GdkAtom        encoding,
1039                                                gint           format,
1040                                                const guchar  *text,
1041                                                gint           length,
1042                                                gchar       ***list)
1043 {
1044   g_return_val_if_fail (text != NULL, 0);
1045   g_return_val_if_fail (length >= 0, 0);
1046   g_return_val_if_fail (display == _gdk_display, 0);
1047
1048   if (encoding == GDK_TARGET_STRING)
1049     {
1050       return make_list ((gchar *)text, length, TRUE, list);
1051     }
1052   else if (encoding == _utf8_string)
1053     {
1054       return make_list ((gchar *)text, length, FALSE, list);
1055     }
1056   else
1057     {
1058       gchar *enc_name = gdk_atom_name (encoding);
1059
1060       g_warning ("gdk_text_property_to_utf8_list_for_display: encoding %s not handled\n", enc_name);
1061       g_free (enc_name);
1062
1063       if (list)
1064         *list = NULL;
1065
1066       return 0;
1067     }
1068 }
1069
1070 gint
1071 gdk_string_to_compound_text_for_display (GdkDisplay  *display,
1072                                          const gchar *str,
1073                                          GdkAtom     *encoding,
1074                                          gint        *format,
1075                                          guchar     **ctext,
1076                                          gint        *length)
1077 {
1078   g_return_val_if_fail (str != NULL, 0);
1079   g_return_val_if_fail (length >= 0, 0);
1080   g_return_val_if_fail (display == _gdk_display, 0);
1081
1082   GDK_NOTE (DND, g_print ("gdk_string_to_compound_text_for_display: %.20s\n", str));
1083
1084   /* Always fail on Win32. No COMPOUND_TEXT support. */
1085
1086   if (encoding)
1087     *encoding = GDK_NONE;
1088
1089   if (format)
1090     *format = 0;
1091
1092   if (ctext)
1093     *ctext = NULL;
1094
1095   if (length)
1096     *length = 0;
1097
1098   return -1;
1099 }
1100
1101 gchar *
1102 _gdk_win32_display_utf8_to_string_target (GdkDisplay *display,
1103                                           const gchar *str)
1104 {
1105   return _gdk_utf8_to_string_target_internal (str, strlen (str));
1106 }
1107
1108 gboolean
1109 gdk_utf8_to_compound_text_for_display (GdkDisplay  *display,
1110                                        const gchar *str,
1111                                        GdkAtom     *encoding,
1112                                        gint        *format,
1113                                        guchar     **ctext,
1114                                        gint        *length)
1115 {
1116   g_return_val_if_fail (str != NULL, FALSE);
1117   g_return_val_if_fail (display == _gdk_display, FALSE);
1118
1119   GDK_NOTE (DND, g_print ("gdk_utf8_to_compound_text_for_display: %.20s\n", str));
1120
1121   /* Always fail on Win32. No COMPOUND_TEXT support. */
1122
1123   if (encoding)
1124     *encoding = GDK_NONE;
1125
1126   if (format)
1127     *format = 0;
1128   
1129   if (ctext)
1130     *ctext = NULL;
1131
1132   if (length)
1133     *length = 0;
1134
1135   return FALSE;
1136 }
1137
1138 void
1139 gdk_free_compound_text (guchar *ctext)
1140 {
1141   /* As we never generate anything claimed to be COMPOUND_TEXT, this
1142    * should never be called. Or if it is called, ctext should be the
1143    * NULL returned for conversions to COMPOUND_TEXT above.
1144    */
1145   g_return_if_fail (ctext == NULL);
1146 }
1147
1148 /* This function is called from gtk_selection_add_target() and
1149  * gtk_selection_add_targets() in gtkselection.c. It is this function
1150  * that takes care of setting those clipboard formats for which we use
1151  * delayed rendering. Formats copied directly to the clipboard are
1152  * handled in gdk_property_change() in gdkproperty-win32.c.
1153  */
1154
1155 void
1156 gdk_win32_selection_add_targets (GdkWindow  *owner,
1157                                  GdkAtom     selection,
1158                                  gint        n_targets,
1159                                  GdkAtom    *targets)
1160 {
1161   HWND hwnd = NULL;
1162   gboolean has_image = FALSE;
1163   gint i;
1164
1165   GDK_NOTE (DND, {
1166       gchar *sel_name = gdk_atom_name (selection);
1167       
1168       g_print ("gdk_win32_selection_add_targets: %p: %s: ",
1169                owner ? GDK_WINDOW_HWND (owner) : NULL,
1170                sel_name);
1171       g_free (sel_name);
1172
1173       for (i = 0; i < n_targets; i++)
1174         {
1175           gchar *tgt_name = gdk_atom_name (targets[i]);
1176
1177           g_print ("%s", tgt_name);
1178           g_free (tgt_name);
1179           if (i < n_targets - 1)
1180             g_print (", ");
1181         }
1182       g_print ("\n");
1183     });
1184
1185   if (selection != GDK_SELECTION_CLIPBOARD)
1186     return;
1187
1188   if (owner != NULL)
1189     {
1190       if (GDK_WINDOW_DESTROYED (owner))
1191         return;
1192       hwnd = GDK_WINDOW_HWND (owner);
1193     }
1194
1195   if (!API_CALL (OpenClipboard, (hwnd)))
1196     return;
1197
1198   /* We have a very simple strategy: If some kind of pixmap image
1199    * format is being added, actually advertise just PNG and DIB. PNG
1200    * is our preferred format because it can losslessly represent any
1201    * image that gdk-pixbuf formats in general can, even with alpha,
1202    * unambiguously. CF_DIB is also advertised because of the general
1203    * support for it in Windows software, but note that alpha won't be
1204    * handled.
1205    */
1206   for (i = 0; !has_image && i < n_targets; ++i)
1207     {
1208       UINT cf;
1209       gchar *target_name;
1210       int j;
1211       
1212       for (j = 0; j < n_known_pixbuf_formats; j++)
1213         if (targets[i] == known_pixbuf_formats[j])
1214           {
1215             if (!has_image)
1216               {
1217                 GDK_NOTE (DND, g_print ("... SetClipboardData(PNG,NULL)\n"));
1218                 SetClipboardData (_cf_png, NULL);
1219
1220                 GDK_NOTE (DND, g_print ("... SetClipboardData(CF_DIB,NULL)\n"));
1221                 SetClipboardData (CF_DIB, NULL);
1222
1223                 has_image = TRUE;
1224               }
1225             break;
1226           }
1227       
1228       /* If it is one of the pixmap formats, already handled or not
1229        * needed.
1230        */
1231       if (j < n_known_pixbuf_formats)
1232         continue;
1233
1234       /* We don't bother registering and advertising clipboard formats
1235        * that are X11 specific or no non-GTK+ apps will have ever
1236        * heard of, and when there are equivalent clipboard formats
1237        * that are commonly used.
1238        */
1239       if (targets[i] == _save_targets ||
1240           targets[i] == _utf8_string ||
1241           targets[i] == GDK_TARGET_STRING ||
1242           targets[i] == _compound_text ||
1243           targets[i] == _text ||
1244           targets[i] == text_plain_charset_utf_8 ||
1245           targets[i] == text_plain_charset_CP1252 ||
1246           targets[i] == text_plain)
1247         continue;
1248
1249       target_name = gdk_atom_name (targets[i]);
1250
1251       if (g_str_has_prefix (target_name, "text/plain;charset="))
1252         {
1253           g_free (target_name);
1254           continue;
1255         }
1256
1257       cf = RegisterClipboardFormat (target_name);
1258
1259       g_hash_table_replace (_format_atom_table,
1260                             GINT_TO_POINTER (cf),
1261                             targets[i]);
1262       
1263       GDK_NOTE (DND, g_print ("... SetClipboardData(%s,NULL)\n",
1264                               _gdk_win32_cf_to_string (cf)));
1265       SetClipboardData (cf, NULL);
1266
1267       g_free (target_name);
1268     }
1269   API_CALL (CloseClipboard, ());
1270 }
1271
1272 /* Convert from types such as "image/jpg" or "image/png" to DIB using
1273  * gdk-pixbuf so that image copied from GTK+ apps can be pasted in
1274  * native apps like mspaint.exe
1275  */
1276 HGLOBAL
1277 _gdk_win32_selection_convert_to_dib (HGLOBAL  hdata,
1278                                      GdkAtom  target)
1279 {
1280   GDK_NOTE (DND, {
1281       gchar *target_name = gdk_atom_name (target);
1282
1283       g_print ("_gdk_win32_selection_convert_to_dib: %p %s\n",
1284                hdata, target_name);
1285       g_free (target_name);
1286     });
1287
1288   if (target == _image_bmp)
1289     {
1290       /* No conversion is needed, just strip the BITMAPFILEHEADER */
1291       HGLOBAL hdatanew;
1292       SIZE_T size = GlobalSize (hdata) - sizeof (BITMAPFILEHEADER);
1293       guchar *ptr = GlobalLock (hdata);
1294
1295       memmove (ptr, ptr + sizeof (BITMAPFILEHEADER), size);
1296       GlobalUnlock (hdata);
1297
1298       if ((hdatanew = GlobalReAlloc (hdata, size, GMEM_MOVEABLE)) == NULL)
1299         {
1300           WIN32_API_FAILED ("GlobalReAlloc");
1301           GlobalFree (hdata); /* The old hdata is not freed if error */
1302         }
1303       return hdatanew;
1304     }
1305
1306   g_warning ("Should not happen: We provide some image format but not CF_DIB and CF_DIB is requested.");
1307
1308   return NULL;
1309 }