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().
This commit is contained in:
Tor Lillqvist 2005-04-04 00:12:26 +00:00 committed by Tor Lillqvist
parent ba433af9fb
commit 0b2ac32cf5
13 changed files with 751 additions and 228 deletions

View File

@ -1,3 +1,46 @@
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().
2005-04-03 Hans Breuer <hans@breuer.org>
[merged from gtk-2-6 branch]

View File

@ -1,3 +1,46 @@
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().
2005-04-03 Hans Breuer <hans@breuer.org>
[merged from gtk-2-6 branch]

View File

@ -1,3 +1,46 @@
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().
2005-04-03 Hans Breuer <hans@breuer.org>
[merged from gtk-2-6 branch]

View File

@ -1047,6 +1047,12 @@ gdk_win32_hdc_get
gdk_win32_hdc_release
#endif
#endif
#if IN_HEADER(__GDK_WIN32_H__)
#if IN_FILE(__GDK_SELECTION_WIN32_C__)
gdk_win32_selection_add_targets
#endif
#endif
#endif
#ifdef GDK_WINDOWING_X11

View File

@ -375,9 +375,7 @@ _win32_on_clipboard_change (HWND hwnd,
g_print ("WM_DRAWCLIPBOARD: owner:%p formats: ", hwndOwner);
for (; 0 != (nFormat = EnumClipboardFormats (nFormat));)
{
char sFormat[80];
if (GetClipboardFormatName (nFormat, sFormat, G_N_ELEMENTS (sFormat)) > 0)
g_print ("%s ", sFormat);
g_print ("%s ", _gdk_win32_cf_to_string (nFormat));
}
g_print ("\n");
CloseClipboard ();

View File

@ -2178,6 +2178,7 @@ gdk_event_translate (GdkDisplay *display,
static gint update_colors_counter = 0;
gint button;
GdkAtom target;
gchar buf[256];
gboolean return_val = FALSE;
@ -3362,7 +3363,62 @@ gdk_event_translate (GdkDisplay *display,
else
return_val = TRUE;
break;
case WM_RENDERFORMAT:
GDK_NOTE (EVENTS, g_print (" %s", _gdk_win32_cf_to_string (msg->wParam)));
if (!(target = g_hash_table_lookup (_format_atom_table, GINT_TO_POINTER (msg->wParam))))
{
GDK_NOTE (EVENTS, g_print (" (target not found)"));
return_val = TRUE;
break;
}
/* We need to render to clipboard immediately, don't call
* append_event()
*/
if (_gdk_event_func)
{
event = gdk_event_new (GDK_SELECTION_REQUEST);
event->selection.window = window;
event->selection.send_event = FALSE;
event->selection.selection = GDK_SELECTION_CLIPBOARD;
event->selection.target = target;
event->selection.property = _gdk_selection_property;
event->selection.requestor = (guint32) msg->hwnd;
event->selection.time = msg->time;
fixup_event (event);
GDK_NOTE (EVENTS, g_print (" (calling gdk_event_func)"));
GDK_NOTE (EVENTS, print_event (event));
(*_gdk_event_func) (event, _gdk_event_data);
gdk_event_free (event);
/* Now the clipboard owner should have rendered */
if (!_delayed_rendering_data)
GDK_NOTE (EVENTS, g_print (" (no _delayed_rendering_data?)"));
else
{
if (msg->wParam == CF_DIB)
{
_delayed_rendering_data =
_gdk_win32_selection_convert_to_dib (_delayed_rendering_data,
target);
if (!_delayed_rendering_data)
{
g_warning ("Cannot convert to DIB from delayed rendered image");
break;
}
}
/* The requestor is holding the clipboard, no
* OpenClipboard() is required/possible
*/
API_CALL (SetClipboardData, (msg->wParam, _delayed_rendering_data));
_delayed_rendering_data = NULL;
}
}
break;
#ifdef HAVE_WINTAB
case WM_ACTIVATE:
/* Bring any tablet contexts to the top of the overlap order when

View File

@ -36,7 +36,7 @@ GdkWindow *_gdk_root = NULL;
gint _gdk_num_monitors;
GdkRectangle *_gdk_monitors = NULL;
gint _gdk_offset_x, _gdk_offset_y;
gint _gdk_offset_x, _gdk_offset_y;
HDC _gdk_display_hdc;
HINSTANCE _gdk_dll_hinstance;
@ -50,9 +50,11 @@ WORD _cf_rtf;
WORD _cf_utf8_string;
GdkAtom _utf8_string;
GdkAtom _text_uri_list;
GdkAtom _targets;
GdkAtom _text_uri_list;
GdkAtom _image_bmp;
GdkAtom _local_dnd;
GdkAtom _gdk_win32_dropfiles;
GdkAtom _gdk_ole2_dnd;
@ -66,3 +68,6 @@ gint _gdk_max_colors = 0;
gboolean _sizemove_in_progress = FALSE;
gboolean _ignore_destroy_clipboard = FALSE;
HGLOBAL _delayed_rendering_data = NULL;
GHashTable *_format_atom_table = NULL;

View File

@ -112,9 +112,11 @@ _gdk_windowing_init (void)
_cf_utf8_string = RegisterClipboardFormat ("UTF8_STRING");
_utf8_string = gdk_atom_intern ("UTF8_STRING", FALSE);
_text_uri_list = gdk_atom_intern ("text/uri-list", FALSE);
_targets = gdk_atom_intern ("TARGETS", FALSE);
_text_uri_list = gdk_atom_intern ("text/uri-list", FALSE);
_image_bmp = gdk_atom_intern ("image/bmp", FALSE);
_local_dnd = gdk_atom_intern ("LocalDndSelection", FALSE);
_gdk_win32_dropfiles = gdk_atom_intern ("DROPFILES_DND", FALSE);
_gdk_ole2_dnd = gdk_atom_intern ("OLE2_DND", FALSE);
@ -250,7 +252,7 @@ gdk_notify_startup_complete (void)
*/
static gchar *
static_printf (const gchar *format,
...)
...)
{
static gchar buf[10000];
gchar *msg;
@ -922,6 +924,71 @@ _gdk_win32_key_to_string (LONG lParam)
return static_printf ("unk-%#lx", lParam);
}
gchar *
_gdk_win32_cf_to_string (UINT format)
{
char buf[100];
switch (format)
{
#define CASE(x) case CF_##x: return #x
CASE (BITMAP);
CASE (DIB);
#ifdef CF_DIBV5
CASE (DIBV5);
#endif
CASE (DIF);
CASE (DSPBITMAP);
CASE (DSPENHMETAFILE);
CASE (DSPMETAFILEPICT);
CASE (DSPTEXT);
CASE (ENHMETAFILE);
CASE (HDROP);
CASE (LOCALE);
CASE (METAFILEPICT);
CASE (OEMTEXT);
CASE (OWNERDISPLAY);
CASE (PALETTE);
CASE (PENDATA);
CASE (RIFF);
CASE (SYLK);
CASE (TEXT);
CASE (WAVE);
CASE (TIFF);
CASE (UNICODETEXT);
default:
if (format >= CF_GDIOBJFIRST &&
format <= CF_GDIOBJLAST)
return static_printf ("CF_GDIOBJ%d", format - CF_GDIOBJFIRST);
if (format >= CF_PRIVATEFIRST &&
format <= CF_PRIVATELAST)
return static_printf ("CF_PRIVATE%d", format - CF_PRIVATEFIRST);
if (GetClipboardFormatName (format, buf, sizeof (buf)))
return static_printf ("%s", buf);
else
return static_printf ("unk-%#lx", format);
}
}
gchar *
_gdk_win32_data_to_string (const guchar *data,
int nbytes)
{
GString *s = g_string_new ("");
int i;
gchar *retval;
for (i = 0; i < nbytes; i++)
if (data[i] >=' ' && data[i] <= '~')
g_string_append_printf (s, "%c ", data[i]);
else
g_string_append_printf (s, "%02X ", data[i]);
retval = static_printf ("%s", s->str);
g_string_free (s, TRUE);
return retval;
}
gchar *
_gdk_win32_rect_to_string (const RECT *rect)

View File

@ -401,6 +401,9 @@ gchar *_gdk_win32_psendcap_to_string (DWORD pen_style);
gchar *_gdk_win32_psjoin_to_string (DWORD pen_style);
gchar *_gdk_win32_message_to_string (UINT msg);
gchar *_gdk_win32_key_to_string (LONG lParam);
gchar *_gdk_win32_cf_to_string (UINT format);
gchar *_gdk_win32_data_to_string (const guchar*data,
int nbytes);
gchar *_gdk_win32_rect_to_string (const RECT *rect);
gchar *_gdk_win32_gdkrectangle_to_string (const GdkRectangle *rect);
@ -473,12 +476,13 @@ extern gboolean _gdk_keyboard_has_altgr;
extern WORD _cf_rtf;
extern WORD _cf_utf8_string;
/* GdkAtoms: Targets */
/* GdkAtoms: targets */
extern GdkAtom _utf8_string;
extern GdkAtom _compound_text;
extern GdkAtom _text_uri_list;
extern GdkAtom _targets;
extern GdkAtom _text_uri_list;
extern GdkAtom _image_bmp;
/* DND selections */
extern GdkAtom _local_dnd;
extern GdkAtom _gdk_win32_dropfiles;
@ -500,6 +504,17 @@ extern gboolean _sizemove_in_progress;
/* TRUE when we are emptying the clipboard ourselves */
extern gboolean _ignore_destroy_clipboard;
/* Mapping from registered clipboard format id (native) to
* corresponding GdkAtom
*/
extern GHashTable *_format_atom_table;
/* Hold the result of a delayed rendering */
extern HGLOBAL _delayed_rendering_data;
HGLOBAL _gdk_win32_selection_convert_to_dib (HGLOBAL hdata,
GdkAtom target);
/* Initialization */
void _gdk_windowing_window_init (void);
void _gdk_root_window_size_init (void);

View File

@ -265,7 +265,7 @@ gdk_property_change (GdkWindow *window,
GDK_NOTE (DND,
(prop_name = gdk_atom_name (property),
type_name = gdk_atom_name (type),
g_print ("gdk_property_change: %p %#x (%s) %#x (%s) %s %d*%d bytes %.10s\n",
g_print ("gdk_property_change: %p %#x (%s) %#x (%s) %s %d*%d bytes: %s\n",
GDK_WINDOW_HWND (window),
(guint) property, prop_name,
(guint) type, type_name,
@ -273,201 +273,221 @@ gdk_property_change (GdkWindow *window,
(mode == GDK_PROP_MODE_PREPEND ? "PREPEND" :
(mode == GDK_PROP_MODE_APPEND ? "APPEND" :
"???"))),
format, nelements, data),
format, nelements,
_gdk_win32_data_to_string (data, MIN (10, format*nelements/8))),
g_free (prop_name),
g_free (type_name)));
if (property == _gdk_selection_property
&& ((type == GDK_TARGET_STRING && GetACP () == 1252) ||
type == _utf8_string)
&& format == 8
&& mode == GDK_PROP_MODE_REPLACE)
{
if (!OpenClipboard (GDK_WINDOW_HWND (window)))
if ((type == GDK_TARGET_STRING && GetACP () == 1252) ||
type == _utf8_string)
{
WIN32_API_FAILED ("OpenClipboard");
return;
}
if (!OpenClipboard (GDK_WINDOW_HWND (window)))
{
WIN32_API_FAILED ("OpenClipboard");
return;
}
if (type == _utf8_string)
{
/* Check if only ASCII */
for (i = 0; i < nelements; i++)
if (data[i] >= 0200)
break;
}
else /* if (type == GDK_TARGET_STRING) */
{
/* Check that no 0200..0240 chars present, as they
* differ between ISO-8859-1 and CP1252.
*/
for (i = 0; i < nelements; i++)
if (data[i] >= 0200 && data[i] < 0240)
break;
}
nchars = g_utf8_strlen (data, nelements);
if (type == _utf8_string)
{
/* Check if only ASCII */
for (i = 0; i < nelements; i++)
if (data[i] >= 0200)
break;
}
else /* if (type == GDK_TARGET_STRING) */
{
/* Check that no 0200..0240 chars present, as they
* differ between ISO-8859-1 and CP1252.
*/
for (i = 0; i < nelements; i++)
if (data[i] >= 0200 && data[i] < 0240)
break;
}
nchars = g_utf8_strlen (data, nelements);
if (i == nelements)
{
/* If UTF-8 and only ASCII, or if STRING (ISO-8859-1) and
* system codepage is CP1252, use CF_TEXT and the data as
* such.
*/
method = SYSTEM_CODEPAGE;
size = nelements;
for (i = 0; i < nelements; i++)
if (data[i] == '\n')
if (i == nelements)
{
/* If UTF-8 and only ASCII, or if STRING (ISO-8859-1)
* and system codepage is CP1252, use CF_TEXT and the
* data as such.
*/
method = SYSTEM_CODEPAGE;
size = nelements;
for (i = 0; i < nelements; i++)
if (data[i] == '\n')
size++;
size++;
size++;
GDK_NOTE (DND, g_print ("... as text: %.40s\n", data));
}
else if (G_WIN32_IS_NT_BASED ())
{
/* On NT, use CF_UNICODETEXT if any non-system codepage char
* present.
*/
method = UNICODE_TEXT;
wcptr = g_utf8_to_utf16 (data, nelements, NULL, &wclen, NULL);
wclen++; /* Terminating 0 */
size = wclen * 2;
GDK_NOTE (DND, g_print ("... as Unicode\n"));
}
else if (find_common_locale (data, nelements, nchars, &lcid, &buf, &size))
{
/* On Win9x, if all chars are in the default code page of
* some installed locale, use CF_TEXT and CF_LOCALE.
*/
method = SINGLE_LOCALE;
GDK_NOTE (DND, g_print ("... as text in locale %#lx %d bytes\n",
(gulong) lcid, size));
}
else
{
/* On Win9x, otherwise use RTF */
const guchar *p = data;
method = RICH_TEXT;
rtf = g_string_new ("{\\rtf1\\uc0 ");
while (p < data + nelements)
{
if (*p == '{' ||
*p == '\\' ||
*p == '}')
{
rtf = g_string_append_c (rtf, '\\');
rtf = g_string_append_c (rtf, *p);
p++;
}
else if (*p < 0200 && *p >= ' ')
{
rtf = g_string_append_c (rtf, *p);
p++;
}
else
{
guchar *q;
gint n;
rtf = g_string_append (rtf, "\\uNNNNN ");
rtf->len -= 6; /* five digits and a space */
q = rtf->str + rtf->len;
n = g_sprintf (q, "%d ", g_utf8_get_char (p));
g_assert (n <= 6);
rtf->len += n;
p = g_utf8_next_char (p);
}
GDK_NOTE (DND, g_print ("... as text: %.40s\n", data));
}
rtf = g_string_append (rtf, "}");
size = rtf->len + 1;
GDK_NOTE (DND, g_print ("... as RTF: %.40s\n", rtf->str));
}
if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, size)))
{
WIN32_API_FAILED ("GlobalAlloc");
if (!CloseClipboard ())
WIN32_API_FAILED ("CloseClipboard");
if (buf != NULL)
g_free (buf);
if (rtf != NULL)
g_string_free (rtf, TRUE);
return;
}
ucptr = GlobalLock (hdata);
switch (method)
{
case SYSTEM_CODEPAGE:
cf = CF_TEXT;
for (i = 0; i < nelements; i++)
else if (G_WIN32_IS_NT_BASED ())
{
if (data[i] == '\n')
*ucptr++ = '\r';
*ucptr++ = data[i];
/* On NT, use CF_UNICODETEXT if any non-system codepage
* char present.
*/
method = UNICODE_TEXT;
wcptr = g_utf8_to_utf16 (data, nelements, NULL, &wclen, NULL);
wclen++; /* Terminating 0 */
size = wclen * 2;
GDK_NOTE (DND, g_print ("... as Unicode\n"));
}
*ucptr++ = '\0';
break;
case UNICODE_TEXT:
cf = CF_UNICODETEXT;
memmove (ucptr, wcptr, size);
g_free (wcptr);
break;
case SINGLE_LOCALE:
cf = CF_TEXT;
memmove (ucptr, buf, size);
g_free (buf);
/* Set the CF_LOCALE clipboard data, too */
if (!(hlcid = GlobalAlloc (GMEM_MOVEABLE, sizeof (LCID))))
WIN32_API_FAILED ("GlobalAlloc"), ok = FALSE;
if (ok)
else if (find_common_locale (data, nelements, nchars, &lcid, &buf, &size))
{
lcidptr = GlobalLock (hlcid);
*lcidptr = lcid;
GlobalUnlock (hlcid);
if (!SetClipboardData (CF_LOCALE, hlcid))
WIN32_API_FAILED ("SetClipboardData (CF_LOCALE)"), ok = FALSE;
/* On Win9x, if all chars are in the default code page
* of some installed locale, use CF_TEXT and CF_LOCALE.
*/
method = SINGLE_LOCALE;
GDK_NOTE (DND, g_print ("... as text in locale %#lx %d bytes\n",
(gulong) lcid, size));
}
break;
case RICH_TEXT:
cf = _cf_rtf;
memmove (ucptr, rtf->str, size);
g_string_free (rtf, TRUE);
/* Set the UTF8_STRING clipboard data, too, for other
* GTK+ apps to use (won't bother reading RTF).
*/
if (!(hutf8 = GlobalAlloc (GMEM_MOVEABLE, nelements)))
WIN32_API_FAILED ("GlobalAlloc");
else
{
guchar *utf8ptr = GlobalLock (hutf8);
memmove (utf8ptr, data, nelements);
GlobalUnlock (hutf8);
if (!SetClipboardData (_cf_utf8_string, hutf8))
WIN32_API_FAILED ("SetClipboardData (UTF8_STRING)");
/* On Win9x, otherwise use RTF */
const guchar *p = data;
method = RICH_TEXT;
rtf = g_string_new ("{\\rtf1\\uc0 ");
while (p < data + nelements)
{
if (*p == '{' ||
*p == '\\' ||
*p == '}')
{
rtf = g_string_append_c (rtf, '\\');
rtf = g_string_append_c (rtf, *p);
p++;
}
else if (*p < 0200 && *p >= ' ')
{
rtf = g_string_append_c (rtf, *p);
p++;
}
else
{
guchar *q;
gint n;
rtf = g_string_append (rtf, "\\uNNNNN ");
rtf->len -= 6; /* five digits and a space */
q = rtf->str + rtf->len;
n = g_sprintf (q, "%d ", g_utf8_get_char (p));
g_assert (n <= 6);
rtf->len += n;
p = g_utf8_next_char (p);
}
}
rtf = g_string_append (rtf, "}");
size = rtf->len + 1;
GDK_NOTE (DND, g_print ("... as RTF: %.40s\n", rtf->str));
}
if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, size)))
{
WIN32_API_FAILED ("GlobalAlloc");
if (!CloseClipboard ())
WIN32_API_FAILED ("CloseClipboard");
if (buf != NULL)
g_free (buf);
if (rtf != NULL)
g_string_free (rtf, TRUE);
return;
}
break;
default:
g_assert_not_reached ();
}
ucptr = GlobalLock (hdata);
GlobalUnlock (hdata);
if (ok && !SetClipboardData (cf, hdata))
WIN32_API_FAILED ("SetClipboardData"), ok = FALSE;
switch (method)
{
case SYSTEM_CODEPAGE:
cf = CF_TEXT;
for (i = 0; i < nelements; i++)
{
if (data[i] == '\n')
*ucptr++ = '\r';
*ucptr++ = data[i];
}
*ucptr++ = '\0';
break;
case UNICODE_TEXT:
cf = CF_UNICODETEXT;
memmove (ucptr, wcptr, size);
g_free (wcptr);
break;
case SINGLE_LOCALE:
cf = CF_TEXT;
memmove (ucptr, buf, size);
g_free (buf);
/* Set the CF_LOCALE clipboard data, too */
if (!(hlcid = GlobalAlloc (GMEM_MOVEABLE, sizeof (LCID))))
WIN32_API_FAILED ("GlobalAlloc"), ok = FALSE;
if (ok)
{
lcidptr = GlobalLock (hlcid);
*lcidptr = lcid;
GlobalUnlock (hlcid);
if (!SetClipboardData (CF_LOCALE, hlcid))
WIN32_API_FAILED ("SetClipboardData (CF_LOCALE)"), ok = FALSE;
}
break;
case RICH_TEXT:
cf = _cf_rtf;
memmove (ucptr, rtf->str, size);
g_string_free (rtf, TRUE);
/* Set the UTF8_STRING clipboard data, too, for other
* GTK+ apps to use (won't bother reading RTF).
*/
if (!(hutf8 = GlobalAlloc (GMEM_MOVEABLE, nelements)))
WIN32_API_FAILED ("GlobalAlloc");
else
{
guchar *utf8ptr = GlobalLock (hutf8);
memmove (utf8ptr, data, nelements);
GlobalUnlock (hutf8);
if (!SetClipboardData (_cf_utf8_string, hutf8))
WIN32_API_FAILED ("SetClipboardData (UTF8_STRING)");
}
break;
default:
g_assert_not_reached ();
}
GlobalUnlock (hdata);
if (ok && !SetClipboardData (cf, hdata))
WIN32_API_FAILED ("SetClipboardData"), ok = FALSE;
if (!CloseClipboard ())
WIN32_API_FAILED ("CloseClipboard");
if (!CloseClipboard ())
WIN32_API_FAILED ("CloseClipboard");
}
else
{
/* Delayed Rendering. We can't assign hdata to the clipboard
* here as type may be "image/png", "image/jpg", etc. In
* this case there's a further conversion afterwards.
*/
_delayed_rendering_data = NULL;
if (!(hdata = GlobalAlloc (GMEM_MOVEABLE, nelements > 0 ? nelements : 1)))
{
WIN32_API_FAILED ("GlobalAlloc");
return;
}
ucptr = GlobalLock (hdata);
memcpy (ucptr, data, nelements);
GlobalUnlock (hdata);
_delayed_rendering_data = hdata;
}
}
else
g_warning ("gdk_property_change: General case not implemented");
@ -592,13 +612,15 @@ gdk_screen_get_setting (GdkScreen *screen,
ncm.cbSize = sizeof(NONCLIENTMETRICS);
if (SystemParametersInfo (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, FALSE))
{
/* Pango finally uses GetDeviceCaps to scale, we use simple approximation here */
/* Pango finally uses GetDeviceCaps to scale, we use simple
* approximation here.
*/
int nHeight = (0 > ncm.lfMenuFont.lfHeight ? -3*ncm.lfMenuFont.lfHeight/4 : 10);
if (OUT_STRING_PRECIS == ncm.lfMenuFont.lfOutPrecision)
GDK_NOTE(MISC, g_print("gdk_screen_get_setting(%s) : ignoring bitmap font '%s'\n",
name, ncm.lfMenuFont.lfFaceName));
else if (ncm.lfMenuFont.lfFaceName && strlen(ncm.lfMenuFont.lfFaceName) > 0 &&
/* avoid issues like those described in bug #135098 */
/* Avoid issues like those described in bug #135098 */
g_utf8_validate (ncm.lfMenuFont.lfFaceName, -1, NULL))
{
char* s = g_strdup_printf ("%s %d", ncm.lfMenuFont.lfFaceName, nHeight);

View File

@ -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));
data[i++] = _utf8_string;
}
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));
}
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;
}

