summaryrefslogtreecommitdiff
path: root/gdk/win32/gdkselection-win32.c
diff options
context:
space:
mode:
authorTor Lillqvist <tml@novell.com>2005-04-04 00:12:26 +0000
committerTor Lillqvist <tml@src.gnome.org>2005-04-04 00:12:26 +0000
commit0b2ac32cf5d8ed96ebf743cbfc112d7e52928c81 (patch)
tree36a7395abd82e5c8bc1ad3ca0aec863ae0c8bc57 /gdk/win32/gdkselection-win32.c
parentba433af9fb2419f3429622d40300c7ac3659fd75 (diff)
downloadgtk+-0b2ac32cf5d8ed96ebf743cbfc112d7e52928c81.tar.gz
New debugging function, to log a clipboard format name symbolically.
2005-04-04 Tor Lillqvist <tml@novell.com> * gdk/win32/gdkmain.c (_gdk_win32_cf_to_string): New debugging function, to log a clipboard format name symbolically. (_gdk_win32_data_to_string): Also new, to log random data bytes. Implement delayed rendering on Win32, specifically for transfering images through the clipboard from GTK+ apps to other apps (#168173, implementation by Ivan Wong): * gdk/win32/gdkevents-win32.c (gdk_event_translate): Handle WM_RENDERFORMAT. * gdk/win32/gdkprivate-win32.h * gdk/win32/gdkglobals-win32.c: Add _format_atom_table, _delayed_rendering_data and _image_bmp. * gdk/win32/gdkmain-win32.c: Initialize _image_bmp. * gdk/win32/gdkproperty-win32.c (gdk_property_change): Accept formats other than GDK_TARGET_STRING or _utf8_string, and assume they are handled through delayed rendering. * gdk/win32/gdkselection-win32.c (gdk_selection_convert): Return all available formats (including those registered by GTK+ apps) on request_targets. (gdk_selection_property_get): We should append a zero byte like X11 does. (gdk_win32_selection_add_targets): New function, for gtkselection's use. Win32 requires that the clipboard owner registers all valid formats even if the owner wants delayed rendering. (_gdk_win32_selection_convert_to_dib): New function. Convert images to DIB using gdk-pixbuf. * gdk/win32/gdkwin32.h: Declare gdk_win32_selection_add_targets(). * gtk/gtkselection.c (gtk_selection_add_target, gtk_selection_add_targets): Call gdk_win32_selection_add_targets() to register target formats. * gdk/gdk.symbols: Add gdk_win32_selection_add_targets().
Diffstat (limited to 'gdk/win32/gdkselection-win32.c')
-rw-r--r--gdk/win32/gdkselection-win32.c283
1 files changed, 242 insertions, 41 deletions
diff --git a/gdk/win32/gdkselection-win32.c b/gdk/win32/gdkselection-win32.c
index 31eab06c8b..d5edb2d08b 100644
--- a/gdk/win32/gdkselection-win32.c
+++ b/gdk/win32/gdkselection-win32.c
@@ -60,6 +60,7 @@ _gdk_win32_selection_init (void)
{
sel_prop_table = g_hash_table_new (NULL, NULL);
sel_owner_table = g_hash_table_new (NULL, NULL);
+ _format_atom_table = g_hash_table_new (NULL, NULL);
}
/* The specifications for COMPOUND_TEXT and STRING specify that C0 and
@@ -350,52 +351,55 @@ gdk_selection_convert (GdkWindow *requestor,
if (selection == GDK_SELECTION_CLIPBOARD && target == _targets)
{
- /* He wants to know what formats are on the clipboard. If there
+ gint formats_cnt, i, fmt;
+ GdkAtom *data;
+ gboolean has_bmp = FALSE;
+
+ /* He wants to know what formats are on the clipboard. If there
* is some kind of text, tell him so.
*/
if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
return;
+ formats_cnt = CountClipboardFormats ();
+ data = g_new (GdkAtom, formats_cnt + 2);
+ i = 0;
+
if (IsClipboardFormatAvailable (CF_UNICODETEXT) ||
IsClipboardFormatAvailable (_cf_utf8_string) ||
IsClipboardFormatAvailable (CF_TEXT))
{
- GdkAtom *data = g_new (GdkAtom, 1);
- *data = _utf8_string;
- _gdk_selection_property_store (requestor, GDK_SELECTION_TYPE_ATOM,
- 32, (guchar *) data, 1 * sizeof (GdkAtom));
- }
- else if (IsClipboardFormatAvailable (CF_BITMAP) ||
- IsClipboardFormatAvailable (CF_DIB))
- {
- GdkAtom *data = g_new (GdkAtom, 1);
- GdkAtom atom = gdk_atom_intern ("image/bmp", FALSE);
- *data = atom;
- _gdk_selection_property_store (requestor, GDK_SELECTION_TYPE_ATOM,
- 32, (guchar *) data, 1 * sizeof (GdkAtom));
+ data[i++] = _utf8_string;
}
- else if (CountClipboardFormats() > 0)
+ if (formats_cnt > 0)
{
- /* if there is anything else in the clipboard, enum it all although we don't
- * offer special conversion services
+ /* If there is anything else in the clipboard, enum it all
+ * although we don't offer special conversion services.
*/
- int fmt = 0, i = 0;
- GdkAtom *data = g_new (GdkAtom, CountClipboardFormats());
-
- for ( ; 0 != (fmt = EnumClipboardFormats (fmt)); )
+ for (fmt = 0; 0 != (fmt = EnumClipboardFormats (fmt)); )
{
- char sFormat[80];
+ gchar sFormat[80];
- if (GetClipboardFormatName (fmt, sFormat, 80) > 0)
+ if (GetClipboardFormatName (fmt, sFormat, 80) > 0 &&
+ strcmp (sFormat, "UTF8_STRING"))
{
+ if (!has_bmp &&
+ (!strcmp (sFormat, "image/bmp") ||
+ !strcmp (sFormat, "image/x-bmp") ||
+ !strcmp (sFormat, "image/x-MS-bmp")))
+ has_bmp = TRUE;
GdkAtom atom = gdk_atom_intern (sFormat, FALSE);
- data[i] = atom;
- i++;
+ data[i++] = atom;
}
}
+ }
+ if (!has_bmp && (IsClipboardFormatAvailable (CF_BITMAP) ||
+ IsClipboardFormatAvailable (CF_DIB)))
+ data[i++] = _image_bmp;
+
+ if (i > 0)
_gdk_selection_property_store (requestor, GDK_SELECTION_TYPE_ATOM,
32, (guchar *) data, i * sizeof (GdkAtom));
- }
else
property = GDK_NONE;
@@ -542,21 +546,42 @@ gdk_selection_convert (GdkWindow *requestor,
API_CALL (CloseClipboard, ());
}
else if (selection == GDK_SELECTION_CLIPBOARD &&
- target == gdk_atom_intern ("image/bmp", TRUE))
+ target == _image_bmp)
{
+ guchar *data;
+
if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
return;
- if ((hdata = GetClipboardData (CF_DIB)) != NULL)
+ if ((hdata = GetClipboardData (RegisterClipboardFormat ("image/bmp"))) != NULL)
+ {
+ /* "image/bmp" is the first choice. */
+ guchar *ptr;
+
+ if ((ptr = GlobalLock (hdata)) != NULL)
+ {
+ gint length = GlobalSize (hdata);
+
+ GDK_NOTE (DND, g_print ("...BITMAP (from \"image/bmp\": %d bytes\n",
+ length));
+
+ _gdk_selection_property_store (requestor, target, 8,
+ g_memdup (ptr, length), length);
+ GlobalUnlock (hdata);
+ }
+ }
+ else if ((hdata = GetClipboardData (CF_DIB)) != NULL)
{
+ /* If there's CF_DIB but not "image/bmp", the clipboard
+ * owner is probably a native Win32 application.
+ */
BITMAPINFOHEADER *ptr;
- guchar *data;
if ((ptr = GlobalLock (hdata)) != NULL)
{
- BITMAPFILEHEADER *hdr; /* need to add a file header so gdk-pixbuf can load it */
- gint length = GlobalSize (hdata) + sizeof(BITMAPFILEHEADER);
+ BITMAPFILEHEADER *hdr; /* Need to add a file header so gdk-pixbuf can load it */
+ gint length = GlobalSize (hdata) + sizeof (BITMAPFILEHEADER);
- GDK_NOTE (DND, g_print ("... BITMAP: %d bytes\n", length));
+ GDK_NOTE (DND, g_print ("... BITMAP (from CF_DIB): %d bytes\n", length));
data = g_try_malloc (length);
if (data)
@@ -564,16 +589,16 @@ gdk_selection_convert (GdkWindow *requestor,
hdr = (BITMAPFILEHEADER *)data;
hdr->bfType = 0x4d42; /* 0x42 = "B" 0x4d = "M" */
/* Compute the size of the entire file. */
- hdr->bfSize = (DWORD) (sizeof(BITMAPFILEHEADER)
+ hdr->bfSize = (DWORD) (sizeof (BITMAPFILEHEADER)
+ ptr->biSize + ptr->biClrUsed
- * sizeof(RGBQUAD) + ptr->biSizeImage);
+ * sizeof (RGBQUAD) + ptr->biSizeImage);
hdr->bfReserved1 = 0;
hdr->bfReserved2 = 0;
/* Compute the offset to the array of color indices. */
- hdr->bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER)
+ hdr->bfOffBits = (DWORD) sizeof (BITMAPFILEHEADER)
+ ptr->biSize + ptr->biClrUsed * sizeof (RGBQUAD);
- /* copy the data behind it */
- memcpy (data + sizeof(BITMAPFILEHEADER), ptr, length - sizeof(BITMAPFILEHEADER));
+ /* Copy the data behind it */
+ memcpy (data + sizeof (BITMAPFILEHEADER), ptr, length - sizeof (BITMAPFILEHEADER));
_gdk_selection_property_store (requestor, target, 8,
data, length);
}
@@ -591,7 +616,12 @@ gdk_selection_convert (GdkWindow *requestor,
if (!API_CALL (OpenClipboard, (GDK_WINDOW_HWND (requestor))))
return;
- /* check if its available */
+ /* Check if it's available. In fact, we can simply call
+ * GetClipboardData (RegisterClipboardFormat (targetname)), but
+ * the global custom format ID space is limited,
+ * (0xC000~0xFFFF), and we better not waste an format ID if we
+ * are just a requestor.
+ */
for ( ; 0 != (fmt = EnumClipboardFormats (fmt)); )
{
char sFormat[80];
@@ -601,7 +631,7 @@ gdk_selection_convert (GdkWindow *requestor,
{
if ((hdata = GetClipboardData (fmt)) != NULL)
{
- /* simply get it without conversion */
+ /* Simply get it without conversion */
guchar *ptr;
gint length;
@@ -673,7 +703,8 @@ gdk_selection_property_get (GdkWindow *requestor,
return 0;
}
- *data = g_malloc (prop->length);
+ *data = g_malloc (prop->length + 1);
+ (*data)[prop->length] = '\0';
if (prop->length > 0)
memmove (*data, prop->data, prop->length);
@@ -713,7 +744,6 @@ gdk_selection_send_notify_for_display (GdkDisplay *display,
GdkAtom property,
guint32 time)
{
- GdkEvent tmp_event;
gchar *sel_name, *tgt_name, *prop_name;
g_return_if_fail (display == _gdk_display);
@@ -968,3 +998,174 @@ gdk_free_compound_text (guchar *ctext)
*/
g_return_if_fail (ctext == NULL);
}
+
+void
+gdk_win32_selection_add_targets (GdkWindow *owner,
+ GdkAtom selection,
+ gint n_targets,
+ GdkAtom *targets)
+{
+ HWND hwnd;
+ const gchar *target_name;
+ guint formatid;
+ gint i;
+ GSList *convertable_formats, *format;
+ gboolean has_set_dib = FALSE, has_real_dib = FALSE;
+
+ if (selection != GDK_SELECTION_CLIPBOARD)
+ return;
+
+ if (owner != NULL)
+ {
+ if (GDK_WINDOW_DESTROYED (owner))
+ return;
+ hwnd = GDK_WINDOW_HWND (owner);
+ }
+
+ if (!API_CALL (OpenClipboard, (hwnd)))
+ return;
+
+ convertable_formats = gdk_pixbuf_get_formats ();
+ for (i = 0; i < n_targets; ++i)
+ {
+ if (targets[i] == _utf8_string)
+ continue;
+
+ target_name = gdk_atom_name (targets[i]);
+ if (!(formatid = RegisterClipboardFormat (target_name))) {
+ WIN32_API_FAILED ("RegisterClipboardFormat");
+ API_CALL (CloseClipboard, ());
+ return;
+ }
+ g_hash_table_replace (_format_atom_table, GINT_TO_POINTER (formatid), targets[i]);
+ SetClipboardData (formatid, NULL);
+
+ /* We should replace the previous image format associated with
+ * CF_DIB with "image/bmp" if we find "image/bmp", "image/x-bmp"
+ * or "image/x-MS-bmp" is available.
+ */
+ if (!has_real_dib &&
+ (!strcmp (target_name, "image/bmp") ||
+ !strcmp (target_name, "image/x-bmp") ||
+ !strcmp (target_name, "image/x-MS-bmp")))
+ {
+ g_hash_table_replace (_format_atom_table,
+ GINT_TO_POINTER (CF_DIB),
+ targets[i]);
+ if (!has_set_dib) {
+ SetClipboardData (CF_DIB, NULL);
+ has_set_dib = TRUE;
+ }
+ has_real_dib = TRUE;
+ continue;
+ }
+
+ for (format = convertable_formats; !has_set_dib && format; format = format->next)
+ {
+ gchar **mime_types =
+ gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) format->data);
+
+ for (; *mime_types; ++mime_types)
+ {
+ if (!strcmp (target_name, *mime_types))
+ {
+ g_hash_table_replace (_format_atom_table,
+ GINT_TO_POINTER (CF_DIB),
+ targets[i]);
+ SetClipboardData (CF_DIB, NULL);
+ has_set_dib = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ g_slist_free (convertable_formats);
+
+ API_CALL (CloseClipboard, ());
+}
+
+/* Convert from types such as "image/jpg" or "image/png" to DIB using
+ * gdk-pixbuf so that image copied from GTK+ apps can be pasted in
+ * native apps like mspaint.exe
+ */
+HGLOBAL
+_gdk_win32_selection_convert_to_dib (HGLOBAL hdata,
+ GdkAtom target)
+{
+ GdkPixbufLoader *loader;
+ GdkPixbuf *pixbuf;
+ const gchar *target_name;
+ guchar *ptr;
+ gchar *bmp_buf;
+ gsize size;
+ gboolean ok;
+
+ if (!(target_name = gdk_atom_name (target)))
+ {
+ GlobalFree (hdata);
+ return NULL;
+ }
+
+ if (!strcmp (target_name, "image/bmp") ||
+ !strcmp (target_name, "image/x-bmp") ||
+ !strcmp (target_name, "image/x-MS-bmp"))
+ {
+ /* No conversion is needed, just strip the BITMAPFILEHEADER */
+ HGLOBAL hdatanew;
+
+ size = GlobalSize (hdata) - 1 - sizeof (BITMAPFILEHEADER);
+ ptr = GlobalLock (hdata);
+ memmove (ptr, ptr + sizeof (BITMAPFILEHEADER), size);
+ GlobalUnlock (hdata);
+ if (!(hdatanew = GlobalReAlloc (hdata, size, 0))) {
+ WIN32_API_FAILED ("GlobalReAlloc");
+ GlobalFree (hdata); /* the old hdata is not freed if error */
+ }
+ return hdatanew;
+ }
+
+ /* We actually provide image formats -other than- "image/bmp" etc
+ * and the requestor is either a native Win32 application or a GTK+
+ * client that requested "image/bmp".
+ */
+ if (!(loader = gdk_pixbuf_loader_new_with_mime_type (target_name, NULL)))
+ {
+ GlobalFree (hdata);
+ return NULL;
+ }
+
+ ptr = GlobalLock (hdata);
+ ok = gdk_pixbuf_loader_write (loader, ptr, GlobalSize (hdata) - 1, NULL) &&
+ gdk_pixbuf_loader_close (loader, NULL);
+
+ GlobalUnlock (hdata);
+ GlobalFree (hdata);
+ hdata = NULL;
+
+ if (ok && (pixbuf = gdk_pixbuf_loader_get_pixbuf (loader)) != NULL)
+ g_object_ref (pixbuf);
+
+ g_object_unref (loader);
+
+ if (ok && gdk_pixbuf_save_to_buffer (pixbuf, &bmp_buf, &size, "bmp", NULL, NULL))
+ {
+ size -= sizeof (BITMAPFILEHEADER);
+ if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, size)))
+ {
+ WIN32_API_FAILED ("GlobalAlloc");
+ ok = FALSE;
+ }
+
+ if (ok)
+ {
+ ptr = GlobalLock (hdata);
+ memcpy (ptr, bmp_buf + sizeof (BITMAPFILEHEADER), size);
+ GlobalUnlock (hdata);
+ }
+
+ g_free (bmp_buf);
+ g_object_unref (pixbuf);
+ }
+
+ return hdata;
+}