winex11: Add a helper function to register builtin clipboard formats.
[wine.git] / dlls / winex11.drv / clipboard.c
blob602a69a0bf0ac3f78bd526d83788c72966d55228
1 /*
2 * X11 clipboard windows driver
4 * Copyright 1994 Martin Ayotte
5 * Copyright 1996 Alex Korobka
6 * Copyright 1999 Noel Borthwick
7 * Copyright 2003 Ulrich Czekalla for CodeWeavers
8 * Copyright 2014 Damjan Jovanovic
9 * Copyright 2016 Alexandre Julliard
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 * NOTES:
26 * This file contains the X specific implementation for the windows
27 * Clipboard API.
29 * Wine's internal clipboard is exposed to external apps via the X
30 * selection mechanism.
31 * Currently the driver asserts ownership via two selection atoms:
32 * 1. PRIMARY(XA_PRIMARY)
33 * 2. CLIPBOARD
35 * In our implementation, the CLIPBOARD selection takes precedence over PRIMARY,
36 * i.e. if a CLIPBOARD selection is available, it is used instead of PRIMARY.
37 * When Wine takes ownership of the clipboard, it takes ownership of BOTH selections.
38 * While giving up selection ownership, if the CLIPBOARD selection is lost,
39 * it will lose both PRIMARY and CLIPBOARD and empty the clipboard.
40 * However if only PRIMARY is lost, it will continue to hold the CLIPBOARD selection
41 * (leaving the clipboard cache content unaffected).
43 * Every format exposed via a windows clipboard format is also exposed through
44 * a corresponding X selection target. A selection target atom is synthesized
45 * whenever a new Windows clipboard format is registered via RegisterClipboardFormat,
46 * or when a built-in format is used for the first time.
47 * Windows native format are exposed by prefixing the format name with "<WCF>"
48 * This allows us to uniquely identify windows native formats exposed by other
49 * running WINE apps.
51 * In order to allow external applications to query WINE for supported formats,
52 * we respond to the "TARGETS" selection target. (See EVENT_SelectionRequest
53 * for implementation) We use the same mechanism to query external clients for
54 * availability of a particular format, by caching the list of available targets
55 * by using the clipboard cache's "delayed render" mechanism. If a selection client
56 * does not support the "TARGETS" selection target, we actually attempt to retrieve
57 * the format requested as a fallback mechanism.
59 * Certain Windows native formats are automatically converted to X native formats
60 * and vice versa. If a native format is available in the selection, it takes
61 * precedence, in order to avoid unnecessary conversions.
63 * FIXME: global format list needs a critical section
66 #include "config.h"
67 #include "wine/port.h"
69 #include <string.h>
70 #include <stdarg.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #ifdef HAVE_UNISTD_H
74 # include <unistd.h>
75 #endif
76 #include <fcntl.h>
77 #include <limits.h>
78 #include <time.h>
79 #include <assert.h>
81 #include "windef.h"
82 #include "winbase.h"
83 #include "shlobj.h"
84 #include "shellapi.h"
85 #include "shlwapi.h"
86 #include "x11drv.h"
87 #include "wine/list.h"
88 #include "wine/debug.h"
89 #include "wine/unicode.h"
90 #include "wine/server.h"
92 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
94 /* Maximum wait time for selection notify */
95 #define SELECTION_RETRIES 500 /* wait for .5 seconds */
96 #define SELECTION_WAIT 1000 /* us */
98 #define SELECTION_UPDATE_DELAY 2000 /* delay between checks of the X11 selection */
100 /* Selection masks */
101 #define S_NOSELECTION 0
102 #define S_PRIMARY 1
103 #define S_CLIPBOARD 2
105 struct tagWINE_CLIPDATA; /* Forward */
107 typedef BOOL (*EXPORTFUNC)( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
108 typedef HANDLE (*IMPORTFUNC)( Atom type, const void *data, size_t size );
110 typedef struct clipboard_format
112 struct list entry;
113 UINT id;
114 Atom atom;
115 IMPORTFUNC import;
116 EXPORTFUNC export;
117 } WINE_CLIPFORMAT, *LPWINE_CLIPFORMAT;
119 typedef struct tagWINE_CLIPDATA {
120 struct list entry;
121 UINT wFormatID;
122 HANDLE hData;
123 } WINE_CLIPDATA, *LPWINE_CLIPDATA;
125 static int selectionAcquired = 0; /* Contains the current selection masks */
126 static Window selectionWindow = None; /* The top level X window which owns the selection */
127 static Atom selectionCacheSrc = XA_PRIMARY; /* The selection source from which the clipboard cache was filled */
129 static HANDLE import_data( Atom type, const void *data, size_t size );
130 static HANDLE import_enhmetafile( Atom type, const void *data, size_t size );
131 static HANDLE import_metafile( Atom type, const void *data, size_t size );
132 static HANDLE import_pixmap( Atom type, const void *data, size_t size );
133 static HANDLE import_image_bmp( Atom type, const void *data, size_t size );
134 static HANDLE import_string( Atom type, const void *data, size_t size );
135 static HANDLE import_utf8_string( Atom type, const void *data, size_t size );
136 static HANDLE import_compound_text( Atom type, const void *data, size_t size );
137 static HANDLE import_text_uri_list( Atom type, const void *data, size_t size );
138 static HANDLE import_targets( Atom type, const void *data, size_t size );
140 static BOOL export_data( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
141 static BOOL export_string( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
142 static BOOL export_utf8_string( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
143 static BOOL export_compound_text( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
144 static BOOL export_pixmap( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
145 static BOOL export_image_bmp( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
146 static BOOL export_metafile( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
147 static BOOL export_enhmetafile( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
148 static BOOL export_text_html( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
149 static BOOL export_hdrop( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
150 static BOOL export_targets( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
151 static BOOL export_multiple( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
153 static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData);
154 static int X11DRV_CLIPBOARD_QueryAvailableData(Display *display);
155 static BOOL X11DRV_CLIPBOARD_ReadSelectionData(Display *display, LPWINE_CLIPDATA lpData);
156 static BOOL X11DRV_CLIPBOARD_ReadProperty( Display *display, Window w, Atom prop,
157 Atom *type, unsigned char **data, unsigned long *datasize );
158 static BOOL X11DRV_CLIPBOARD_RenderFormat(Display *display, LPWINE_CLIPDATA lpData);
159 static void empty_clipboard(void);
161 /* Clipboard formats */
163 static const WCHAR RichTextFormatW[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
164 static const WCHAR GIFW[] = {'G','I','F',0};
165 static const WCHAR JFIFW[] = {'J','F','I','F',0};
166 static const WCHAR PNGW[] = {'P','N','G',0};
167 static const WCHAR HTMLFormatW[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
169 static const struct
171 const WCHAR *name;
172 UINT id;
173 UINT data;
174 IMPORTFUNC import;
175 EXPORTFUNC export;
176 } builtin_formats[] =
178 { 0, CF_TEXT, XA_STRING, import_string, export_string },
179 { 0, CF_TEXT, XATOM_text_plain, import_string, export_string },
180 { 0, CF_BITMAP, XATOM_WCF_BITMAP, import_data, NULL },
181 { 0, CF_METAFILEPICT, XATOM_WCF_METAFILEPICT, import_metafile, export_metafile },
182 { 0, CF_SYLK, XATOM_WCF_SYLK, import_data, export_data },
183 { 0, CF_DIF, XATOM_WCF_DIF, import_data, export_data },
184 { 0, CF_TIFF, XATOM_WCF_TIFF, import_data, export_data },
185 { 0, CF_OEMTEXT, XATOM_WCF_OEMTEXT, import_data, export_data },
186 { 0, CF_DIB, XA_PIXMAP, import_pixmap, export_pixmap },
187 { 0, CF_PALETTE, XATOM_WCF_PALETTE, import_data, export_data },
188 { 0, CF_PENDATA, XATOM_WCF_PENDATA, import_data, export_data },
189 { 0, CF_RIFF, XATOM_WCF_RIFF, import_data, export_data },
190 { 0, CF_WAVE, XATOM_WCF_WAVE, import_data, export_data },
191 { 0, CF_UNICODETEXT, XATOM_UTF8_STRING, import_utf8_string, export_utf8_string },
192 { 0, CF_UNICODETEXT, XATOM_COMPOUND_TEXT, import_compound_text, export_compound_text },
193 { 0, CF_ENHMETAFILE, XATOM_WCF_ENHMETAFILE, import_enhmetafile, export_enhmetafile },
194 { 0, CF_HDROP, XATOM_text_uri_list, import_text_uri_list, export_hdrop },
195 { 0, CF_LOCALE, XATOM_WCF_LOCALE, import_data, export_data },
196 { 0, CF_DIBV5, XATOM_WCF_DIBV5, import_data, export_data },
197 { 0, CF_OWNERDISPLAY, XATOM_WCF_OWNERDISPLAY, import_data, export_data },
198 { 0, CF_DSPTEXT, XATOM_WCF_DSPTEXT, import_data, export_data },
199 { 0, CF_DSPBITMAP, XATOM_WCF_DSPBITMAP, import_data, export_data },
200 { 0, CF_DSPMETAFILEPICT, XATOM_WCF_DSPMETAFILEPICT, import_data, export_data },
201 { 0, CF_DSPENHMETAFILE, XATOM_WCF_DSPENHMETAFILE, import_data, export_data },
202 { 0, CF_DIB, XATOM_image_bmp, import_image_bmp, export_image_bmp },
203 { RichTextFormatW, 0, XATOM_text_rtf, import_data, export_data },
204 { RichTextFormatW, 0, XATOM_text_richtext, import_data, export_data },
205 { GIFW, 0, XATOM_image_gif, import_data, export_data },
206 { JFIFW, 0, XATOM_image_jpeg, import_data, export_data },
207 { PNGW, 0, XATOM_image_png, import_data, export_data },
208 { HTMLFormatW, 0, XATOM_HTML_Format, import_data, export_data },
209 { HTMLFormatW, 0, XATOM_text_html, import_data, export_text_html },
210 { 0, 0, XATOM_TARGETS, import_targets, export_targets },
211 { 0, 0, XATOM_MULTIPLE, NULL, export_multiple },
214 static struct list format_list = LIST_INIT( format_list );
216 #define NB_BUILTIN_FORMATS (sizeof(builtin_formats) / sizeof(builtin_formats[0]))
217 #define GET_ATOM(prop) (((prop) < FIRST_XATOM) ? (Atom)(prop) : X11DRV_Atoms[(prop) - FIRST_XATOM])
219 static struct clipboard_format **current_x11_formats;
220 static unsigned int nb_current_x11_formats;
224 * Cached clipboard data.
226 static struct list data_list = LIST_INIT( data_list );
227 static UINT ClipDataCount = 0;
230 /**************************************************************************
231 * Internal Clipboard implementation methods
232 **************************************************************************/
234 static Window thread_selection_wnd(void)
236 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
237 Window w = thread_data->selection_wnd;
239 if (!w)
241 w = XCreateWindow(thread_data->display, root_window, 0, 0, 1, 1, 0, CopyFromParent,
242 InputOnly, CopyFromParent, 0, NULL);
243 if (w)
245 thread_data->selection_wnd = w;
247 XSelectInput(thread_data->display, w, PropertyChangeMask);
249 else
250 FIXME("Failed to create window. Fetching selection data will fail.\n");
253 return w;
256 static const char *debugstr_format( UINT id )
258 WCHAR buffer[256];
260 if (GetClipboardFormatNameW( id, buffer, 256 ))
261 return wine_dbg_sprintf( "%04x %s", id, debugstr_w(buffer) );
263 switch (id)
265 case 0: return "(none)";
266 #define BUILTIN(id) case id: return #id;
267 BUILTIN(CF_TEXT)
268 BUILTIN(CF_BITMAP)
269 BUILTIN(CF_METAFILEPICT)
270 BUILTIN(CF_SYLK)
271 BUILTIN(CF_DIF)
272 BUILTIN(CF_TIFF)
273 BUILTIN(CF_OEMTEXT)
274 BUILTIN(CF_DIB)
275 BUILTIN(CF_PALETTE)
276 BUILTIN(CF_PENDATA)
277 BUILTIN(CF_RIFF)
278 BUILTIN(CF_WAVE)
279 BUILTIN(CF_UNICODETEXT)
280 BUILTIN(CF_ENHMETAFILE)
281 BUILTIN(CF_HDROP)
282 BUILTIN(CF_LOCALE)
283 BUILTIN(CF_DIBV5)
284 BUILTIN(CF_OWNERDISPLAY)
285 BUILTIN(CF_DSPTEXT)
286 BUILTIN(CF_DSPBITMAP)
287 BUILTIN(CF_DSPMETAFILEPICT)
288 BUILTIN(CF_DSPENHMETAFILE)
289 #undef BUILTIN
290 default: return wine_dbg_sprintf( "%04x", id );
294 static const char *debugstr_xatom( Atom atom )
296 const char *ret;
297 char *name;
299 if (!atom) return "(None)";
300 name = XGetAtomName( thread_display(), atom );
301 ret = debugstr_a( name );
302 XFree( name );
303 return ret;
307 static int is_atom_error( Display *display, XErrorEvent *event, void *arg )
309 return (event->error_code == BadAtom);
312 static int is_window_error( Display *display, XErrorEvent *event, void *arg )
314 return (event->error_code == BadWindow);
318 /**************************************************************************
319 * find_win32_format
321 static struct clipboard_format *find_win32_format( UINT id )
323 struct clipboard_format *format;
325 LIST_FOR_EACH_ENTRY( format, &format_list, struct clipboard_format, entry )
326 if (format->id == id) return format;
327 return NULL;
331 /**************************************************************************
332 * find_x11_format
334 static struct clipboard_format *find_x11_format( Atom atom )
336 struct clipboard_format *format;
338 LIST_FOR_EACH_ENTRY( format, &format_list, struct clipboard_format, entry )
339 if (format->atom == atom) return format;
340 return NULL;
344 /**************************************************************************
345 * register_builtin_formats
347 static void register_builtin_formats(void)
349 struct clipboard_format *formats;
350 unsigned int i;
352 if (!(formats = HeapAlloc( GetProcessHeap(), 0, NB_BUILTIN_FORMATS * sizeof(*formats)))) return;
354 for (i = 0; i < NB_BUILTIN_FORMATS; i++)
356 if (builtin_formats[i].name)
357 formats[i].id = RegisterClipboardFormatW( builtin_formats[i].name );
358 else
359 formats[i].id = builtin_formats[i].id;
361 formats[i].atom = GET_ATOM(builtin_formats[i].data);
362 formats[i].import = builtin_formats[i].import;
363 formats[i].export = builtin_formats[i].export;
364 list_add_tail( &format_list, &formats[i].entry );
369 /**************************************************************************
370 * register_formats
372 static void register_formats( const UINT *ids, const Atom *atoms, unsigned int count )
374 struct clipboard_format *formats;
375 unsigned int i;
377 if (!(formats = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*formats)))) return;
379 for (i = 0; i < count; i++)
381 formats[i].id = ids[i];
382 formats[i].atom = atoms[i];
383 formats[i].import = import_data;
384 formats[i].export = export_data;
385 list_add_tail( &format_list, &formats[i].entry );
386 TRACE( "registered %s atom %s\n", debugstr_format( ids[i] ), debugstr_xatom( atoms[i] ));
391 /**************************************************************************
392 * register_win32_formats
394 * Register Win32 clipboard formats the first time we encounter them.
396 static void register_win32_formats( const UINT *ids, UINT size )
398 unsigned int count, len;
399 UINT new_ids[256];
400 char *names[256];
401 Atom atoms[256];
402 WCHAR buffer[256];
404 if (list_empty( &format_list)) register_builtin_formats();
406 while (size)
408 for (count = 0; count < 256 && size; ids++, size--)
410 if (find_win32_format( *ids )) continue; /* it already exists */
411 if (!GetClipboardFormatNameW( *ids, buffer, 256 )) continue; /* not a named format */
412 if (!(len = WideCharToMultiByte( CP_UNIXCP, 0, buffer, -1, NULL, 0, NULL, NULL ))) continue;
413 if (!(names[count] = HeapAlloc( GetProcessHeap(), 0, len ))) continue;
414 WideCharToMultiByte( CP_UNIXCP, 0, buffer, -1, names[count], len, NULL, NULL );
415 new_ids[count++] = *ids;
417 if (!count) return;
419 XInternAtoms( thread_display(), names, count, False, atoms );
420 register_formats( new_ids, atoms, count );
421 while (count) HeapFree( GetProcessHeap(), 0, names[--count] );
426 /**************************************************************************
427 * register_x11_formats
429 * Register X11 atom formats the first time we encounter them.
431 static void register_x11_formats( const Atom *atoms, UINT size )
433 Display *display = thread_display();
434 unsigned int i, pos, count;
435 char *names[256];
436 UINT ids[256];
437 Atom new_atoms[256];
438 WCHAR buffer[256];
440 if (list_empty( &format_list)) register_builtin_formats();
442 while (size)
444 for (count = 0; count < 256 && size; atoms++, size--)
445 if (!find_x11_format( *atoms )) new_atoms[count++] = *atoms;
447 if (!count) return;
449 X11DRV_expect_error( display, is_atom_error, NULL );
450 if (!XGetAtomNames( display, new_atoms, count, names )) count = 0;
451 if (X11DRV_check_error())
453 WARN( "got some bad atoms, ignoring\n" );
454 count = 0;
457 for (i = pos = 0; i < count; i++)
459 if (MultiByteToWideChar( CP_UNIXCP, 0, names[i], -1, buffer, 256 ) &&
460 (ids[pos] = RegisterClipboardFormatW( buffer )))
461 new_atoms[pos++] = new_atoms[i];
462 XFree( names[i] );
464 register_formats( ids, new_atoms, pos );
469 /**************************************************************************
470 * X11DRV_InitClipboard
472 void X11DRV_InitClipboard(void)
474 register_builtin_formats();
478 /**************************************************************************
479 * X11DRV_CLIPBOARD_LookupData
481 static LPWINE_CLIPDATA X11DRV_CLIPBOARD_LookupData(DWORD wID)
483 WINE_CLIPDATA *data;
485 LIST_FOR_EACH_ENTRY( data, &data_list, WINE_CLIPDATA, entry )
486 if (data->wFormatID == wID) return data;
488 return NULL;
492 /**************************************************************************
493 * X11DRV_CLIPBOARD_IsProcessOwner
495 static BOOL X11DRV_CLIPBOARD_IsProcessOwner( HWND *owner )
497 BOOL ret = FALSE;
499 SERVER_START_REQ( set_clipboard_info )
501 req->flags = 0;
502 if (!wine_server_call_err( req ))
504 *owner = wine_server_ptr_handle( reply->old_owner );
505 ret = (reply->flags & CB_PROCESS);
508 SERVER_END_REQ;
510 return ret;
514 /**************************************************************************
515 * X11DRV_CLIPBOARD_ReleaseOwnership
517 static BOOL X11DRV_CLIPBOARD_ReleaseOwnership(void)
519 BOOL ret;
521 SERVER_START_REQ( set_clipboard_info )
523 req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
524 ret = !wine_server_call_err( req );
526 SERVER_END_REQ;
528 return ret;
533 /**************************************************************************
534 * X11DRV_CLIPBOARD_InsertClipboardData
536 * Caller *must* have the clipboard open and be the owner.
538 static BOOL X11DRV_CLIPBOARD_InsertClipboardData( UINT wFormatID, HANDLE hData )
540 LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(wFormatID);
542 TRACE("format=%04x lpData=%p hData=%p\n", wFormatID, lpData, hData);
544 if (lpData)
546 X11DRV_CLIPBOARD_FreeData(lpData);
548 lpData->hData = hData;
550 else
552 lpData = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPDATA));
554 lpData->wFormatID = wFormatID;
555 lpData->hData = hData;
557 list_add_tail( &data_list, &lpData->entry );
558 ClipDataCount++;
561 return TRUE;
565 /**************************************************************************
566 * X11DRV_CLIPBOARD_FreeData
568 * Free clipboard data handle.
570 static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData)
572 TRACE("%04x\n", lpData->wFormatID);
574 if (!lpData->hData) return;
576 switch (lpData->wFormatID)
578 case CF_BITMAP:
579 case CF_DSPBITMAP:
580 case CF_PALETTE:
581 DeleteObject(lpData->hData);
582 break;
583 case CF_METAFILEPICT:
584 case CF_DSPMETAFILEPICT:
585 DeleteMetaFile(((METAFILEPICT *)GlobalLock( lpData->hData ))->hMF );
586 GlobalFree(lpData->hData);
587 break;
588 case CF_ENHMETAFILE:
589 case CF_DSPENHMETAFILE:
590 DeleteEnhMetaFile(lpData->hData);
591 break;
592 default:
593 GlobalFree(lpData->hData);
594 break;
596 lpData->hData = 0;
600 /**************************************************************************
601 * X11DRV_CLIPBOARD_RenderFormat
603 static BOOL X11DRV_CLIPBOARD_RenderFormat(Display *display, LPWINE_CLIPDATA lpData)
605 BOOL bret = TRUE;
607 TRACE(" 0x%04x hData(%p)\n", lpData->wFormatID, lpData->hData);
609 if (lpData->hData) return bret; /* Already rendered */
611 if (!selectionAcquired)
613 if (!X11DRV_CLIPBOARD_ReadSelectionData(display, lpData))
615 ERR("Failed to cache clipboard data owned by another process. Format=%04x\n",
616 lpData->wFormatID);
617 bret = FALSE;
620 else
622 HWND owner = GetClipboardOwner();
624 if (owner)
626 /* Send a WM_RENDERFORMAT message to notify the owner to render the
627 * data requested into the clipboard.
629 TRACE("Sending WM_RENDERFORMAT message to hwnd(%p)\n", owner);
630 SendMessageW(owner, WM_RENDERFORMAT, lpData->wFormatID, 0);
632 if (!lpData->hData) bret = FALSE;
634 else
636 ERR("hWndClipOwner is lost!\n");
637 bret = FALSE;
641 return bret;
645 /**************************************************************************
646 * put_property
648 * Put data as a property on the specified window.
650 static void put_property( Display *display, Window win, Atom prop, Atom type, int format,
651 const void *ptr, size_t size )
653 const unsigned char *data = ptr;
654 int mode = PropModeReplace;
655 size_t width = (format == 32) ? sizeof(long) : format / 8;
656 size_t max_size = XExtendedMaxRequestSize( display ) * 4;
658 if (!max_size) max_size = XMaxRequestSize( display ) * 4;
659 max_size -= 64; /* request overhead */
663 size_t count = min( size, max_size / width );
664 XChangeProperty( display, win, prop, type, format, mode, data, count );
665 mode = PropModeAppend;
666 size -= count;
667 data += count * width;
668 } while (size > 0);
672 /**************************************************************************
673 * convert_selection
675 static Atom convert_selection( Display *display, Window win, Atom selection, Atom target )
677 int i;
678 XEvent event;
680 XConvertSelection( display, selection, target, x11drv_atom(SELECTION_DATA), win, CurrentTime );
682 for (i = 0; i < SELECTION_RETRIES; i++)
684 Bool res = XCheckTypedWindowEvent( display, win, SelectionNotify, &event );
685 if (res && event.xselection.selection == selection && event.xselection.target == target)
686 return event.xselection.property;
687 usleep( SELECTION_WAIT );
689 ERR( "Timed out waiting for SelectionNotify event\n" );
690 return None;
694 /***********************************************************************
695 * bitmap_info_size
697 * Return the size of the bitmap info structure including color table.
699 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
701 unsigned int colors, size, masks = 0;
703 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
705 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
706 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
707 return sizeof(BITMAPCOREHEADER) + colors *
708 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
710 else /* assume BITMAPINFOHEADER */
712 colors = info->bmiHeader.biClrUsed;
713 if (!colors && (info->bmiHeader.biBitCount <= 8))
714 colors = 1 << info->bmiHeader.biBitCount;
715 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
716 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
717 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
722 /***********************************************************************
723 * create_dib_from_bitmap
725 * Allocates a packed DIB and copies the bitmap data into it.
727 static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
729 BITMAP bmp;
730 HDC hdc;
731 HGLOBAL hPackedDIB;
732 LPBYTE pPackedDIB;
733 LPBITMAPINFOHEADER pbmiHeader;
734 unsigned int cDataSize, cPackedSize, OffsetBits;
735 int nLinesCopied;
737 if (!GetObjectW( hBmp, sizeof(bmp), &bmp )) return 0;
740 * A packed DIB contains a BITMAPINFO structure followed immediately by
741 * an optional color palette and the pixel data.
744 /* Calculate the size of the packed DIB */
745 cDataSize = abs( bmp.bmHeight ) * (((bmp.bmWidth * bmp.bmBitsPixel + 31) / 8) & ~3);
746 cPackedSize = sizeof(BITMAPINFOHEADER)
747 + ( (bmp.bmBitsPixel <= 8) ? (sizeof(RGBQUAD) * (1 << bmp.bmBitsPixel)) : 0 )
748 + cDataSize;
749 /* Get the offset to the bits */
750 OffsetBits = cPackedSize - cDataSize;
752 /* Allocate the packed DIB */
753 TRACE("\tAllocating packed DIB of size %d\n", cPackedSize);
754 hPackedDIB = GlobalAlloc( GMEM_FIXED, cPackedSize );
755 if ( !hPackedDIB )
757 WARN("Could not allocate packed DIB!\n");
758 return 0;
761 /* A packed DIB starts with a BITMAPINFOHEADER */
762 pPackedDIB = GlobalLock(hPackedDIB);
763 pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
765 /* Init the BITMAPINFOHEADER */
766 pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
767 pbmiHeader->biWidth = bmp.bmWidth;
768 pbmiHeader->biHeight = bmp.bmHeight;
769 pbmiHeader->biPlanes = 1;
770 pbmiHeader->biBitCount = bmp.bmBitsPixel;
771 pbmiHeader->biCompression = BI_RGB;
772 pbmiHeader->biSizeImage = 0;
773 pbmiHeader->biXPelsPerMeter = pbmiHeader->biYPelsPerMeter = 0;
774 pbmiHeader->biClrUsed = 0;
775 pbmiHeader->biClrImportant = 0;
777 /* Retrieve the DIB bits from the bitmap and fill in the
778 * DIB color table if present */
779 hdc = GetDC( 0 );
780 nLinesCopied = GetDIBits(hdc, /* Handle to device context */
781 hBmp, /* Handle to bitmap */
782 0, /* First scan line to set in dest bitmap */
783 bmp.bmHeight, /* Number of scan lines to copy */
784 pPackedDIB + OffsetBits, /* [out] Address of array for bitmap bits */
785 (LPBITMAPINFO) pbmiHeader, /* [out] Address of BITMAPINFO structure */
786 0); /* RGB or palette index */
787 GlobalUnlock(hPackedDIB);
788 ReleaseDC( 0, hdc );
790 /* Cleanup if GetDIBits failed */
791 if (nLinesCopied != bmp.bmHeight)
793 TRACE("\tGetDIBits returned %d. Actual lines=%d\n", nLinesCopied, bmp.bmHeight);
794 GlobalFree(hPackedDIB);
795 hPackedDIB = 0;
797 return hPackedDIB;
801 /***********************************************************************
802 * uri_to_dos
804 * Converts a text/uri-list URI to DOS filename.
806 static WCHAR* uri_to_dos(char *encodedURI)
808 WCHAR *ret = NULL;
809 int i;
810 int j = 0;
811 char *uri = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(encodedURI) + 1);
812 if (uri == NULL)
813 return NULL;
814 for (i = 0; encodedURI[i]; ++i)
816 if (encodedURI[i] == '%')
818 if (encodedURI[i+1] && encodedURI[i+2])
820 char buffer[3];
821 int number;
822 buffer[0] = encodedURI[i+1];
823 buffer[1] = encodedURI[i+2];
824 buffer[2] = '\0';
825 sscanf(buffer, "%x", &number);
826 uri[j++] = number;
827 i += 2;
829 else
831 WARN("invalid URI encoding in %s\n", debugstr_a(encodedURI));
832 HeapFree(GetProcessHeap(), 0, uri);
833 return NULL;
836 else
837 uri[j++] = encodedURI[i];
840 /* Read http://www.freedesktop.org/wiki/Draganddropwarts and cry... */
841 if (strncmp(uri, "file:/", 6) == 0)
843 if (uri[6] == '/')
845 if (uri[7] == '/')
847 /* file:///path/to/file (nautilus, thunar) */
848 ret = wine_get_dos_file_name(&uri[7]);
850 else if (uri[7])
852 /* file://hostname/path/to/file (X file drag spec) */
853 char hostname[256];
854 char *path = strchr(&uri[7], '/');
855 if (path)
857 *path = '\0';
858 if (strcmp(&uri[7], "localhost") == 0)
860 *path = '/';
861 ret = wine_get_dos_file_name(path);
863 else if (gethostname(hostname, sizeof(hostname)) == 0)
865 if (strcmp(hostname, &uri[7]) == 0)
867 *path = '/';
868 ret = wine_get_dos_file_name(path);
874 else if (uri[6])
876 /* file:/path/to/file (konqueror) */
877 ret = wine_get_dos_file_name(&uri[5]);
880 HeapFree(GetProcessHeap(), 0, uri);
881 return ret;
885 /**************************************************************************
886 * import_string
888 * Import XA_STRING, converting the string to CF_TEXT.
890 static HANDLE import_string( Atom type, const void *data, size_t size )
892 const char *lpdata = data;
893 LPSTR lpstr;
894 size_t i, inlcount = 0;
896 for (i = 0; i < size; i++)
898 if (lpdata[i] == '\n')
899 inlcount++;
902 if ((lpstr = GlobalAlloc( GMEM_FIXED, size + inlcount + 1 )))
904 for (i = 0, inlcount = 0; i < size; i++)
906 if (lpdata[i] == '\n')
907 lpstr[inlcount++] = '\r';
909 lpstr[inlcount++] = lpdata[i];
911 lpstr[inlcount] = 0;
913 return lpstr;
917 /**************************************************************************
918 * import_utf8_string
920 * Import XA_UTF8_STRING, converting the string to CF_UNICODE.
922 static HANDLE import_utf8_string( Atom type, const void *data, size_t size )
924 const char *lpdata = data;
925 LPSTR lpstr;
926 size_t i, inlcount = 0;
927 WCHAR *textW = NULL;
929 for (i = 0; i < size; i++)
931 if (lpdata[i] == '\n')
932 inlcount++;
935 if ((lpstr = HeapAlloc( GetProcessHeap(), 0, size + inlcount + 1 )))
937 UINT count;
939 for (i = 0, inlcount = 0; i < size; i++)
941 if (lpdata[i] == '\n')
942 lpstr[inlcount++] = '\r';
944 lpstr[inlcount++] = lpdata[i];
946 lpstr[inlcount] = 0;
948 count = MultiByteToWideChar(CP_UTF8, 0, lpstr, -1, NULL, 0);
949 textW = GlobalAlloc( GMEM_FIXED, count * sizeof(WCHAR) );
950 if (textW) MultiByteToWideChar( CP_UTF8, 0, lpstr, -1, textW, count );
951 HeapFree(GetProcessHeap(), 0, lpstr);
953 return textW;
957 /**************************************************************************
958 * import_compound_text
960 * Import COMPOUND_TEXT to CF_UNICODE
962 static HANDLE import_compound_text( Atom type, const void *data, size_t size )
964 int i, j;
965 char** srcstr;
966 int count, lcount;
967 int srclen, destlen;
968 WCHAR *deststr;
969 XTextProperty txtprop;
971 txtprop.value = (BYTE *)data;
972 txtprop.nitems = size;
973 txtprop.encoding = x11drv_atom(COMPOUND_TEXT);
974 txtprop.format = 8;
975 if (XmbTextPropertyToTextList( thread_display(), &txtprop, &srcstr, &count ) != Success) return 0;
976 if (!count) return 0;
978 TRACE("Importing %d line(s)\n", count);
980 /* Compute number of lines */
981 srclen = strlen(srcstr[0]);
982 for (i = 0, lcount = 0; i <= srclen; i++)
984 if (srcstr[0][i] == '\n')
985 lcount++;
988 destlen = MultiByteToWideChar(CP_UNIXCP, 0, srcstr[0], -1, NULL, 0);
990 TRACE("lcount = %d, destlen=%d, srcstr %s\n", lcount, destlen, srcstr[0]);
992 if ((deststr = GlobalAlloc( GMEM_FIXED, (destlen + lcount + 1) * sizeof(WCHAR) )))
994 MultiByteToWideChar(CP_UNIXCP, 0, srcstr[0], -1, deststr, destlen);
996 if (lcount)
998 for (i = destlen - 1, j = destlen + lcount - 1; i >= 0; i--, j--)
1000 deststr[j] = deststr[i];
1002 if (deststr[i] == '\n')
1003 deststr[--j] = '\r';
1008 XFreeStringList(srcstr);
1010 return deststr;
1014 /**************************************************************************
1015 * import_pixmap
1017 * Import XA_PIXMAP, converting the image to CF_DIB.
1019 static HANDLE import_pixmap( Atom type, const void *data, size_t size )
1021 const Pixmap *pPixmap = (const Pixmap *)data;
1022 BYTE *ptr = NULL;
1023 XVisualInfo vis = default_visual;
1024 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1025 BITMAPINFO *info = (BITMAPINFO *)buffer;
1026 struct gdi_image_bits bits;
1027 Window root;
1028 int x,y; /* Unused */
1029 unsigned border_width; /* Unused */
1030 unsigned int depth, width, height;
1032 /* Get the Pixmap dimensions and bit depth */
1033 if (!XGetGeometry(gdi_display, *pPixmap, &root, &x, &y, &width, &height,
1034 &border_width, &depth)) depth = 0;
1035 if (!pixmap_formats[depth]) return 0;
1037 TRACE( "pixmap properties: width=%d, height=%d, depth=%d\n", width, height, depth );
1039 if (depth != vis.depth) switch (pixmap_formats[depth]->bits_per_pixel)
1041 case 1:
1042 case 4:
1043 case 8:
1044 break;
1045 case 16: /* assume R5G5B5 */
1046 vis.red_mask = 0x7c00;
1047 vis.green_mask = 0x03e0;
1048 vis.blue_mask = 0x001f;
1049 break;
1050 case 24: /* assume R8G8B8 */
1051 case 32: /* assume A8R8G8B8 */
1052 vis.red_mask = 0xff0000;
1053 vis.green_mask = 0x00ff00;
1054 vis.blue_mask = 0x0000ff;
1055 break;
1056 default:
1057 return 0;
1060 if (!get_pixmap_image( *pPixmap, width, height, &vis, info, &bits ))
1062 DWORD info_size = bitmap_info_size( info, DIB_RGB_COLORS );
1064 ptr = GlobalAlloc( GMEM_FIXED, info_size + info->bmiHeader.biSizeImage );
1065 if (ptr)
1067 memcpy( ptr, info, info_size );
1068 memcpy( ptr + info_size, bits.ptr, info->bmiHeader.biSizeImage );
1070 if (bits.free) bits.free( &bits );
1072 return ptr;
1076 /**************************************************************************
1077 * import_image_bmp
1079 * Import image/bmp, converting the image to CF_DIB.
1081 static HANDLE import_image_bmp( Atom type, const void *data, size_t size )
1083 HANDLE hClipData = 0;
1084 const BITMAPFILEHEADER *bfh = data;
1086 if (size >= sizeof(BITMAPFILEHEADER)+sizeof(BITMAPCOREHEADER) &&
1087 bfh->bfType == 0x4d42 /* "BM" */)
1089 const BITMAPINFO *bmi = (const BITMAPINFO *)(bfh + 1);
1090 HBITMAP hbmp;
1091 HDC hdc = GetDC(0);
1093 if ((hbmp = CreateDIBitmap( hdc, &bmi->bmiHeader, CBM_INIT,
1094 (const BYTE *)data + bfh->bfOffBits, bmi, DIB_RGB_COLORS )))
1096 hClipData = create_dib_from_bitmap( hbmp );
1097 DeleteObject(hbmp);
1099 ReleaseDC(0, hdc);
1101 return hClipData;
1105 /**************************************************************************
1106 * import_metafile
1108 static HANDLE import_metafile( Atom type, const void *data, size_t size )
1110 METAFILEPICT *mf;
1112 if (size < sizeof(METAFILEPICT)) return 0;
1113 if ((mf = GlobalAlloc( GMEM_FIXED, sizeof(METAFILEPICT) )))
1115 memcpy( mf, data, sizeof(METAFILEPICT) );
1116 mf->hMF = SetMetaFileBitsEx( size - sizeof(METAFILEPICT),
1117 (const BYTE *)data + sizeof(METAFILEPICT) );
1119 return mf;
1123 /**************************************************************************
1124 * import_enhmetafile
1126 static HANDLE import_enhmetafile( Atom type, const void *data, size_t size )
1128 return SetEnhMetaFileBits( size, data );
1132 /**************************************************************************
1133 * import_text_uri_list
1135 * Import text/uri-list.
1137 static HANDLE import_text_uri_list( Atom type, const void *data, size_t size )
1139 const char *uriList = data;
1140 char *uri;
1141 WCHAR *path;
1142 WCHAR *out = NULL;
1143 int total = 0;
1144 int capacity = 4096;
1145 int start = 0;
1146 int end = 0;
1147 DROPFILES *dropFiles = NULL;
1149 if (!(out = HeapAlloc(GetProcessHeap(), 0, capacity * sizeof(WCHAR)))) return 0;
1151 while (end < size)
1153 while (end < size && uriList[end] != '\r')
1154 ++end;
1155 if (end < (size - 1) && uriList[end+1] != '\n')
1157 WARN("URI list line doesn't end in \\r\\n\n");
1158 break;
1161 uri = HeapAlloc(GetProcessHeap(), 0, end - start + 1);
1162 if (uri == NULL)
1163 break;
1164 lstrcpynA(uri, &uriList[start], end - start + 1);
1165 path = uri_to_dos(uri);
1166 TRACE("converted URI %s to DOS path %s\n", debugstr_a(uri), debugstr_w(path));
1167 HeapFree(GetProcessHeap(), 0, uri);
1169 if (path)
1171 int pathSize = strlenW(path) + 1;
1172 if (pathSize > capacity - total)
1174 capacity = 2*capacity + pathSize;
1175 out = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, out, (capacity + 1)*sizeof(WCHAR));
1176 if (out == NULL)
1177 goto done;
1179 memcpy(&out[total], path, pathSize * sizeof(WCHAR));
1180 total += pathSize;
1181 done:
1182 HeapFree(GetProcessHeap(), 0, path);
1183 if (out == NULL)
1184 break;
1187 start = end + 2;
1188 end = start;
1190 if (out && end >= size)
1192 if ((dropFiles = GlobalAlloc( GMEM_FIXED, sizeof(DROPFILES) + (total + 1) * sizeof(WCHAR) )))
1194 dropFiles->pFiles = sizeof(DROPFILES);
1195 dropFiles->pt.x = 0;
1196 dropFiles->pt.y = 0;
1197 dropFiles->fNC = 0;
1198 dropFiles->fWide = TRUE;
1199 out[total] = '\0';
1200 memcpy( (char*)dropFiles + dropFiles->pFiles, out, (total + 1) * sizeof(WCHAR) );
1203 HeapFree(GetProcessHeap(), 0, out);
1204 return dropFiles;
1208 /**************************************************************************
1209 * import_targets
1211 * Import TARGETS and mark the corresponding clipboard formats as available.
1213 static HANDLE import_targets( Atom type, const void *data, size_t size )
1215 UINT i, pos, count = size / sizeof(Atom);
1216 const Atom *properties = data;
1217 struct clipboard_format *format, **formats;
1219 if (type != XA_ATOM && type != x11drv_atom(TARGETS)) return 0;
1221 register_x11_formats( properties, count );
1223 /* the builtin formats contain duplicates, so allocate some extra space */
1224 if (!(formats = HeapAlloc( GetProcessHeap(), 0, (count + NB_BUILTIN_FORMATS) * sizeof(*formats ))))
1225 return 0;
1227 pos = 0;
1228 LIST_FOR_EACH_ENTRY( format, &format_list, struct clipboard_format, entry )
1230 for (i = 0; i < count; i++) if (properties[i] == format->atom) break;
1231 if (i == count) continue;
1232 if (format->import && format->id)
1234 TRACE( "property %s -> format %s\n",
1235 debugstr_xatom( properties[i] ), debugstr_format( format->id ));
1236 X11DRV_CLIPBOARD_InsertClipboardData( format->id, 0 );
1237 formats[pos++] = format;
1239 else TRACE( "property %s (ignoring)\n", debugstr_xatom( properties[i] ));
1242 HeapFree( GetProcessHeap(), 0, current_x11_formats );
1243 current_x11_formats = formats;
1244 nb_current_x11_formats = pos;
1245 return (HANDLE)1;
1249 /**************************************************************************
1250 * import_data
1252 * Generic import clipboard data routine.
1254 static HANDLE import_data( Atom type, const void *data, size_t size )
1256 void *ret = GlobalAlloc( GMEM_FIXED, size );
1258 if (ret) memcpy( ret, data, size );
1259 return ret;
1263 /**************************************************************************
1264 * import_selection
1266 * Import the specified format from the selection and return a global handle to the data.
1268 static HANDLE import_selection( Display *display, Window win, Atom selection,
1269 struct clipboard_format *format )
1271 unsigned char *data;
1272 unsigned long size;
1273 Atom prop, type;
1274 HANDLE ret;
1276 if (!format->import) return 0;
1278 TRACE( "import %s from %s win %lx to format %s\n",
1279 debugstr_xatom( format->atom ), debugstr_xatom( selection ),
1280 win, debugstr_format( format->id ) );
1282 if ((prop = convert_selection( display, win, selection, format->atom )) == None)
1284 TRACE( "failed to convert selection\n" );
1285 return 0;
1287 if (!X11DRV_CLIPBOARD_ReadProperty( display, win, prop, &type, &data, &size ))
1289 TRACE( "failed to read property\n" );
1290 return 0;
1292 ret = format->import( type, data, size );
1293 HeapFree( GetProcessHeap(), 0, data );
1294 return ret;
1298 /**************************************************************************
1299 * X11DRV_CLIPBOARD_ImportSelection
1301 * Import the X selection into the clipboard format registered for the given X target.
1303 void X11DRV_CLIPBOARD_ImportSelection( Display *display, Window win, Atom selection,
1304 Atom *targets, UINT count,
1305 void (*callback)( Atom, UINT, HANDLE ))
1307 UINT i;
1308 HANDLE handle;
1309 struct clipboard_format *format;
1311 register_x11_formats( targets, count );
1313 for (i = 0; i < count; i++)
1315 if (!(format = find_x11_format( targets[i] ))) continue;
1316 if (!format->id) continue;
1317 if (!(handle = import_selection( display, win, selection, format ))) continue;
1318 callback( targets[i], format->id, handle );
1323 /**************************************************************************
1324 * render_format
1326 static BOOL render_format( Display *display, Window win, Atom selection, UINT id )
1328 unsigned int i;
1329 HANDLE handle = 0;
1331 for (i = 0; i < nb_current_x11_formats; i++)
1333 if (current_x11_formats[i]->id != id) continue;
1334 handle = import_selection( display, win, selection, current_x11_formats[i] );
1335 break;
1337 if (handle) X11DRV_CLIPBOARD_InsertClipboardData( id, handle );
1338 return handle != 0;
1342 /**************************************************************************
1343 * export_data
1345 * Generic export clipboard data routine.
1347 static BOOL export_data( Display *display, Window win, Atom prop, Atom target, HANDLE handle )
1349 void *ptr = GlobalLock( handle );
1351 if (!ptr) return FALSE;
1352 put_property( display, win, prop, target, 8, ptr, GlobalSize( handle ));
1353 GlobalUnlock( handle );
1354 return TRUE;
1358 /**************************************************************************
1359 * export_string
1361 * Export CF_TEXT converting the string to XA_STRING.
1363 static BOOL export_string( Display *display, Window win, Atom prop, Atom target, HANDLE handle )
1365 UINT i, j;
1366 UINT size;
1367 LPSTR text, lpstr = NULL;
1369 text = GlobalLock( handle );
1370 size = strlen(text);
1372 /* remove carriage returns */
1373 lpstr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + 1);
1374 if (lpstr == NULL)
1376 GlobalUnlock( handle );
1377 return FALSE;
1379 for (i = 0,j = 0; i < size && text[i]; i++)
1381 if (text[i] == '\r' && (text[i+1] == '\n' || text[i+1] == '\0'))
1382 continue;
1383 lpstr[j++] = text[i];
1385 put_property( display, win, prop, target, 8, lpstr, j );
1386 HeapFree( GetProcessHeap(), 0, lpstr );
1387 GlobalUnlock( handle );
1388 return TRUE;
1392 /**************************************************************************
1393 * export_utf8_string
1395 * Export CF_UNICODE converting the string to UTF8.
1397 static BOOL export_utf8_string( Display *display, Window win, Atom prop, Atom target, HANDLE handle )
1399 UINT i, j;
1400 UINT size;
1401 LPSTR text, lpstr;
1402 LPWSTR uni_text = GlobalLock( handle );
1404 size = WideCharToMultiByte(CP_UTF8, 0, uni_text, -1, NULL, 0, NULL, NULL);
1405 text = HeapAlloc(GetProcessHeap(), 0, size);
1406 if (!text)
1408 GlobalUnlock( handle );
1409 return FALSE;
1412 WideCharToMultiByte(CP_UTF8, 0, uni_text, -1, text, size, NULL, NULL);
1413 GlobalUnlock( handle );
1415 /* remove carriage returns */
1416 lpstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size--);
1417 if (lpstr == NULL)
1419 HeapFree(GetProcessHeap(), 0, text);
1420 return FALSE;
1422 for (i = 0,j = 0; i < size && text[i]; i++)
1424 if (text[i] == '\r' && (text[i+1] == '\n' || text[i+1] == '\0'))
1425 continue;
1426 lpstr[j++] = text[i];
1428 put_property( display, win, prop, target, 8, lpstr, j );
1429 HeapFree(GetProcessHeap(), 0, lpstr);
1430 HeapFree(GetProcessHeap(), 0, text);
1431 GlobalUnlock( handle );
1432 return TRUE;
1436 /**************************************************************************
1437 * export_compound_text
1439 * Export CF_UNICODE to COMPOUND_TEXT
1441 static BOOL export_compound_text( Display *display, Window win, Atom prop, Atom target, HANDLE handle )
1443 char* lpstr;
1444 XTextProperty textprop;
1445 XICCEncodingStyle style;
1446 UINT i, j;
1447 UINT size;
1448 LPWSTR uni_text = GlobalLock( handle );
1450 size = WideCharToMultiByte(CP_UNIXCP, 0, uni_text, -1, NULL, 0, NULL, NULL);
1451 lpstr = HeapAlloc(GetProcessHeap(), 0, size);
1452 if (!lpstr)
1454 GlobalUnlock( handle );
1455 return FALSE;
1458 WideCharToMultiByte(CP_UNIXCP, 0, uni_text, -1, lpstr, size, NULL, NULL);
1460 /* remove carriage returns */
1461 for (i = 0, j = 0; i < size && lpstr[i]; i++)
1463 if (lpstr[i] == '\r' && (lpstr[i+1] == '\n' || lpstr[i+1] == '\0'))
1464 continue;
1465 lpstr[j++] = lpstr[i];
1467 lpstr[j]='\0';
1469 GlobalUnlock( handle );
1471 if (target == x11drv_atom(COMPOUND_TEXT))
1472 style = XCompoundTextStyle;
1473 else
1474 style = XStdICCTextStyle;
1476 /* Update the X property */
1477 if (XmbTextListToTextProperty( display, &lpstr, 1, style, &textprop ) == Success)
1479 XSetTextProperty( display, win, &textprop, prop );
1480 XFree( textprop.value );
1483 HeapFree(GetProcessHeap(), 0, lpstr);
1484 return TRUE;
1488 /**************************************************************************
1489 * export_pixmap
1491 * Export CF_DIB to XA_PIXMAP.
1493 static BOOL export_pixmap( Display *display, Window win, Atom prop, Atom target, HANDLE handle )
1495 Pixmap pixmap;
1496 BITMAPINFO *pbmi;
1497 struct gdi_image_bits bits;
1499 pbmi = GlobalLock( handle );
1500 bits.ptr = (LPBYTE)pbmi + bitmap_info_size( pbmi, DIB_RGB_COLORS );
1501 bits.free = NULL;
1502 bits.is_copy = FALSE;
1503 pixmap = create_pixmap_from_image( 0, &default_visual, pbmi, &bits, DIB_RGB_COLORS );
1504 GlobalUnlock( handle );
1506 put_property( display, win, prop, target, 32, &pixmap, 1 );
1507 /* FIXME: free the pixmap when the property is deleted */
1508 return TRUE;
1512 /**************************************************************************
1513 * export_image_bmp
1515 * Export CF_DIB to image/bmp.
1517 static BOOL export_image_bmp( Display *display, Window win, Atom prop, Atom target, HANDLE handle )
1519 LPBYTE dibdata = GlobalLock( handle );
1520 UINT bmpsize;
1521 BITMAPFILEHEADER *bfh;
1523 bmpsize = sizeof(BITMAPFILEHEADER) + GlobalSize( handle );
1524 bfh = HeapAlloc( GetProcessHeap(), 0, bmpsize );
1525 if (bfh)
1527 /* bitmap file header */
1528 bfh->bfType = 0x4d42; /* "BM" */
1529 bfh->bfSize = bmpsize;
1530 bfh->bfReserved1 = 0;
1531 bfh->bfReserved2 = 0;
1532 bfh->bfOffBits = sizeof(BITMAPFILEHEADER) + bitmap_info_size((BITMAPINFO*)dibdata, DIB_RGB_COLORS);
1534 /* rest of bitmap is the same as the packed dib */
1535 memcpy(bfh+1, dibdata, bmpsize-sizeof(BITMAPFILEHEADER));
1537 GlobalUnlock( handle );
1538 put_property( display, win, prop, target, 8, bfh, bmpsize );
1539 HeapFree( GetProcessHeap(), 0, bfh );
1540 return TRUE;
1544 /**************************************************************************
1545 * export_metafile
1547 * Export MetaFilePict.
1549 static BOOL export_metafile( Display *display, Window win, Atom prop, Atom target, HANDLE handle )
1551 METAFILEPICT *src, *dst;
1552 unsigned int size;
1554 src = GlobalLock( handle );
1555 size = GetMetaFileBitsEx(src->hMF, 0, NULL);
1557 dst = HeapAlloc( GetProcessHeap(), 0, size + sizeof(*dst) );
1558 if (dst)
1560 *dst = *src;
1561 GetMetaFileBitsEx( src->hMF, size, dst + 1 );
1563 GlobalUnlock( handle );
1564 put_property( display, win, prop, target, 8, dst, size + sizeof(*dst) );
1565 HeapFree( GetProcessHeap(), 0, dst );
1566 return TRUE;
1570 /**************************************************************************
1571 * export_enhmetafile
1573 * Export EnhMetaFile.
1575 static BOOL export_enhmetafile( Display *display, Window win, Atom prop, Atom target, HANDLE handle )
1577 unsigned int size;
1578 void *ptr;
1580 if (!(size = GetEnhMetaFileBits( handle, 0, NULL ))) return FALSE;
1581 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
1583 GetEnhMetaFileBits( handle, size, ptr );
1584 put_property( display, win, prop, target, 8, ptr, size );
1585 HeapFree( GetProcessHeap(), 0, ptr );
1586 return TRUE;
1590 /**************************************************************************
1591 * get_html_description_field
1593 * Find the value of a field in an HTML Format description.
1595 static LPCSTR get_html_description_field(LPCSTR data, LPCSTR keyword)
1597 LPCSTR pos=data;
1599 while (pos && *pos && *pos != '<')
1601 if (memcmp(pos, keyword, strlen(keyword)) == 0)
1602 return pos+strlen(keyword);
1604 pos = strchr(pos, '\n');
1605 if (pos) pos++;
1608 return NULL;
1612 /**************************************************************************
1613 * export_text_html
1615 * Export HTML Format to text/html.
1617 * FIXME: We should attempt to add an <a base> tag and convert windows paths.
1619 static BOOL export_text_html( Display *display, Window win, Atom prop, Atom target, HANDLE handle )
1621 LPCSTR data, field_value;
1622 UINT fragmentstart, fragmentend;
1624 data = GlobalLock( handle );
1626 /* read the important fields */
1627 field_value = get_html_description_field(data, "StartFragment:");
1628 if (!field_value)
1630 ERR("Couldn't find StartFragment value\n");
1631 goto failed;
1633 fragmentstart = atoi(field_value);
1635 field_value = get_html_description_field(data, "EndFragment:");
1636 if (!field_value)
1638 ERR("Couldn't find EndFragment value\n");
1639 goto failed;
1641 fragmentend = atoi(field_value);
1643 /* export only the fragment */
1644 put_property( display, win, prop, target, 8, &data[fragmentstart], fragmentend - fragmentstart );
1645 GlobalUnlock( handle );
1646 return TRUE;
1648 failed:
1649 GlobalUnlock( handle );
1650 return FALSE;
1654 /**************************************************************************
1655 * export_hdrop
1657 * Export CF_HDROP format to text/uri-list.
1659 static BOOL export_hdrop( Display *display, Window win, Atom prop, Atom target, HANDLE handle )
1661 UINT i;
1662 UINT numFiles;
1663 char *textUriList;
1664 UINT textUriListSize = 32;
1665 UINT next = 0;
1667 textUriList = HeapAlloc( GetProcessHeap(), 0, textUriListSize );
1668 if (!textUriList) return FALSE;
1669 numFiles = DragQueryFileW( handle, 0xFFFFFFFF, NULL, 0 );
1670 for (i = 0; i < numFiles; i++)
1672 UINT dosFilenameSize;
1673 WCHAR *dosFilename = NULL;
1674 char *unixFilename = NULL;
1675 UINT uriSize;
1676 UINT u;
1678 dosFilenameSize = 1 + DragQueryFileW( handle, i, NULL, 0 );
1679 dosFilename = HeapAlloc(GetProcessHeap(), 0, dosFilenameSize*sizeof(WCHAR));
1680 if (dosFilename == NULL) goto failed;
1681 DragQueryFileW( handle, i, dosFilename, dosFilenameSize );
1682 unixFilename = wine_get_unix_file_name(dosFilename);
1683 HeapFree(GetProcessHeap(), 0, dosFilename);
1684 if (unixFilename == NULL) goto failed;
1685 uriSize = 8 + /* file:/// */
1686 3 * (lstrlenA(unixFilename) - 1) + /* "%xy" per char except first '/' */
1687 2; /* \r\n */
1688 if ((next + uriSize) > textUriListSize)
1690 UINT biggerSize = max( 2 * textUriListSize, next + uriSize );
1691 void *bigger = HeapReAlloc( GetProcessHeap(), 0, textUriList, biggerSize );
1692 if (bigger)
1694 textUriList = bigger;
1695 textUriListSize = biggerSize;
1697 else
1699 HeapFree(GetProcessHeap(), 0, unixFilename);
1700 goto failed;
1703 lstrcpyA(&textUriList[next], "file:///");
1704 next += 8;
1705 /* URL encode everything - unnecessary, but easier/lighter than linking in shlwapi, and can't hurt */
1706 for (u = 1; unixFilename[u]; u++)
1708 static const char hex_table[] = "0123456789abcdef";
1709 textUriList[next++] = '%';
1710 textUriList[next++] = hex_table[unixFilename[u] >> 4];
1711 textUriList[next++] = hex_table[unixFilename[u] & 0xf];
1713 textUriList[next++] = '\r';
1714 textUriList[next++] = '\n';
1715 HeapFree(GetProcessHeap(), 0, unixFilename);
1717 put_property( display, win, prop, target, 8, textUriList, next );
1718 HeapFree( GetProcessHeap(), 0, textUriList );
1719 return TRUE;
1721 failed:
1722 HeapFree( GetProcessHeap(), 0, textUriList );
1723 return FALSE;
1727 /***********************************************************************
1728 * get_clipboard_formats
1730 * Return a list of all formats currently available on the Win32 clipboard.
1731 * Helper for export_targets.
1733 static UINT *get_clipboard_formats( UINT *size )
1735 UINT *ids;
1737 *size = 256;
1738 for (;;)
1740 if (!(ids = HeapAlloc( GetProcessHeap(), 0, *size * sizeof(*ids) ))) return NULL;
1741 if (GetUpdatedClipboardFormats( ids, *size, size )) break;
1742 HeapFree( GetProcessHeap(), 0, ids );
1743 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL;
1745 register_win32_formats( ids, *size );
1746 return ids;
1750 /***********************************************************************
1751 * is_format_available
1753 * Check if a clipboard format is included in the list.
1754 * Helper for export_targets.
1756 static BOOL is_format_available( UINT format, const UINT *ids, unsigned int count )
1758 while (count--) if (*ids++ == format) return TRUE;
1759 return FALSE;
1763 /***********************************************************************
1764 * export_targets
1766 * Service a TARGETS selection request event
1768 static BOOL export_targets( Display *display, Window win, Atom prop, Atom target, HANDLE handle )
1770 struct clipboard_format *format;
1771 UINT pos, count, *formats;
1772 Atom *targets;
1774 if (!(formats = get_clipboard_formats( &count ))) return FALSE;
1776 /* the builtin formats contain duplicates, so allocate some extra space */
1777 if (!(targets = HeapAlloc( GetProcessHeap(), 0, (count + NB_BUILTIN_FORMATS) * sizeof(*targets) )))
1779 HeapFree( GetProcessHeap(), 0, formats );
1780 return FALSE;
1783 pos = 0;
1784 LIST_FOR_EACH_ENTRY( format, &format_list, struct clipboard_format, entry )
1786 if (!format->export) continue;
1787 /* formats with id==0 are always exported */
1788 if (format->id && !is_format_available( format->id, formats, count )) continue;
1789 TRACE( "%d: %s -> %s\n", pos, debugstr_format( format->id ), debugstr_xatom( format->atom ));
1790 targets[pos++] = format->atom;
1793 put_property( display, win, prop, XA_ATOM, 32, targets, pos );
1794 HeapFree( GetProcessHeap(), 0, targets );
1795 HeapFree( GetProcessHeap(), 0, formats );
1796 return TRUE;
1800 /**************************************************************************
1801 * export_selection
1803 * Export selection data, depending on the target type.
1805 static BOOL export_selection( Display *display, Window win, Atom prop, Atom target )
1807 struct clipboard_format *format;
1808 HANDLE handle = 0;
1809 BOOL open = FALSE, ret = FALSE;
1811 LIST_FOR_EACH_ENTRY( format, &format_list, struct clipboard_format, entry )
1813 if (format->atom != target) continue;
1814 if (!format->export) continue;
1815 if (!format->id)
1817 TRACE( "win %lx prop %s target %s\n", win, debugstr_xatom( prop ), debugstr_xatom( target ));
1818 ret = format->export( display, win, prop, target, 0 );
1819 break;
1821 if (!open && !(open = OpenClipboard( 0 )))
1823 ERR( "failed to open clipboard for %s\n", debugstr_xatom( target ));
1824 return FALSE;
1826 if ((handle = GetClipboardData( format->id )))
1828 TRACE( "win %lx prop %s target %s exporting %s %p\n",
1829 win, debugstr_xatom( prop ), debugstr_xatom( target ),
1830 debugstr_format( format->id ), handle );
1832 ret = format->export( display, win, prop, target, handle );
1833 break;
1835 /* keep looking for another Win32 format mapping to the same target */
1837 if (open) CloseClipboard();
1838 return ret;
1842 /***********************************************************************
1843 * export_multiple
1845 * Service a MULTIPLE selection request event
1846 * prop contains a list of (target,property) atom pairs.
1847 * The first atom names a target and the second names a property.
1848 * The effect is as if we have received a sequence of SelectionRequest events
1849 * (one for each atom pair) except that:
1850 * 1. We reply with a SelectionNotify only when all the requested conversions
1851 * have been performed.
1852 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
1853 * we replace the atom in the property by None.
1855 static BOOL export_multiple( Display *display, Window win, Atom prop, Atom target, HANDLE handle )
1857 Atom atype;
1858 int aformat;
1859 Atom *list;
1860 unsigned long i, count, failed, remain;
1862 /* Read the MULTIPLE property contents. This should contain a list of
1863 * (target,property) atom pairs.
1865 if (XGetWindowProperty( display, win, prop, 0, 0x3FFF, False, AnyPropertyType, &atype, &aformat,
1866 &count, &remain, (unsigned char**)&list ))
1867 return FALSE;
1869 TRACE( "type %s format %d count %ld remain %ld\n",
1870 debugstr_xatom( atype ), aformat, count, remain );
1873 * Make sure we got what we expect.
1874 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
1875 * in a MULTIPLE selection request should be of type ATOM_PAIR.
1876 * However some X apps(such as XPaint) are not compliant with this and return
1877 * a user defined atom in atype when XGetWindowProperty is called.
1878 * The data *is* an atom pair but is not denoted as such.
1880 if (aformat == 32 /* atype == xAtomPair */ )
1882 for (i = failed = 0; i < count; i += 2)
1884 if (list[i+1] == None) continue;
1885 if (export_selection( display, win, list[i + 1], list[i] )) continue;
1886 failed++;
1887 list[i + 1] = None;
1889 if (failed) put_property( display, win, prop, atype, 32, list, count );
1891 XFree( list );
1892 return TRUE;
1896 /**************************************************************************
1897 * X11DRV_CLIPBOARD_QueryAvailableData
1899 * Caches the list of data formats available from the current selection.
1900 * This queries the selection owner for the TARGETS property and saves all
1901 * reported property types.
1903 static int X11DRV_CLIPBOARD_QueryAvailableData(Display *display)
1905 Window w;
1907 if (selectionAcquired & (S_PRIMARY | S_CLIPBOARD))
1909 ERR("Received request to cache selection but process is owner=(%08x)\n",
1910 (unsigned) selectionWindow);
1911 return -1; /* Prevent self request */
1914 w = thread_selection_wnd();
1915 if (!w)
1917 ERR("No window available to retrieve selection!\n");
1918 return -1;
1922 * Query the selection owner for the TARGETS property
1924 if ((use_primary_selection && XGetSelectionOwner(display,XA_PRIMARY)) ||
1925 XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)))
1927 struct clipboard_format *format = find_x11_format( x11drv_atom(TARGETS) );
1929 assert( format );
1930 if (use_primary_selection && import_selection( display, w, XA_PRIMARY, format ))
1931 selectionCacheSrc = XA_PRIMARY;
1932 else if (import_selection( display, w, x11drv_atom(CLIPBOARD), format ))
1933 selectionCacheSrc = x11drv_atom(CLIPBOARD);
1934 else
1936 HANDLE handle;
1938 format = find_x11_format( XA_STRING );
1939 assert( format );
1940 /* Selection Owner doesn't understand TARGETS, try retrieving XA_STRING */
1941 if (use_primary_selection && (handle = import_selection( display, w, XA_PRIMARY, format )))
1943 X11DRV_CLIPBOARD_InsertClipboardData( format->id, handle );
1944 selectionCacheSrc = XA_PRIMARY;
1946 else if ((handle = import_selection( display, w, x11drv_atom(CLIPBOARD), format )))
1948 X11DRV_CLIPBOARD_InsertClipboardData( format->id, handle );
1949 selectionCacheSrc = x11drv_atom(CLIPBOARD);
1951 else
1953 WARN("Failed to query selection owner for available data.\n");
1954 return -1;
1957 return 1;
1959 else return 0; /* No selection owner so report 0 targets available */
1963 /**************************************************************************
1964 * X11DRV_CLIPBOARD_ReadSelectionData
1966 * This method is invoked only when we DO NOT own the X selection
1968 * We always get the data from the selection client each time,
1969 * since we have no way of determining if the data in our cache is stale.
1971 static BOOL X11DRV_CLIPBOARD_ReadSelectionData(Display *display, LPWINE_CLIPDATA lpData)
1973 Window w = thread_selection_wnd();
1975 if (!w)
1977 ERR("No window available to read selection data!\n");
1978 return FALSE;
1980 return render_format( display, w, selectionCacheSrc, lpData->wFormatID );
1984 /**************************************************************************
1985 * X11DRV_CLIPBOARD_GetProperty
1986 * Gets type, data and size.
1988 static BOOL X11DRV_CLIPBOARD_GetProperty(Display *display, Window w, Atom prop,
1989 Atom *atype, unsigned char** data, unsigned long* datasize)
1991 int aformat;
1992 unsigned long pos = 0, nitems, remain, count;
1993 unsigned char *val = NULL, *buffer;
1995 for (;;)
1997 if (XGetWindowProperty(display, w, prop, pos, INT_MAX / 4, False,
1998 AnyPropertyType, atype, &aformat, &nitems, &remain, &buffer))
2000 WARN("Failed to read property\n");
2001 HeapFree( GetProcessHeap(), 0, val );
2002 return FALSE;
2005 count = get_property_size( aformat, nitems );
2006 if (!val) *data = HeapAlloc( GetProcessHeap(), 0, pos * sizeof(int) + count + 1 );
2007 else *data = HeapReAlloc( GetProcessHeap(), 0, val, pos * sizeof(int) + count + 1 );
2009 if (!*data)
2011 XFree( buffer );
2012 HeapFree( GetProcessHeap(), 0, val );
2013 return FALSE;
2015 val = *data;
2016 memcpy( (int *)val + pos, buffer, count );
2017 XFree( buffer );
2018 if (!remain)
2020 *datasize = pos * sizeof(int) + count;
2021 val[*datasize] = 0;
2022 break;
2024 pos += count / sizeof(int);
2027 TRACE( "got property %s type %s format %u len %lu from window %lx\n",
2028 debugstr_xatom( prop ), debugstr_xatom( *atype ), aformat, *datasize, w );
2030 /* Delete the property on the window now that we are done
2031 * This will send a PropertyNotify event to the selection owner. */
2032 XDeleteProperty(display, w, prop);
2033 return TRUE;
2037 struct clipboard_data_packet {
2038 struct list entry;
2039 unsigned long size;
2040 unsigned char *data;
2043 /**************************************************************************
2044 * X11DRV_CLIPBOARD_ReadProperty
2045 * Reads the contents of the X selection property.
2047 static BOOL X11DRV_CLIPBOARD_ReadProperty( Display *display, Window w, Atom prop,
2048 Atom *type, unsigned char** data, unsigned long* datasize )
2050 XEvent xe;
2052 if (prop == None)
2053 return FALSE;
2055 while (XCheckTypedWindowEvent(display, w, PropertyNotify, &xe))
2058 if (!X11DRV_CLIPBOARD_GetProperty(display, w, prop, type, data, datasize))
2059 return FALSE;
2061 if (*type == x11drv_atom(INCR))
2063 unsigned char *buf;
2064 unsigned long bufsize = 0;
2065 struct list packets;
2066 struct clipboard_data_packet *packet, *packet2;
2067 BOOL res;
2069 HeapFree(GetProcessHeap(), 0, *data);
2070 *data = NULL;
2072 list_init(&packets);
2074 for (;;)
2076 int i;
2077 unsigned char *prop_data;
2078 unsigned long prop_size;
2080 /* Wait until PropertyNotify is received */
2081 for (i = 0; i < SELECTION_RETRIES; i++)
2083 Bool res;
2085 res = XCheckTypedWindowEvent(display, w, PropertyNotify, &xe);
2086 if (res && xe.xproperty.atom == prop &&
2087 xe.xproperty.state == PropertyNewValue)
2088 break;
2089 usleep(SELECTION_WAIT);
2092 if (i >= SELECTION_RETRIES ||
2093 !X11DRV_CLIPBOARD_GetProperty(display, w, prop, type, &prop_data, &prop_size))
2095 res = FALSE;
2096 break;
2099 /* Retrieved entire data. */
2100 if (prop_size == 0)
2102 HeapFree(GetProcessHeap(), 0, prop_data);
2103 res = TRUE;
2104 break;
2107 packet = HeapAlloc(GetProcessHeap(), 0, sizeof(*packet));
2108 if (!packet)
2110 HeapFree(GetProcessHeap(), 0, prop_data);
2111 res = FALSE;
2112 break;
2115 packet->size = prop_size;
2116 packet->data = prop_data;
2117 list_add_tail(&packets, &packet->entry);
2118 bufsize += prop_size;
2121 if (res)
2123 buf = HeapAlloc(GetProcessHeap(), 0, bufsize + 1);
2124 if (buf)
2126 unsigned long bytes_copied = 0;
2127 *datasize = bufsize;
2128 LIST_FOR_EACH_ENTRY( packet, &packets, struct clipboard_data_packet, entry)
2130 memcpy(&buf[bytes_copied], packet->data, packet->size);
2131 bytes_copied += packet->size;
2133 buf[bufsize] = 0;
2134 *data = buf;
2136 else
2137 res = FALSE;
2140 LIST_FOR_EACH_ENTRY_SAFE( packet, packet2, &packets, struct clipboard_data_packet, entry)
2142 HeapFree(GetProcessHeap(), 0, packet->data);
2143 HeapFree(GetProcessHeap(), 0, packet);
2146 return res;
2149 return TRUE;
2153 /**************************************************************************
2154 * X11DRV_CLIPBOARD_ReleaseSelection
2156 * Release XA_CLIPBOARD and XA_PRIMARY in response to a SelectionClear event.
2158 static void X11DRV_CLIPBOARD_ReleaseSelection(Display *display, Atom selType, Window w, HWND hwnd, Time time)
2160 /* w is the window that lost the selection
2162 TRACE("event->window = %08x (selectionWindow = %08x) selectionAcquired=0x%08x\n",
2163 (unsigned)w, (unsigned)selectionWindow, (unsigned)selectionAcquired);
2165 if (selectionAcquired && (w == selectionWindow))
2167 HWND owner;
2169 /* completely give up the selection */
2170 TRACE("Lost CLIPBOARD (+PRIMARY) selection\n");
2172 if (X11DRV_CLIPBOARD_IsProcessOwner( &owner ))
2174 /* Since we're still the owner, this wasn't initiated by
2175 another Wine process */
2176 if (OpenClipboard(hwnd))
2178 /* Destroy private objects */
2179 SendMessageW(owner, WM_DESTROYCLIPBOARD, 0, 0);
2181 /* Give up ownership of the windows clipboard */
2182 X11DRV_CLIPBOARD_ReleaseOwnership();
2183 CloseClipboard();
2187 if ((selType == x11drv_atom(CLIPBOARD)) && (selectionAcquired & S_PRIMARY))
2189 TRACE("Lost clipboard. Check if we need to release PRIMARY\n");
2191 if (selectionWindow == XGetSelectionOwner(display, XA_PRIMARY))
2193 TRACE("We still own PRIMARY. Releasing PRIMARY.\n");
2194 XSetSelectionOwner(display, XA_PRIMARY, None, time);
2196 else
2197 TRACE("We no longer own PRIMARY\n");
2199 else if ((selType == XA_PRIMARY) && (selectionAcquired & S_CLIPBOARD))
2201 TRACE("Lost PRIMARY. Check if we need to release CLIPBOARD\n");
2203 if (selectionWindow == XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)))
2205 TRACE("We still own CLIPBOARD. Releasing CLIPBOARD.\n");
2206 XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), None, time);
2208 else
2209 TRACE("We no longer own CLIPBOARD\n");
2212 selectionWindow = None;
2214 empty_clipboard();
2216 /* Reset the selection flags now that we are done */
2217 selectionAcquired = S_NOSELECTION;
2222 /**************************************************************************
2223 * X11DRV Clipboard Exports
2224 **************************************************************************/
2227 static void selection_acquire(void)
2229 Window owner;
2230 Display *display;
2232 owner = thread_selection_wnd();
2233 display = thread_display();
2235 selectionAcquired = 0;
2236 selectionWindow = 0;
2238 /* Grab PRIMARY selection if not owned */
2239 if (use_primary_selection)
2240 XSetSelectionOwner(display, XA_PRIMARY, owner, CurrentTime);
2242 /* Grab CLIPBOARD selection if not owned */
2243 XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), owner, CurrentTime);
2245 if (use_primary_selection && XGetSelectionOwner(display, XA_PRIMARY) == owner)
2246 selectionAcquired |= S_PRIMARY;
2248 if (XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)) == owner)
2249 selectionAcquired |= S_CLIPBOARD;
2251 if (selectionAcquired)
2253 selectionWindow = owner;
2254 TRACE("Grabbed X selection, owner=(%08x)\n", (unsigned) owner);
2258 static DWORD WINAPI selection_thread_proc(LPVOID p)
2260 HANDLE event = p;
2262 TRACE("\n");
2264 selection_acquire();
2265 SetEvent(event);
2267 while (selectionAcquired)
2269 MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_SENDMESSAGE, 0);
2272 return 0;
2275 /**************************************************************************
2276 * X11DRV_AcquireClipboard
2278 void X11DRV_AcquireClipboard(HWND hWndClipWindow)
2280 DWORD procid;
2281 HANDLE selectionThread;
2283 TRACE(" %p\n", hWndClipWindow);
2286 * It's important that the selection get acquired from the thread
2287 * that owns the clipboard window. The primary reason is that we know
2288 * it is running a message loop and therefore can process the
2289 * X selection events.
2291 if (hWndClipWindow &&
2292 GetCurrentThreadId() != GetWindowThreadProcessId(hWndClipWindow, &procid))
2294 if (procid != GetCurrentProcessId())
2296 WARN("Setting clipboard owner to other process is not supported\n");
2297 hWndClipWindow = NULL;
2299 else
2301 TRACE("Thread %x is acquiring selection with thread %x's window %p\n",
2302 GetCurrentThreadId(),
2303 GetWindowThreadProcessId(hWndClipWindow, NULL), hWndClipWindow);
2305 SendMessageW(hWndClipWindow, WM_X11DRV_ACQUIRE_SELECTION, 0, 0);
2306 return;
2310 if (hWndClipWindow)
2312 selection_acquire();
2314 else
2316 HANDLE event = CreateEventW(NULL, FALSE, FALSE, NULL);
2317 selectionThread = CreateThread(NULL, 0, selection_thread_proc, event, 0, NULL);
2319 if (selectionThread)
2321 WaitForSingleObject(event, INFINITE);
2322 CloseHandle(selectionThread);
2324 CloseHandle(event);
2329 static void empty_clipboard(void)
2331 WINE_CLIPDATA *data, *next;
2333 LIST_FOR_EACH_ENTRY_SAFE( data, next, &data_list, WINE_CLIPDATA, entry )
2335 list_remove( &data->entry );
2336 X11DRV_CLIPBOARD_FreeData( data );
2337 HeapFree( GetProcessHeap(), 0, data );
2338 ClipDataCount--;
2341 TRACE(" %d entries remaining in cache.\n", ClipDataCount);
2344 /**************************************************************************
2345 * X11DRV_EmptyClipboard
2347 * Empty cached clipboard data.
2349 void CDECL X11DRV_EmptyClipboard(void)
2351 X11DRV_AcquireClipboard( GetOpenClipboardWindow() );
2352 empty_clipboard();
2355 /**************************************************************************
2356 * X11DRV_SetClipboardData
2358 BOOL CDECL X11DRV_SetClipboardData(UINT wFormat, HANDLE hData, BOOL owner)
2360 return X11DRV_CLIPBOARD_InsertClipboardData( wFormat, hData );
2364 /**************************************************************************
2365 * CountClipboardFormats
2367 INT CDECL X11DRV_CountClipboardFormats(void)
2369 return ClipDataCount;
2373 /**************************************************************************
2374 * X11DRV_EnumClipboardFormats
2376 UINT CDECL X11DRV_EnumClipboardFormats(UINT wFormat)
2378 struct list *ptr = NULL;
2380 if (!wFormat)
2382 ptr = list_head( &data_list );
2384 else
2386 LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(wFormat);
2387 if (lpData) ptr = list_next( &data_list, &lpData->entry );
2390 if (!ptr) return 0;
2391 return LIST_ENTRY( ptr, WINE_CLIPDATA, entry )->wFormatID;
2395 /**************************************************************************
2396 * X11DRV_IsClipboardFormatAvailable
2398 BOOL CDECL X11DRV_IsClipboardFormatAvailable(UINT wFormat)
2400 BOOL bRet = FALSE;
2402 if (wFormat != 0 && X11DRV_CLIPBOARD_LookupData(wFormat))
2403 bRet = TRUE;
2405 TRACE("(%04X)- ret(%d)\n", wFormat, bRet);
2407 return bRet;
2411 /**************************************************************************
2412 * GetClipboardData (USER.142)
2414 HANDLE CDECL X11DRV_GetClipboardData(UINT wFormat)
2416 LPWINE_CLIPDATA lpRender;
2418 TRACE("(%04X)\n", wFormat);
2420 if ((lpRender = X11DRV_CLIPBOARD_LookupData(wFormat)))
2422 if ( !lpRender->hData )
2423 X11DRV_CLIPBOARD_RenderFormat(thread_init_display(), lpRender);
2425 TRACE(" returning %p (type %04x)\n", lpRender->hData, lpRender->wFormatID);
2426 return lpRender->hData;
2429 return 0;
2433 /**************************************************************************
2434 * X11DRV_UpdateClipboard
2436 void CDECL X11DRV_UpdateClipboard(void)
2438 static ULONG last_update;
2439 ULONG now;
2441 if (selectionAcquired) return;
2442 now = GetTickCount();
2443 if ((int)(now - last_update) <= SELECTION_UPDATE_DELAY) return;
2444 last_update = now;
2446 empty_clipboard();
2447 if (X11DRV_CLIPBOARD_QueryAvailableData(thread_init_display()) < 0)
2448 ERR("Failed to cache clipboard data owned by another process.\n");
2452 /**************************************************************************
2453 * ResetSelectionOwner
2455 * Called when the thread owning the selection is destroyed and we need to
2456 * preserve the selection ownership. We look for another top level window
2457 * in this process and send it a message to acquire the selection.
2459 void X11DRV_ResetSelectionOwner(void)
2461 HWND hwnd;
2462 DWORD procid;
2464 TRACE("\n");
2466 if (!selectionAcquired || thread_selection_wnd() != selectionWindow)
2467 return;
2469 selectionAcquired = S_NOSELECTION;
2470 selectionWindow = 0;
2472 hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
2475 if (GetCurrentThreadId() != GetWindowThreadProcessId(hwnd, &procid))
2477 if (GetCurrentProcessId() == procid)
2479 if (SendMessageW(hwnd, WM_X11DRV_ACQUIRE_SELECTION, 0, 0))
2480 return;
2483 } while ((hwnd = GetWindow(hwnd, GW_HWNDNEXT)) != NULL);
2485 WARN("Failed to find another thread to take selection ownership. Clipboard data will be lost.\n");
2487 X11DRV_CLIPBOARD_ReleaseOwnership();
2488 empty_clipboard();
2492 /***********************************************************************
2493 * X11DRV_HandleSelectionRequest
2495 BOOL X11DRV_SelectionRequest( HWND hwnd, XEvent *xev )
2497 XSelectionRequestEvent *event = &xev->xselectionrequest;
2498 Display *display = event->display;
2499 XEvent result;
2500 Atom rprop = None;
2502 X11DRV_expect_error( display, is_window_error, NULL );
2505 * We can only handle the selection request if :
2506 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
2508 if (((event->selection != XA_PRIMARY) && (event->selection != x11drv_atom(CLIPBOARD))))
2509 goto done;
2511 /* If the specified property is None the requestor is an obsolete client.
2512 * We support these by using the specified target atom as the reply property.
2514 rprop = event->property;
2515 if( rprop == None )
2516 rprop = event->target;
2518 if (!export_selection( display, event->requestor, rprop, event->target ))
2519 rprop = None; /* report failure to client */
2521 done:
2522 result.xselection.type = SelectionNotify;
2523 result.xselection.display = display;
2524 result.xselection.requestor = event->requestor;
2525 result.xselection.selection = event->selection;
2526 result.xselection.property = rprop;
2527 result.xselection.target = event->target;
2528 result.xselection.time = event->time;
2529 TRACE( "sending SelectionNotify for %s to %lx\n", debugstr_xatom( rprop ), event->requestor );
2530 XSendEvent( display, event->requestor, False, NoEventMask, &result );
2531 XSync( display, False );
2532 if (X11DRV_check_error()) WARN( "requestor %lx is no longer valid\n", event->requestor );
2533 return FALSE;
2537 /***********************************************************************
2538 * X11DRV_SelectionClear
2540 BOOL X11DRV_SelectionClear( HWND hWnd, XEvent *xev )
2542 XSelectionClearEvent *event = &xev->xselectionclear;
2543 if (event->selection == XA_PRIMARY || event->selection == x11drv_atom(CLIPBOARD))
2544 X11DRV_CLIPBOARD_ReleaseSelection( event->display, event->selection,
2545 event->window, hWnd, event->time );
2546 return FALSE;