View File

@ -79,6 +79,11 @@ void gdk_win32_hdc_release (GdkDrawable *drawable,
GdkGC *gc,
GdkGCValuesMask usage);
void gdk_win32_selection_add_targets (GdkWindow *owner,
GdkAtom selection,
gint n_targets,
GdkAtom *targets);
G_END_DECLS
#endif /* __GDK_WIN32_H__ */

View File

@ -64,6 +64,10 @@
#include "x11/gdkx.h"
#endif
#ifdef GDK_WINDOWING_WIN32
#include "win32/gdkwin32.h"
#endif
#include "gtkalias.h"
#undef DEBUG_SELECTION
@ -750,6 +754,9 @@ gtk_selection_add_target (GtkWidget *widget,
list = gtk_selection_target_list_get (widget, selection);
gtk_target_list_add (list, target, 0, info);
#ifdef GDK_WINDOWING_WIN32
gdk_win32_selection_add_targets (widget->window, selection, 1, &target);
#endif
}
/**
@ -776,6 +783,18 @@ gtk_selection_add_targets (GtkWidget *widget,
list = gtk_selection_target_list_get (widget, selection);
gtk_target_list_add_table (list, targets, ntargets);
#ifdef GDK_WINDOWING_WIN32
{
int i;
GdkAtom *atoms = g_new (GdkAtom, ntargets);
for (i = 0; i < ntargets; ++i)
atoms[i] = gdk_atom_intern (targets[i].target, FALSE);
gdk_win32_selection_add_targets (widget->window, selection, ntargets, atoms);
g_free (atoms);
}
#endif
}