blob: 9725c063f4aacb000b549cd7499ff2c61bd4988a [file] [log] [blame]
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001/*
Noel Borthwick29700671999-09-03 15:17:57 +00002 * X11 clipboard windows driver
Patrik Stridvalle35d6361998-12-07 09:13:40 +00003 *
4 * Copyright 1994 Martin Ayotte
5 * 1996 Alex Korobka
Noel Borthwick29700671999-09-03 15:17:57 +00006 * 1999 Noel Borthwick
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00007 * 2003 Ulrich Czekalla for CodeWeavers
Noel Borthwick29700671999-09-03 15:17:57 +00008 *
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00009 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
Noel Borthwick29700671999-09-03 15:17:57 +000023 * NOTES:
24 * This file contains the X specific implementation for the windows
25 * Clipboard API.
26 *
27 * Wine's internal clipboard is exposed to external apps via the X
28 * selection mechanism.
29 * Currently the driver asserts ownership via two selection atoms:
30 * 1. PRIMARY(XA_PRIMARY)
31 * 2. CLIPBOARD
32 *
Francois Gougetcd8d1812001-05-18 21:01:38 +000033 * In our implementation, the CLIPBOARD selection takes precedence over PRIMARY,
Noel Borthwick29700671999-09-03 15:17:57 +000034 * i.e. if a CLIPBOARD selection is available, it is used instead of PRIMARY.
Francois Gougetcd8d1812001-05-18 21:01:38 +000035 * When Wine takes ownership of the clipboard, it takes ownership of BOTH selections.
Noel Borthwick29700671999-09-03 15:17:57 +000036 * While giving up selection ownership, if the CLIPBOARD selection is lost,
37 * it will lose both PRIMARY and CLIPBOARD and empty the clipboard.
38 * However if only PRIMARY is lost, it will continue to hold the CLIPBOARD selection
39 * (leaving the clipboard cache content unaffected).
40 *
41 * Every format exposed via a windows clipboard format is also exposed through
42 * a corresponding X selection target. A selection target atom is synthesized
43 * whenever a new Windows clipboard format is registered via RegisterClipboardFormat,
Francois Gougetcd8d1812001-05-18 21:01:38 +000044 * or when a built-in format is used for the first time.
Noel Borthwick29700671999-09-03 15:17:57 +000045 * Windows native format are exposed by prefixing the format name with "<WCF>"
46 * This allows us to uniquely identify windows native formats exposed by other
47 * running WINE apps.
48 *
49 * In order to allow external applications to query WINE for supported formats,
50 * we respond to the "TARGETS" selection target. (See EVENT_SelectionRequest
51 * for implementation) We use the same mechanism to query external clients for
Francois Gougetcd8d1812001-05-18 21:01:38 +000052 * availability of a particular format, by caching the list of available targets
Noel Borthwick29700671999-09-03 15:17:57 +000053 * by using the clipboard cache's "delayed render" mechanism. If a selection client
54 * does not support the "TARGETS" selection target, we actually attempt to retrieve
55 * the format requested as a fallback mechanism.
56 *
57 * Certain Windows native formats are automatically converted to X native formats
58 * and vice versa. If a native format is available in the selection, it takes
59 * precedence, in order to avoid unnecessary conversions.
60 *
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +000061 * FIXME: global format list needs a critical section
Patrik Stridvalle35d6361998-12-07 09:13:40 +000062 */
63
François Gouget14259412001-11-06 20:57:11 +000064#include "config.h"
Alexandre Julliard1bacc582003-12-04 05:11:56 +000065#include "wine/port.h"
Patrik Stridvalle35d6361998-12-07 09:13:40 +000066
Noel Borthwick29700671999-09-03 15:17:57 +000067#include <string.h>
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000068#include <stdarg.h>
Jeremy Whited3e22d92000-02-10 19:03:02 +000069#include <stdio.h>
Alexandre Julliard908464d2000-11-01 03:11:12 +000070#include <stdlib.h>
Patrik Stridvalld016f812002-08-17 00:43:16 +000071#ifdef HAVE_UNISTD_H
72# include <unistd.h>
73#endif
Juergen Lock7cc0e271999-11-07 05:12:43 +000074#include <fcntl.h>
Ulrich Czekalla651c5982002-08-27 19:19:49 +000075#include <time.h>
Francis Beaudet56ab55d1999-10-24 20:22:24 +000076
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000077#include "windef.h"
78#include "winbase.h"
Dmitry Timoshkovde70d2b2001-06-19 03:32:44 +000079#include "winreg.h"
Alexandre Julliard294c8af2004-01-20 22:48:57 +000080#include "wine/wingdi16.h"
Patrik Stridvalle35d6361998-12-07 09:13:40 +000081#include "x11drv.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000082#include "wine/debug.h"
Ulrich Czekallab2df5f92003-06-23 23:02:02 +000083#include "wine/unicode.h"
84#include "wine/server.h"
Patrik Stridvalle35d6361998-12-07 09:13:40 +000085
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000086WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000087
Ulrich Czekallab2df5f92003-06-23 23:02:02 +000088#define HGDIOBJ_32(handle16) ((HGDIOBJ)(ULONG_PTR)(handle16))
89
Ulrich Czekalla18873e72003-07-08 21:02:51 +000090/* Maximum wait time for selection notify */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +000091#define SELECTION_RETRIES 500 /* wait for .1 seconds */
92#define SELECTION_WAIT 1000 /* us */
Ulrich Czekalla18873e72003-07-08 21:02:51 +000093/* Minimum seconds that must lapse between owner queries */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +000094#define OWNERQUERYLAPSETIME 1
Ulrich Czekalla651c5982002-08-27 19:19:49 +000095
Noel Borthwick29700671999-09-03 15:17:57 +000096/* Selection masks */
Noel Borthwick29700671999-09-03 15:17:57 +000097#define S_NOSELECTION 0
98#define S_PRIMARY 1
99#define S_CLIPBOARD 2
100
Alexandre Julliard5329fc82003-12-05 04:45:50 +0000101typedef struct
102{
103 HWND hWndOpen;
104 HWND hWndOwner;
105 HWND hWndViewer;
106 UINT seqno;
107 UINT flags;
108} CLIPBOARDINFO, *LPCLIPBOARDINFO;
109
Alexandre Julliard0778a452005-02-25 21:01:15 +0000110typedef struct tagWINE_CLIPDATA {
111 UINT wFormatID;
112 HANDLE16 hData16;
113 HANDLE hData32;
114 UINT drvData;
115 UINT wFlags;
116 struct tagWINE_CLIPDATA *PrevData;
117 struct tagWINE_CLIPDATA *NextData;
118} WINE_CLIPDATA, *LPWINE_CLIPDATA;
119
120typedef HANDLE (*DRVEXPORTFUNC)(Window requestor, Atom aTarget, Atom rprop,
121 LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
122typedef HANDLE (*DRVIMPORTFUNC)(LPBYTE hData, UINT cBytes);
123
124typedef struct tagWINE_CLIPFORMAT {
125 UINT wFormatID;
126 LPCWSTR Name;
127 UINT drvData;
128 UINT wFlags;
129 DRVIMPORTFUNC lpDrvImportFunc;
130 DRVEXPORTFUNC lpDrvExportFunc;
131 struct tagWINE_CLIPFORMAT *PrevFormat;
132 struct tagWINE_CLIPFORMAT *NextFormat;
133} WINE_CLIPFORMAT, *LPWINE_CLIPFORMAT;
134
135#define CF_FLAG_BUILTINFMT 1 /* Built-in windows format */
136#define CF_FLAG_UNOWNED 2 /* cached data is not owned */
137#define CF_FLAG_SYNTHESIZED 8 /* Implicitly converted data */
138
Francis Beaudet56ab55d1999-10-24 20:22:24 +0000139static int selectionAcquired = 0; /* Contains the current selection masks */
Noel Borthwick29700671999-09-03 15:17:57 +0000140static Window selectionWindow = None; /* The top level X window which owns the selection */
Ulrich Czekalla6af0df42004-01-08 00:43:46 +0000141static BOOL usePrimary = FALSE; /* Use primary selection in additon to the clipboard selection */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000142static Atom selectionCacheSrc = XA_PRIMARY; /* The selection source from which the clipboard cache was filled */
Noel Borthwick29700671999-09-03 15:17:57 +0000143
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000144INT X11DRV_RegisterClipboardFormat(LPCWSTR FormatName);
Ulrich Czekallab41466b2004-05-06 23:40:30 +0000145void X11DRV_EmptyClipboard(BOOL keepunowned);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000146void X11DRV_EndClipboardUpdate(void);
Alexandre Julliard0778a452005-02-25 21:01:15 +0000147static HANDLE X11DRV_CLIPBOARD_ImportClipboardData(LPBYTE lpdata, UINT cBytes);
148static HANDLE X11DRV_CLIPBOARD_ImportEnhMetaFile(LPBYTE lpdata, UINT cBytes);
149static HANDLE X11DRV_CLIPBOARD_ImportMetaFilePict(LPBYTE lpdata, UINT cBytes);
150static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(LPBYTE lpdata, UINT cBytes);
151static HANDLE X11DRV_CLIPBOARD_ImportXAString(LPBYTE lpdata, UINT cBytes);
152static HANDLE X11DRV_CLIPBOARD_ExportClipboardData(Window requestor, Atom aTarget,
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000153 Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
Alexandre Julliard0778a452005-02-25 21:01:15 +0000154static HANDLE X11DRV_CLIPBOARD_ExportString(Window requestor, Atom aTarget,
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000155 Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
Alexandre Julliard0778a452005-02-25 21:01:15 +0000156static HANDLE X11DRV_CLIPBOARD_ExportXAPIXMAP(Window requestor, Atom aTarget,
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000157 Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
Alexandre Julliard0778a452005-02-25 21:01:15 +0000158static HANDLE X11DRV_CLIPBOARD_ExportMetaFilePict(Window requestor, Atom aTarget,
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000159 Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
Alexandre Julliard0778a452005-02-25 21:01:15 +0000160static HANDLE X11DRV_CLIPBOARD_ExportEnhMetaFile(Window requestor, Atom aTarget,
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000161 Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000162static WINE_CLIPFORMAT *X11DRV_CLIPBOARD_InsertClipboardFormat(LPCWSTR FormatName, Atom prop);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000163static BOOL X11DRV_CLIPBOARD_ReadSelection(LPWINE_CLIPFORMAT lpData, Window w, Atom prop);
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000164static BOOL X11DRV_CLIPBOARD_RenderSynthesizedText(UINT wFormatID);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000165static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData);
166static BOOL X11DRV_CLIPBOARD_IsSelectionOwner(void);
167static int X11DRV_CLIPBOARD_QueryAvailableData(LPCLIPBOARDINFO lpcbinfo);
168static BOOL X11DRV_CLIPBOARD_ReadClipboardData(UINT wFormat);
169static BOOL X11DRV_CLIPBOARD_RenderFormat(LPWINE_CLIPDATA lpData);
170static HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, LPDWORD lpcbytes, BOOL out);
171static BOOL X11DRV_CLIPBOARD_SynthesizeData(UINT wFormatID);
172static BOOL X11DRV_CLIPBOARD_RenderSynthesizedFormat(LPWINE_CLIPDATA lpData);
Ulrich Czekalla455a2232004-02-20 05:43:00 +0000173static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(void);
174static BOOL X11DRV_CLIPBOARD_RenderSynthesizedBitmap(void);
Alexandre Julliard0778a452005-02-25 21:01:15 +0000175static void X11DRV_HandleSelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000176
177/* Clipboard formats
178 * WARNING: This data ordering is dependent on the WINE_CLIPFORMAT structure
179 * declared in clipboard.h
180 */
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000181static const WCHAR wszCF_TEXT[] = {'W','C','F','_','T','E','X','T',0};
182static const WCHAR wszCF_BITMAP[] = {'W','C','F','_','B','I','T','M','A','P',0};
183static const WCHAR wszCF_METAFILEPICT[] = {'W','C','F','_','M','E','T','A','F','I','L','E','P','I','C','T',0};
184static const WCHAR wszCF_SYLK[] = {'W','C','F','_','S','Y','L','K',0};
185static const WCHAR wszCF_DIF[] = {'W','C','F','_','D','I','F',0};
186static const WCHAR wszCF_TIFF[] = {'W','C','F','_','T','I','F','F',0};
187static const WCHAR wszCF_OEMTEXT[] = {'W','C','F','_','O','E','M','T','E','X','T',0};
188static const WCHAR wszCF_DIB[] = {'W','C','F','_','D','I','B',0};
189static const WCHAR wszCF_PALETTE[] = {'W','C','F','_','P','A','L','E','T','T','E',0};
190static const WCHAR wszCF_PENDATA[] = {'W','C','F','_','P','E','N','D','A','T','A',0};
191static const WCHAR wszCF_RIFF[] = {'W','C','F','_','R','I','F','F',0};
192static const WCHAR wszCF_WAVE[] = {'W','C','F','_','W','A','V','E',0};
193static const WCHAR wszCF_UNICODETEXT[] = {'W','C','F','_','U','N','I','C','O','D','E','T','E','X','T',0};
194static const WCHAR wszCF_ENHMETAFILE[] = {'W','C','F','_','E','N','H','M','E','T','A','F','I','L','E',0};
195static const WCHAR wszCF_HDROP[] = {'W','C','F','_','H','D','R','O','P',0};
196static const WCHAR wszCF_LOCALE[] = {'W','C','F','_','L','O','C','A','L','E',0};
197static const WCHAR wszCF_DIBV5[] = {'W','C','F','_','D','I','B','V','5',0};
198static const WCHAR wszCF_OWNERDISPLAY[] = {'W','C','F','_','O','W','N','E','R','D','I','S','P','L','A','Y',0};
199static const WCHAR wszCF_DSPTEXT[] = {'W','C','F','_','D','S','P','T','E','X','T',0};
200static const WCHAR wszCF_DSPBITMAP[] = {'W','C','F','_','D','S','P','B','I','T','M','A','P',0};
201static const WCHAR wszCF_DSPMETAFILEPICT[] = {'W','C','F','_','D','S','P','M','E','T','A','F','I','L','E','P','I','C','T',0};
202static const WCHAR wszCF_DSPENHMETAFILE[] = {'W','C','F','_','D','S','P','E','N','H','M','E','T','A','F','I','L','E',0};
203
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000204static WINE_CLIPFORMAT ClipFormats[] =
Alexandre Julliard96ebf152000-01-26 02:21:30 +0000205{
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000206 { CF_TEXT, wszCF_TEXT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000207 X11DRV_CLIPBOARD_ExportClipboardData, NULL, &ClipFormats[1]},
Noel Borthwickd05b7be1999-09-20 15:42:47 +0000208
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000209 { CF_BITMAP, wszCF_BITMAP, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekalla455a2232004-02-20 05:43:00 +0000210 NULL, &ClipFormats[0], &ClipFormats[2]},
Noel Borthwickd05b7be1999-09-20 15:42:47 +0000211
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000212 { CF_METAFILEPICT, wszCF_METAFILEPICT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportMetaFilePict,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000213 X11DRV_CLIPBOARD_ExportMetaFilePict, &ClipFormats[1], &ClipFormats[3]},
214
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000215 { CF_SYLK, wszCF_SYLK, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000216 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[2], &ClipFormats[4]},
217
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000218 { CF_DIF, wszCF_DIF, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000219 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[3], &ClipFormats[5]},
220
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000221 { CF_TIFF, wszCF_TIFF, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000222 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[4], &ClipFormats[6]},
223
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000224 { CF_OEMTEXT, wszCF_OEMTEXT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000225 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[5], &ClipFormats[7]},
226
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000227 { CF_DIB, wszCF_DIB, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportXAPIXMAP,
228 X11DRV_CLIPBOARD_ExportXAPIXMAP, &ClipFormats[6], &ClipFormats[8]},
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000229
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000230 { CF_PALETTE, wszCF_PALETTE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000231 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[7], &ClipFormats[9]},
232
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000233 { CF_PENDATA, wszCF_PENDATA, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000234 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[8], &ClipFormats[10]},
235
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000236 { CF_RIFF, wszCF_RIFF, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000237 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[9], &ClipFormats[11]},
238
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000239 { CF_WAVE, wszCF_WAVE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000240 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[10], &ClipFormats[12]},
241
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000242 { CF_UNICODETEXT, wszCF_UNICODETEXT, XA_STRING, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportXAString,
243 X11DRV_CLIPBOARD_ExportString, &ClipFormats[11], &ClipFormats[13]},
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000244
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000245 { CF_ENHMETAFILE, wszCF_ENHMETAFILE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportEnhMetaFile,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000246 X11DRV_CLIPBOARD_ExportEnhMetaFile, &ClipFormats[12], &ClipFormats[14]},
247
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000248 { CF_HDROP, wszCF_HDROP, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000249 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[13], &ClipFormats[15]},
250
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000251 { CF_LOCALE, wszCF_LOCALE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000252 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[14], &ClipFormats[16]},
253
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000254 { CF_DIBV5, wszCF_DIBV5, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000255 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[15], &ClipFormats[17]},
256
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000257 { CF_OWNERDISPLAY, wszCF_OWNERDISPLAY, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000258 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[16], &ClipFormats[18]},
259
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000260 { CF_DSPTEXT, wszCF_DSPTEXT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000261 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[17], &ClipFormats[19]},
262
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000263 { CF_DSPBITMAP, wszCF_DSPBITMAP, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000264 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[18], &ClipFormats[20]},
265
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000266 { CF_DSPMETAFILEPICT, wszCF_DSPMETAFILEPICT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000267 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[19], &ClipFormats[21]},
268
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000269 { CF_DSPENHMETAFILE, wszCF_DSPENHMETAFILE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000270 X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[20], NULL}
271};
272
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000273#define GET_ATOM(prop) (((prop) < FIRST_XATOM) ? (Atom)(prop) : X11DRV_Atoms[(prop) - FIRST_XATOM])
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000274
275/* Maps X properties to Windows formats */
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000276static const WCHAR wszRichTextFormat[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
277static const WCHAR wszGIF[] = {'G','I','F',0};
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000278static const struct
279{
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000280 LPCWSTR lpszFormat;
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000281 UINT prop;
282} PropertyFormatMap[] =
283{
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000284 { wszRichTextFormat, XATOM_text_rtf },
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000285 /* Temporarily disable text/html because Evolution incorrectly pastes strings with extra nulls */
286 /*{ "text/html", "HTML Format" },*/
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000287 { wszGIF, XATOM_image_gif }
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000288};
289
290
291/* Maps equivalent X properties. It is assumed that lpszProperty must already
292 be in ClipFormats or PropertyFormatMap. */
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000293static const struct
294{
295 UINT drvDataProperty;
296 UINT drvDataAlias;
297} PropertyAliasMap[] =
298{
299 /* DataProperty, DataAlias */
300 { XATOM_text_rtf, XATOM_text_richtext },
301 { XA_STRING, XATOM_COMPOUND_TEXT },
302 { XA_STRING, XATOM_TEXT },
Ulrich Czekalla455a2232004-02-20 05:43:00 +0000303 { XATOM_WCF_DIB, XA_PIXMAP },
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000304};
305
306
307/*
308 * Cached clipboard data.
309 */
310static LPWINE_CLIPDATA ClipData = NULL;
311static UINT ClipDataCount = 0;
312
313/*
314 * Clipboard sequence number
315 */
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000316static UINT wSeqNo = 0;
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000317
Ulrich Czekalla6af0df42004-01-08 00:43:46 +0000318#define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
319
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000320/**************************************************************************
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000321 * Internal Clipboard implementation methods
322 **************************************************************************/
Noel Borthwick29700671999-09-03 15:17:57 +0000323
Ulrich Czekalla50679092005-03-07 19:31:46 +0000324static Window thread_selection_wnd(void)
325{
326 Window w = x11drv_thread_data()->selection_wnd;
327
328 if (!w)
329 {
330 wine_tsx11_lock();
331 w = XCreateWindow(thread_display(), root_window, 0, 0, 1, 1, 0, screen_depth,
Ron Jensen888fb432005-03-23 13:08:35 +0000332 InputOutput, CopyFromParent, 0, NULL);
Ulrich Czekalla50679092005-03-07 19:31:46 +0000333 wine_tsx11_unlock();
334
335 if (w)
336 x11drv_thread_data()->selection_wnd = w;
337 else
338 FIXME("Failed to create window. Fetching selection data will fail.\n");
339 }
340
341 return w;
342}
343
Noel Borthwick29700671999-09-03 15:17:57 +0000344/**************************************************************************
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000345 * X11DRV_InitClipboard
Noel Borthwick29700671999-09-03 15:17:57 +0000346 */
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000347void X11DRV_InitClipboard(void)
Noel Borthwick29700671999-09-03 15:17:57 +0000348{
Hans Leidekker5f6f63a2004-08-11 23:45:34 +0000349 UINT i;
Dmitry Timoshkovde70d2b2001-06-19 03:32:44 +0000350 HKEY hkey;
Francis Beaudet56ab55d1999-10-24 20:22:24 +0000351
Dmitry Timoshkovde70d2b2001-06-19 03:32:44 +0000352 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Clipboard", &hkey))
353 {
354 char buffer[20];
355 DWORD type, count = sizeof(buffer);
Ulrich Czekalla6af0df42004-01-08 00:43:46 +0000356 if(!RegQueryValueExA(hkey, "UsePrimary", 0, &type, buffer, &count))
357 usePrimary = IS_OPTION_TRUE( buffer[0] );
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000358 RegCloseKey(hkey);
Dmitry Timoshkovde70d2b2001-06-19 03:32:44 +0000359 }
Alexandre Julliard43230042001-05-16 19:52:29 +0000360
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000361 /* Register known mapping between window formats and X properties */
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000362 for (i = 0; i < sizeof(PropertyFormatMap)/sizeof(PropertyFormatMap[0]); i++)
363 X11DRV_CLIPBOARD_InsertClipboardFormat(PropertyFormatMap[i].lpszFormat,
364 GET_ATOM(PropertyFormatMap[i].prop));
Francis Beaudet56ab55d1999-10-24 20:22:24 +0000365}
366
367
368/**************************************************************************
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000369 * intern_atoms
370 *
371 * Intern atoms for formats that don't have one yet.
372 */
373static void intern_atoms(void)
374{
375 LPWINE_CLIPFORMAT format;
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000376 int i, count, len;
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000377 char **names;
378 Atom *atoms;
379
380 for (format = ClipFormats, count = 0; format; format = format->NextFormat)
381 if (!format->drvData) count++;
382 if (!count) return;
383
384 names = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*names) );
385 atoms = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*atoms) );
386
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000387 for (format = ClipFormats, i = 0; format; format = format->NextFormat) {
388 if (!format->drvData) {
389 len = WideCharToMultiByte(CP_UNIXCP, 0, format->Name, -1, NULL, -1, 0, 0);
390 names[i] = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
391 WideCharToMultiByte(CP_UNIXCP, 0, format->Name, -1, names[i++], len, 0, 0);
392 }
393 }
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000394
395 wine_tsx11_lock();
396 XInternAtoms( thread_display(), names, count, False, atoms );
397 wine_tsx11_unlock();
398
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000399 for (format = ClipFormats, i = 0; format; format = format->NextFormat) {
400 if (!format->drvData) {
401 HeapFree(GetProcessHeap(), 0, names[i]);
402 format->drvData = atoms[i++];
403 }
404 }
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000405
406 HeapFree( GetProcessHeap(), 0, names );
407 HeapFree( GetProcessHeap(), 0, atoms );
408}
409
410
411/**************************************************************************
412 * register_format
413 *
414 * Register a custom X clipboard format.
415 */
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000416static WINE_CLIPFORMAT *register_format( LPCWSTR FormatName, Atom prop )
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000417{
418 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
419
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000420 TRACE("%s\n", debugstr_w(FormatName));
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000421
422 /* walk format chain to see if it's already registered */
423 while (lpFormat)
424 {
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000425 if (CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpFormat->Name, -1, FormatName, -1) == CSTR_EQUAL
426 && (lpFormat->wFlags & CF_FLAG_BUILTINFMT) == 0)
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000427 return lpFormat;
428 lpFormat = lpFormat->NextFormat;
429 }
430
431 return X11DRV_CLIPBOARD_InsertClipboardFormat(FormatName, prop);
432}
433
434
435/**************************************************************************
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000436 * X11DRV_CLIPBOARD_LookupFormat
437 */
438LPWINE_CLIPFORMAT X11DRV_CLIPBOARD_LookupFormat(WORD wID)
439{
440 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
441
442 while(lpFormat)
443 {
444 if (lpFormat->wFormatID == wID)
445 break;
446
447 lpFormat = lpFormat->NextFormat;
448 }
Rein Klazes46138d82004-04-05 20:17:13 +0000449 if (lpFormat && !lpFormat->drvData) intern_atoms();
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000450 return lpFormat;
451}
452
453
454/**************************************************************************
455 * X11DRV_CLIPBOARD_LookupProperty
456 */
457LPWINE_CLIPFORMAT X11DRV_CLIPBOARD_LookupProperty(UINT drvData)
458{
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000459 for (;;)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000460 {
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000461 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
462 BOOL need_intern = FALSE;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000463
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000464 while(lpFormat)
465 {
466 if (lpFormat->drvData == drvData) return lpFormat;
467 if (!lpFormat->drvData) need_intern = TRUE;
468 lpFormat = lpFormat->NextFormat;
469 }
470 if (!need_intern) return NULL;
471 intern_atoms();
472 /* restart the search for the new atoms */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000473 }
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000474}
475
476
477/**************************************************************************
478 * X11DRV_CLIPBOARD_LookupAliasProperty
479 */
480LPWINE_CLIPFORMAT X11DRV_CLIPBOARD_LookupAliasProperty(UINT drvDataAlias)
481{
482 unsigned int i;
483 LPWINE_CLIPFORMAT lpFormat = NULL;
484
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000485 for (i = 0; i < sizeof(PropertyAliasMap)/sizeof(PropertyAliasMap[0]); i++)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000486 {
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000487 if (GET_ATOM(PropertyAliasMap[i].drvDataAlias) == drvDataAlias)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000488 {
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000489 lpFormat = X11DRV_CLIPBOARD_LookupProperty(GET_ATOM(PropertyAliasMap[i].drvDataProperty));
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000490 break;
491 }
492 }
493
494 return lpFormat;
495}
496
497
498/**************************************************************************
499 * X11DRV_CLIPBOARD_LookupPropertyAlias
500 */
501UINT X11DRV_CLIPBOARD_LookupPropertyAlias(UINT drvDataProperty)
502{
503 unsigned int i;
504 UINT alias = 0;
505
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000506 for (i = 0; i < sizeof(PropertyAliasMap)/sizeof(PropertyAliasMap[0]); i++)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000507 {
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000508 if (GET_ATOM(PropertyAliasMap[i].drvDataProperty) == drvDataProperty)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000509 {
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000510 alias = GET_ATOM(PropertyAliasMap[i].drvDataAlias);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000511 break;
512 }
513 }
514
515 return alias;
516}
517
518
519/**************************************************************************
520 * X11DRV_CLIPBOARD_LookupData
521 */
522LPWINE_CLIPDATA X11DRV_CLIPBOARD_LookupData(DWORD wID)
523{
524 LPWINE_CLIPDATA lpData = ClipData;
525
526 if (lpData)
527 {
528 do
529 {
530 if (lpData->wFormatID == wID)
531 break;
532
533 lpData = lpData->NextData;
534 }
535 while(lpData != ClipData);
536
537 if (lpData->wFormatID != wID)
538 lpData = NULL;
539 }
540
541 return lpData;
542}
543
544
545/**************************************************************************
546 * InsertClipboardFormat
547 */
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000548static WINE_CLIPFORMAT *X11DRV_CLIPBOARD_InsertClipboardFormat(LPCWSTR FormatName, Atom prop)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000549{
550 LPWINE_CLIPFORMAT lpFormat;
551 LPWINE_CLIPFORMAT lpNewFormat;
552
553 /* allocate storage for new format entry */
Jakob Eriksson9ed61de2005-03-24 21:01:35 +0000554 lpNewFormat = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPFORMAT));
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000555
556 if(lpNewFormat == NULL)
557 {
558 WARN("No more memory for a new format!\n");
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000559 return NULL;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000560 }
561
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000562 if (!(lpNewFormat->Name = HeapAlloc(GetProcessHeap(), 0, (strlenW(FormatName)+1)*sizeof(WCHAR))))
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000563 {
564 WARN("No more memory for the new format name!\n");
565 HeapFree(GetProcessHeap(), 0, lpNewFormat);
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000566 return NULL;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000567 }
568
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000569 strcpyW((LPWSTR)lpNewFormat->Name, FormatName);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000570 lpNewFormat->wFlags = 0;
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000571 lpNewFormat->wFormatID = GlobalAddAtomW(lpNewFormat->Name);
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000572 lpNewFormat->drvData = prop;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000573 lpNewFormat->lpDrvImportFunc = X11DRV_CLIPBOARD_ImportClipboardData;
574 lpNewFormat->lpDrvExportFunc = X11DRV_CLIPBOARD_ExportClipboardData;
575
576 /* Link Format */
577 lpFormat = ClipFormats;
578
579 while(lpFormat->NextFormat) /* Move to last entry */
580 lpFormat = lpFormat->NextFormat;
581
582 lpNewFormat->NextFormat = NULL;
583 lpFormat->NextFormat = lpNewFormat;
584 lpNewFormat->PrevFormat = lpFormat;
585
Alexandre Julliardd09c3282003-11-20 04:24:18 +0000586 TRACE("Registering format(%d): %s drvData %d\n",
Jacek Caban7e2a7c92005-01-11 15:10:56 +0000587 lpNewFormat->wFormatID, debugstr_w(FormatName), lpNewFormat->drvData);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000588
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +0000589 return lpNewFormat;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000590}
591
592
593
594
595/**************************************************************************
596 * X11DRV_CLIPBOARD_GetClipboardInfo
597 */
598static BOOL X11DRV_CLIPBOARD_GetClipboardInfo(LPCLIPBOARDINFO cbInfo)
599{
600 BOOL bRet = FALSE;
601
602 SERVER_START_REQ( set_clipboard_info )
603 {
604 req->flags = 0;
605
606 if (wine_server_call_err( req ))
607 {
608 ERR("Failed to get clipboard owner.\n");
609 }
610 else
611 {
612 cbInfo->hWndOpen = reply->old_clipboard;
613 cbInfo->hWndOwner = reply->old_owner;
614 cbInfo->hWndViewer = reply->old_viewer;
615 cbInfo->seqno = reply->seqno;
616 cbInfo->flags = reply->flags;
617
618 bRet = TRUE;
619 }
620 }
621 SERVER_END_REQ;
622
623 return bRet;
624}
625
626
627/**************************************************************************
628 * X11DRV_CLIPBOARD_ReleaseOwnership
629 */
630static BOOL X11DRV_CLIPBOARD_ReleaseOwnership(void)
631{
632 BOOL bRet = FALSE;
633
634 SERVER_START_REQ( set_clipboard_info )
635 {
636 req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
637
638 if (wine_server_call_err( req ))
639 {
640 ERR("Failed to set clipboard.\n");
641 }
642 else
643 {
644 bRet = TRUE;
645 }
646 }
647 SERVER_END_REQ;
648
649 return bRet;
650}
651
652
653
654/**************************************************************************
655 * X11DRV_CLIPBOARD_InsertClipboardData
656 *
657 * Caller *must* have the clipboard open and be the owner.
658 */
659static BOOL X11DRV_CLIPBOARD_InsertClipboardData(UINT wFormat, HANDLE16 hData16, HANDLE hData32, DWORD flags)
660{
661 LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(wFormat);
662
663 TRACE("format=%d lpData=%p hData16=%08x hData32=%08x flags=0x%08lx\n",
664 wFormat, lpData, hData16, (unsigned int)hData32, flags);
665
666 if (lpData)
667 {
668 X11DRV_CLIPBOARD_FreeData(lpData);
669
670 lpData->hData16 = hData16; /* 0 is legal, see WM_RENDERFORMAT */
671 lpData->hData32 = hData32;
672 }
673 else
674 {
Jakob Eriksson9ed61de2005-03-24 21:01:35 +0000675 lpData = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPDATA));
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000676
677 lpData->wFormatID = wFormat;
678 lpData->hData16 = hData16; /* 0 is legal, see WM_RENDERFORMAT */
679 lpData->hData32 = hData32;
Ulrich Czekalla455a2232004-02-20 05:43:00 +0000680 lpData->drvData = 0;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000681
682 if (ClipData)
683 {
684 LPWINE_CLIPDATA lpPrevData = ClipData->PrevData;
685
686 lpData->PrevData = lpPrevData;
687 lpData->NextData = ClipData;
688
689 lpPrevData->NextData = lpData;
690 ClipData->PrevData = lpData;
691 }
692 else
693 {
694 lpData->NextData = lpData;
695 lpData->PrevData = lpData;
696 ClipData = lpData;
697 }
698
699 ClipDataCount++;
700 }
701
702 lpData->wFlags = flags;
703
704 return TRUE;
705}
706
707
708/**************************************************************************
709 * X11DRV_CLIPBOARD_FreeData
710 *
711 * Free clipboard data handle.
712 */
713static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData)
714{
715 TRACE("%d\n", lpData->wFormatID);
716
717 if ((lpData->wFormatID >= CF_GDIOBJFIRST &&
718 lpData->wFormatID <= CF_GDIOBJLAST) ||
719 lpData->wFormatID == CF_BITMAP ||
720 lpData->wFormatID == CF_DIB ||
721 lpData->wFormatID == CF_PALETTE)
722 {
723 if (lpData->hData32)
724 DeleteObject(lpData->hData32);
725
726 if (lpData->hData16)
727 DeleteObject(HGDIOBJ_32(lpData->hData16));
Ulrich Czekalla455a2232004-02-20 05:43:00 +0000728
729 if ((lpData->wFormatID == CF_DIB) && lpData->drvData)
730 XFreePixmap(gdi_display, lpData->drvData);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000731 }
732 else if (lpData->wFormatID == CF_METAFILEPICT)
733 {
734 if (lpData->hData32)
735 {
736 DeleteMetaFile(((METAFILEPICT *)GlobalLock( lpData->hData32 ))->hMF );
737 GlobalFree(lpData->hData32);
738
739 if (lpData->hData16)
740 /* HMETAFILE16 and HMETAFILE32 are apparently the same thing,
741 and a shallow copy is enough to share a METAFILEPICT
742 structure between 16bit and 32bit clipboards. The MetaFile
743 should of course only be deleted once. */
744 GlobalFree16(lpData->hData16);
745 }
746
747 if (lpData->hData16)
748 {
749 METAFILEPICT16* lpMetaPict = (METAFILEPICT16 *) GlobalLock16(lpData->hData16);
750
751 if (lpMetaPict)
752 {
753 DeleteMetaFile16(lpMetaPict->hMF);
754 lpMetaPict->hMF = 0;
755 }
756
757 GlobalFree16(lpData->hData16);
758 }
759 }
760 else if (lpData->wFormatID == CF_ENHMETAFILE)
761 {
762 if (lpData->hData32)
763 DeleteEnhMetaFile(lpData->hData32);
764 }
765 else if (lpData->wFormatID < CF_PRIVATEFIRST ||
766 lpData->wFormatID > CF_PRIVATELAST)
767 {
768 if (lpData->hData32)
769 GlobalFree(lpData->hData32);
770
771 if (lpData->hData16)
772 GlobalFree16(lpData->hData16);
773 }
774
775 lpData->hData16 = 0;
776 lpData->hData32 = 0;
Ulrich Czekalla455a2232004-02-20 05:43:00 +0000777 lpData->drvData = 0;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000778}
779
780
781/**************************************************************************
782 * X11DRV_CLIPBOARD_UpdateCache
783 */
784static BOOL X11DRV_CLIPBOARD_UpdateCache(LPCLIPBOARDINFO lpcbinfo)
785{
786 BOOL bret = TRUE;
787
788 if (!X11DRV_CLIPBOARD_IsSelectionOwner())
789 {
790 if (!X11DRV_CLIPBOARD_GetClipboardInfo(lpcbinfo))
791 {
792 ERR("Failed to retrieve clipboard information.\n");
793 bret = FALSE;
794 }
795 else if (wSeqNo < lpcbinfo->seqno)
796 {
Ulrich Czekallab41466b2004-05-06 23:40:30 +0000797 X11DRV_EmptyClipboard(TRUE);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000798
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000799 if (X11DRV_CLIPBOARD_QueryAvailableData(lpcbinfo) < 0)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000800 {
801 ERR("Failed to cache clipboard data owned by another process.\n");
802 bret = FALSE;
803 }
804 else
805 {
806 X11DRV_EndClipboardUpdate();
807 }
808
809 wSeqNo = lpcbinfo->seqno;
810 }
811 }
812
813 return bret;
814}
815
816
817/**************************************************************************
818 * X11DRV_CLIPBOARD_RenderFormat
819 */
820static BOOL X11DRV_CLIPBOARD_RenderFormat(LPWINE_CLIPDATA lpData)
821{
822 BOOL bret = TRUE;
823
824 TRACE(" 0x%04x hData32(0x%08x) hData16(0x%08x)\n",
825 lpData->wFormatID, (unsigned int)lpData->hData32, lpData->hData16);
826
827 if (lpData->hData32 || lpData->hData16)
828 return bret; /* Already rendered */
829
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000830 if (lpData->wFlags & CF_FLAG_SYNTHESIZED)
831 bret = X11DRV_CLIPBOARD_RenderSynthesizedFormat(lpData);
832 else if (!X11DRV_CLIPBOARD_IsSelectionOwner())
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000833 {
834 if (!X11DRV_CLIPBOARD_ReadClipboardData(lpData->wFormatID))
835 {
836 ERR("Failed to cache clipboard data owned by another process. Format=%d\n",
837 lpData->wFormatID);
838 bret = FALSE;
839 }
840 }
841 else
842 {
Alexandre Julliard5329fc82003-12-05 04:45:50 +0000843 CLIPBOARDINFO cbInfo;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000844
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000845 if (X11DRV_CLIPBOARD_GetClipboardInfo(&cbInfo) && cbInfo.hWndOwner)
Alexandre Julliard5329fc82003-12-05 04:45:50 +0000846 {
847 /* Send a WM_RENDERFORMAT message to notify the owner to render the
848 * data requested into the clipboard.
849 */
850 TRACE("Sending WM_RENDERFORMAT message to hwnd(%p)\n", cbInfo.hWndOwner);
851 SendMessageW(cbInfo.hWndOwner, WM_RENDERFORMAT, (WPARAM)lpData->wFormatID, 0);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000852
Alexandre Julliard5329fc82003-12-05 04:45:50 +0000853 if (!lpData->hData32 && !lpData->hData16)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000854 bret = FALSE;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000855 }
Alexandre Julliard5329fc82003-12-05 04:45:50 +0000856 else
857 {
858 ERR("hWndClipOwner is lost!\n");
859 bret = FALSE;
860 }
861 }
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000862
863 return bret;
864}
865
866
867/**************************************************************************
868 * CLIPBOARD_ConvertText
869 * Returns number of required/converted characters - not bytes!
870 */
871static INT CLIPBOARD_ConvertText(WORD src_fmt, void const *src, INT src_size,
872 WORD dst_fmt, void *dst, INT dst_size)
873{
874 UINT cp;
875
876 if(src_fmt == CF_UNICODETEXT)
877 {
878 switch(dst_fmt)
879 {
880 case CF_TEXT:
881 cp = CP_ACP;
882 break;
883 case CF_OEMTEXT:
884 cp = CP_OEMCP;
885 break;
886 default:
887 return 0;
888 }
889 return WideCharToMultiByte(cp, 0, src, src_size, dst, dst_size, NULL, NULL);
890 }
891
892 if(dst_fmt == CF_UNICODETEXT)
893 {
894 switch(src_fmt)
895 {
896 case CF_TEXT:
897 cp = CP_ACP;
898 break;
899 case CF_OEMTEXT:
900 cp = CP_OEMCP;
901 break;
902 default:
903 return 0;
904 }
905 return MultiByteToWideChar(cp, 0, src, src_size, dst, dst_size);
906 }
907
908 if(!dst_size) return src_size;
909
910 if(dst_size > src_size) dst_size = src_size;
911
912 if(src_fmt == CF_TEXT )
913 CharToOemBuffA(src, dst, dst_size);
914 else
915 OemToCharBuffA(src, dst, dst_size);
916
917 return dst_size;
918}
919
920
921/**************************************************************************
922 * X11DRV_CLIPBOARD_RenderSynthesizedFormat
923 */
924static BOOL X11DRV_CLIPBOARD_RenderSynthesizedFormat(LPWINE_CLIPDATA lpData)
925{
926 BOOL bret = FALSE;
927
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000928 TRACE("\n");
929
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000930 if (lpData->wFlags & CF_FLAG_SYNTHESIZED)
931 {
932 UINT wFormatID = lpData->wFormatID;
933
934 if (wFormatID == CF_UNICODETEXT || wFormatID == CF_TEXT || wFormatID == CF_OEMTEXT)
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000935 bret = X11DRV_CLIPBOARD_RenderSynthesizedText(wFormatID);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000936 else
937 {
938 switch (wFormatID)
939 {
Ulrich Czekalla455a2232004-02-20 05:43:00 +0000940 case CF_DIB:
941 bret = X11DRV_CLIPBOARD_RenderSynthesizedDIB();
942 break;
943
944 case CF_BITMAP:
945 bret = X11DRV_CLIPBOARD_RenderSynthesizedBitmap();
946 break;
947
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000948 case CF_ENHMETAFILE:
949 case CF_METAFILEPICT:
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000950 FIXME("Synthesizing wFormatID(0x%08x) not implemented\n", wFormatID);
951 break;
952
953 default:
954 FIXME("Called to synthesize unknown format\n");
955 break;
956 }
957 }
958
959 lpData->wFlags &= ~CF_FLAG_SYNTHESIZED;
960 }
961
962 return bret;
963}
964
965
966/**************************************************************************
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000967 * X11DRV_CLIPBOARD_RenderSynthesizedText
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000968 *
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000969 * Renders synthesized text
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000970 */
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000971static BOOL X11DRV_CLIPBOARD_RenderSynthesizedText(UINT wFormatID)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000972{
973 LPCSTR lpstrS;
974 LPSTR lpstrT;
975 HANDLE hData32;
976 INT src_chars, dst_chars, alloc_size;
977 LPWINE_CLIPDATA lpSource = NULL;
978
979 TRACE(" %d\n", wFormatID);
980
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000981 if ((lpSource = X11DRV_CLIPBOARD_LookupData(wFormatID)) &&
982 lpSource->hData32)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000983 return TRUE;
984
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000985 /* Look for rendered source or non-synthesized source */
986 if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_UNICODETEXT)) &&
987 (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData32))
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000988 {
989 TRACE("UNICODETEXT -> %d\n", wFormatID);
990 }
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000991 else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_TEXT)) &&
992 (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData32))
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000993 {
994 TRACE("TEXT -> %d\n", wFormatID);
995 }
Ulrich Czekalla18873e72003-07-08 21:02:51 +0000996 else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_OEMTEXT)) &&
997 (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData32))
Ulrich Czekallab2df5f92003-06-23 23:02:02 +0000998 {
999 TRACE("OEMTEXT -> %d\n", wFormatID);
1000 }
1001
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001002 if (!lpSource || (lpSource->wFlags & CF_FLAG_SYNTHESIZED &&
1003 !lpSource->hData32))
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001004 return FALSE;
1005
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001006 /* Ask the clipboard owner to render the source text if necessary */
1007 if (!lpSource->hData32 && !X11DRV_CLIPBOARD_RenderFormat(lpSource))
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001008 return FALSE;
1009
1010 if (lpSource->hData32)
1011 {
1012 lpstrS = (LPSTR)GlobalLock(lpSource->hData32);
1013 }
1014 else
1015 {
1016 lpstrS = (LPSTR)GlobalLock16(lpSource->hData16);
1017 }
1018
1019 if (!lpstrS)
1020 return FALSE;
1021
1022 /* Text always NULL terminated */
1023 if(lpSource->wFormatID == CF_UNICODETEXT)
1024 src_chars = strlenW((LPCWSTR)lpstrS) + 1;
1025 else
1026 src_chars = strlen(lpstrS) + 1;
1027
1028 /* Calculate number of characters in the destination buffer */
1029 dst_chars = CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS,
1030 src_chars, wFormatID, NULL, 0);
1031
1032 if (!dst_chars)
1033 return FALSE;
1034
1035 TRACE("Converting from '%d' to '%d', %i chars\n",
1036 lpSource->wFormatID, wFormatID, src_chars);
1037
1038 /* Convert characters to bytes */
1039 if(wFormatID == CF_UNICODETEXT)
1040 alloc_size = dst_chars * sizeof(WCHAR);
1041 else
1042 alloc_size = dst_chars;
1043
1044 hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE |
1045 GMEM_DDESHARE, alloc_size);
1046
1047 lpstrT = (LPSTR)GlobalLock(hData32);
1048
1049 if (lpstrT)
1050 {
1051 CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
1052 wFormatID, lpstrT, dst_chars);
1053 GlobalUnlock(hData32);
1054 }
1055
1056 /* Unlock source */
1057 if (lpSource->hData32)
1058 GlobalUnlock(lpSource->hData32);
1059 else
1060 GlobalUnlock16(lpSource->hData16);
1061
1062 return X11DRV_CLIPBOARD_InsertClipboardData(wFormatID, 0, hData32, 0);
1063}
1064
1065
1066/**************************************************************************
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001067 * X11DRV_CLIPBOARD_RenderSynthesizedDIB
1068 *
1069 * Renders synthesized DIB
1070 */
1071static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB()
1072{
1073 BOOL bret = FALSE;
1074 LPWINE_CLIPDATA lpSource = NULL;
1075
1076 TRACE("\n");
1077
1078 if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) && lpSource->hData32)
1079 {
1080 bret = TRUE;
1081 }
1082 /* If we have a bitmap and it's not synthesized or it has been rendered */
1083 else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) &&
1084 (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData32))
1085 {
1086 /* Render source if required */
1087 if (lpSource->hData32 || X11DRV_CLIPBOARD_RenderFormat(lpSource))
1088 {
1089 HDC hdc;
1090 HGLOBAL hData32;
1091
1092 hdc = GetDC(NULL);
1093 hData32 = X11DRV_DIB_CreateDIBFromBitmap(hdc, lpSource->hData32);
1094 ReleaseDC(NULL, hdc);
1095
1096 if (hData32)
1097 {
1098 X11DRV_CLIPBOARD_InsertClipboardData(CF_DIB, 0, hData32, 0);
1099 bret = TRUE;
1100 }
1101 }
1102 }
1103
1104 return bret;
1105}
1106
1107
1108/**************************************************************************
1109 * X11DRV_CLIPBOARD_RenderSynthesizedBitmap
1110 *
1111 * Renders synthesized bitmap
1112 */
1113static BOOL X11DRV_CLIPBOARD_RenderSynthesizedBitmap()
1114{
1115 BOOL bret = FALSE;
1116 LPWINE_CLIPDATA lpSource = NULL;
1117
1118 TRACE("\n");
1119
1120 if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) && lpSource->hData32)
1121 {
1122 bret = TRUE;
1123 }
1124 /* If we have a dib and it's not synthesized or it has been rendered */
1125 else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) &&
1126 (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData32))
1127 {
1128 /* Render source if required */
1129 if (lpSource->hData32 || X11DRV_CLIPBOARD_RenderFormat(lpSource))
1130 {
1131 HDC hdc;
1132 HBITMAP hData32;
1133 unsigned int offset;
1134 LPBITMAPINFOHEADER lpbmih;
1135
1136 hdc = GetDC(NULL);
1137 lpbmih = (LPBITMAPINFOHEADER) GlobalLock(lpSource->hData32);
1138
1139 offset = sizeof(BITMAPINFOHEADER)
1140 + ((lpbmih->biBitCount <= 8) ? (sizeof(RGBQUAD) *
1141 (1 << lpbmih->biBitCount)) : 0);
1142
1143 hData32 = CreateDIBitmap(hdc, lpbmih, CBM_INIT, (LPBYTE)lpbmih +
1144 offset, (LPBITMAPINFO) lpbmih, DIB_RGB_COLORS);
1145
1146 GlobalUnlock(lpSource->hData32);
1147 ReleaseDC(NULL, hdc);
1148
1149 if (hData32)
1150 {
1151 X11DRV_CLIPBOARD_InsertClipboardData(CF_BITMAP, 0, hData32, 0);
1152 bret = TRUE;
1153 }
1154 }
1155 }
1156
1157 return bret;
1158}
1159
1160
1161/**************************************************************************
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001162 * X11DRV_CLIPBOARD_ImportXAString
1163 *
1164 * Import XA_STRING, converting the string to CF_UNICODE.
1165 */
1166HANDLE X11DRV_CLIPBOARD_ImportXAString(LPBYTE lpdata, UINT cBytes)
1167{
1168 LPSTR lpstr;
1169 UINT i, inlcount = 0;
1170 HANDLE hUnicodeText = 0;
1171
1172 for (i = 0; i <= cBytes; i++)
1173 {
1174 if (lpdata[i] == '\n')
1175 inlcount++;
1176 }
1177
1178 if ((lpstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cBytes + inlcount + 1)))
1179 {
1180 UINT count;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001181
1182 for (i = 0, inlcount = 0; i <= cBytes; i++)
1183 {
1184 if (lpdata[i] == '\n')
1185 lpstr[inlcount++] = '\r';
1186
1187 lpstr[inlcount++] = lpdata[i];
1188 }
1189
Dmitry Timoshkov8a8d1b92003-07-09 04:22:57 +00001190 count = MultiByteToWideChar(CP_UNIXCP, 0, lpstr, -1, NULL, 0);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001191 hUnicodeText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
1192
1193 if(hUnicodeText)
1194 {
1195 WCHAR *textW = GlobalLock(hUnicodeText);
Dmitry Timoshkov8a8d1b92003-07-09 04:22:57 +00001196 MultiByteToWideChar(CP_UNIXCP, 0, lpstr, -1, textW, count);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001197 GlobalUnlock(hUnicodeText);
1198 }
1199
1200 HeapFree(GetProcessHeap(), 0, lpstr);
1201 }
1202
1203 return hUnicodeText;
1204}
1205
1206
1207/**************************************************************************
1208 * X11DRV_CLIPBOARD_ImportXAPIXMAP
1209 *
1210 * Import XA_PIXMAP, converting the image to CF_DIB.
1211 */
1212HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(LPBYTE lpdata, UINT cBytes)
1213{
1214 HANDLE hTargetImage = 0; /* Handle to store the converted DIB */
1215 Pixmap *pPixmap = (Pixmap *) lpdata;
1216 HWND hwnd = GetOpenClipboardWindow();
1217 HDC hdc = GetDC(hwnd);
1218
1219 hTargetImage = X11DRV_DIB_CreateDIBFromPixmap(*pPixmap, hdc, TRUE);
1220
1221 ReleaseDC(hwnd, hdc);
1222
1223 return hTargetImage;
1224}
1225
1226
1227/**************************************************************************
1228 * X11DRV_CLIPBOARD_ImportMetaFilePict
1229 *
1230 * Import MetaFilePict.
1231 */
1232HANDLE X11DRV_CLIPBOARD_ImportMetaFilePict(LPBYTE lpdata, UINT cBytes)
1233{
1234 return X11DRV_CLIPBOARD_SerializeMetafile(CF_METAFILEPICT, (HANDLE)lpdata, (LPDWORD)&cBytes, FALSE);
1235}
1236
1237
1238/**************************************************************************
1239 * X11DRV_ImportEnhMetaFile
1240 *
1241 * Import EnhMetaFile.
1242 */
1243HANDLE X11DRV_CLIPBOARD_ImportEnhMetaFile(LPBYTE lpdata, UINT cBytes)
1244{
1245 return X11DRV_CLIPBOARD_SerializeMetafile(CF_ENHMETAFILE, (HANDLE)lpdata, (LPDWORD)&cBytes, FALSE);
1246}
1247
1248
1249/**************************************************************************
1250 * X11DRV_ImportClipbordaData
1251 *
1252 * Generic import clipboard data routine.
1253 */
1254HANDLE X11DRV_CLIPBOARD_ImportClipboardData(LPBYTE lpdata, UINT cBytes)
1255{
1256 LPVOID lpClipData;
1257 HANDLE hClipData = 0;
1258
1259 if (cBytes)
1260 {
1261 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
1262 hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cBytes);
Peter Berg Larsen4293b612005-03-14 10:03:39 +00001263 if (hClipData == 0) return NULL;
1264
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001265 if ((lpClipData = GlobalLock(hClipData)))
1266 {
1267 memcpy(lpClipData, lpdata, cBytes);
1268 GlobalUnlock(hClipData);
1269 }
Peter Berg Larsen4293b612005-03-14 10:03:39 +00001270 else {
1271 GlobalFree(hClipData);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001272 hClipData = 0;
Peter Berg Larsen4293b612005-03-14 10:03:39 +00001273 }
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001274 }
1275
1276 return hClipData;
1277}
1278
1279
1280/**************************************************************************
Ulrich Czekalla6af0df42004-01-08 00:43:46 +00001281 X11DRV_CLIPBOARD_ExportClipboardData
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001282 *
1283 * Generic export clipboard data routine.
1284 */
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001285HANDLE X11DRV_CLIPBOARD_ExportClipboardData(Window requestor, Atom aTarget,
1286 Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001287{
1288 LPVOID lpClipData;
1289 UINT cBytes = 0;
1290 HANDLE hClipData = 0;
1291
1292 *lpBytes = 0; /* Assume failure */
1293
1294 if (!X11DRV_CLIPBOARD_RenderFormat(lpData))
1295 ERR("Failed to export %d format\n", lpData->wFormatID);
1296 else
1297 {
1298 cBytes = GlobalSize(lpData->hData32);
1299
1300 hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cBytes);
Peter Berg Larsen4293b612005-03-14 10:03:39 +00001301 if (hClipData == 0) return NULL;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001302
1303 if ((lpClipData = GlobalLock(hClipData)))
1304 {
1305 LPVOID lpdata = GlobalLock(lpData->hData32);
1306
1307 memcpy(lpClipData, lpdata, cBytes);
1308 *lpBytes = cBytes;
1309
1310 GlobalUnlock(lpData->hData32);
1311 GlobalUnlock(hClipData);
Peter Berg Larsen4293b612005-03-14 10:03:39 +00001312 } else {
1313 GlobalFree(hClipData);
1314 hClipData = 0;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001315 }
1316 }
1317
1318 return hClipData;
1319}
1320
1321
1322/**************************************************************************
1323 * X11DRV_CLIPBOARD_ExportXAString
1324 *
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001325 * Export CF_UNICODE converting the string to XA_STRING.
1326 * Helper function for X11DRV_CLIPBOARD_ExportString.
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001327 */
1328HANDLE X11DRV_CLIPBOARD_ExportXAString(LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1329{
Hans Leidekker5f6f63a2004-08-11 23:45:34 +00001330 UINT i, j;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001331 UINT size;
1332 LPWSTR uni_text;
Peter Berg Larsen4293b612005-03-14 10:03:39 +00001333 LPSTR text, lpstr = NULL;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001334
1335 *lpBytes = 0; /* Assume return has zero bytes */
1336
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001337 uni_text = GlobalLock(lpData->hData32);
1338
Dmitry Timoshkov8a8d1b92003-07-09 04:22:57 +00001339 size = WideCharToMultiByte(CP_UNIXCP, 0, uni_text, -1, NULL, 0, NULL, NULL);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001340
1341 text = HeapAlloc(GetProcessHeap(), 0, size);
Peter Berg Larsen4293b612005-03-14 10:03:39 +00001342 if (!text) goto done;
Dmitry Timoshkov8a8d1b92003-07-09 04:22:57 +00001343 WideCharToMultiByte(CP_UNIXCP, 0, uni_text, -1, text, size, NULL, NULL);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001344
1345 /* remove carriage returns */
1346
Jakob Eriksson9ed61de2005-03-24 21:01:35 +00001347 lpstr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size-- );
Peter Berg Larsen4293b612005-03-14 10:03:39 +00001348 if(lpstr == NULL) goto done;
1349
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001350 for(i = 0,j = 0; i < size && text[i]; i++ )
1351 {
1352 if( text[i] == '\r' &&
1353 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
1354 lpstr[j++] = text[i];
1355 }
1356 lpstr[j]='\0';
1357
1358 *lpBytes = j; /* Number of bytes in string */
1359
Peter Berg Larsen4293b612005-03-14 10:03:39 +00001360done:
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001361 HeapFree(GetProcessHeap(), 0, text);
1362 GlobalUnlock(lpData->hData32);
1363
1364 return lpstr;
1365}
1366
1367
1368/**************************************************************************
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001369 * X11DRV_CLIPBOARD_ExportCompoundText
1370 *
1371 * Export CF_UNICODE to COMPOUND_TEXT or TEXT
1372 * Helper function for X11DRV_CLIPBOARD_ExportString.
1373 */
1374HANDLE X11DRV_CLIPBOARD_ExportCompoundText(Window requestor, Atom aTarget, Atom rprop,
1375 LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1376{
1377 Display *display = thread_display();
1378 char* lpstr = 0;
1379 XTextProperty prop;
1380 XICCEncodingStyle style;
1381
1382 lpstr = (char*) X11DRV_CLIPBOARD_ExportXAString(lpData, lpBytes);
1383
1384 if (lpstr)
1385 {
Alexandre Julliardd09c3282003-11-20 04:24:18 +00001386 if (aTarget == x11drv_atom(COMPOUND_TEXT))
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001387 style = XCompoundTextStyle;
1388 else
1389 style = XStdICCTextStyle;
1390
1391 /* Update the X property */
1392 wine_tsx11_lock();
1393 if (XmbTextListToTextProperty(display, &lpstr, 1, style, &prop) == Success)
1394 {
1395 XSetTextProperty(display, requestor, &prop, rprop);
1396 XFree(prop.value);
1397 }
1398 wine_tsx11_unlock();
1399
1400 HeapFree( GetProcessHeap(), 0, lpstr );
1401 }
1402
1403 return 0;
1404}
1405
1406/**************************************************************************
1407 * X11DRV_CLIPBOARD_ExportString
1408 *
1409 * Export CF_UNICODE string
1410 */
1411HANDLE X11DRV_CLIPBOARD_ExportString(Window requestor, Atom aTarget, Atom rprop,
1412 LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1413{
1414 if (X11DRV_CLIPBOARD_RenderFormat(lpData))
1415 {
1416 if (aTarget == XA_STRING)
1417 return X11DRV_CLIPBOARD_ExportXAString(lpData, lpBytes);
Alexandre Julliardd09c3282003-11-20 04:24:18 +00001418 else if (aTarget == x11drv_atom(COMPOUND_TEXT) || aTarget == x11drv_atom(TEXT))
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001419 return X11DRV_CLIPBOARD_ExportCompoundText(requestor, aTarget,
1420 rprop, lpData, lpBytes);
1421 else
1422 ERR("Unknown target %ld to %d format\n", aTarget, lpData->wFormatID);
1423 }
1424 else
1425 ERR("Failed to render %d format\n", lpData->wFormatID);
1426
1427 return 0;
1428}
1429
1430
1431/**************************************************************************
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001432 * X11DRV_CLIPBOARD_ExportXAPIXMAP
1433 *
1434 * Export CF_DIB to XA_PIXMAP.
1435 */
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001436HANDLE X11DRV_CLIPBOARD_ExportXAPIXMAP(Window requestor, Atom aTarget, Atom rprop,
1437 LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001438{
1439 HDC hdc;
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001440 HANDLE hData;
1441 unsigned char* lpData;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001442
1443 if (!X11DRV_CLIPBOARD_RenderFormat(lpdata))
1444 {
1445 ERR("Failed to export %d format\n", lpdata->wFormatID);
1446 return 0;
1447 }
1448
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001449 if (!lpdata->drvData) /* If not already rendered */
1450 {
1451 /* For convert from packed DIB to Pixmap */
1452 hdc = GetDC(0);
1453 lpdata->drvData = (UINT) X11DRV_DIB_CreatePixmapFromDIB(lpdata->hData32, hdc);
1454 ReleaseDC(0, hdc);
1455 }
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001456
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001457 *lpBytes = sizeof(Pixmap); /* pixmap is a 32bit value */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001458
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001459 /* Wrap pixmap so we can return a handle */
1460 hData = GlobalAlloc(0, *lpBytes);
1461 lpData = GlobalLock(hData);
1462 memcpy(lpData, &lpdata->drvData, *lpBytes);
1463 GlobalUnlock(hData);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001464
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001465 return (HANDLE) hData;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001466}
1467
1468
1469/**************************************************************************
1470 * X11DRV_CLIPBOARD_ExportMetaFilePict
1471 *
1472 * Export MetaFilePict.
1473 */
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001474HANDLE X11DRV_CLIPBOARD_ExportMetaFilePict(Window requestor, Atom aTarget, Atom rprop,
1475 LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001476{
1477 if (!X11DRV_CLIPBOARD_RenderFormat(lpdata))
1478 {
1479 ERR("Failed to export %d format\n", lpdata->wFormatID);
1480 return 0;
1481 }
1482
1483 return X11DRV_CLIPBOARD_SerializeMetafile(CF_METAFILEPICT, (HANDLE)lpdata->hData32,
1484 lpBytes, TRUE);
1485}
1486
1487
1488/**************************************************************************
1489 * X11DRV_CLIPBOARD_ExportEnhMetaFile
1490 *
1491 * Export EnhMetaFile.
1492 */
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001493HANDLE X11DRV_CLIPBOARD_ExportEnhMetaFile(Window requestor, Atom aTarget, Atom rprop,
1494 LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001495{
1496 if (!X11DRV_CLIPBOARD_RenderFormat(lpdata))
1497 {
1498 ERR("Failed to export %d format\n", lpdata->wFormatID);
1499 return 0;
1500 }
1501
1502 return X11DRV_CLIPBOARD_SerializeMetafile(CF_ENHMETAFILE, (HANDLE)lpdata->hData32,
1503 lpBytes, TRUE);
1504}
1505
1506
1507/**************************************************************************
1508 * X11DRV_CLIPBOARD_QueryTargets
1509 */
Ulrich Czekalla5b1a13b2004-07-08 20:14:37 +00001510static BOOL X11DRV_CLIPBOARD_QueryTargets(Display *display, Window w, Atom selection,
1511 Atom target, XEvent *xe)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001512{
1513 INT i;
1514 Bool res;
1515
1516 wine_tsx11_lock();
Ulrich Czekalla5b1a13b2004-07-08 20:14:37 +00001517 XConvertSelection(display, selection, target,
1518 x11drv_atom(SELECTION_DATA), w, CurrentTime);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001519 wine_tsx11_unlock();
1520
1521 /*
1522 * Wait until SelectionNotify is received
1523 */
1524 for (i = 0; i < SELECTION_RETRIES; i++)
1525 {
1526 wine_tsx11_lock();
1527 res = XCheckTypedWindowEvent(display, w, SelectionNotify, xe);
1528 wine_tsx11_unlock();
1529 if (res && xe->xselection.selection == selection) break;
1530
1531 usleep(SELECTION_WAIT);
1532 }
1533
1534 /* Verify that the selection returned a valid TARGETS property */
Ulrich Czekalla5b1a13b2004-07-08 20:14:37 +00001535 if ((xe->xselection.target != target) || (xe->xselection.property == None))
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001536 {
1537 /* Selection owner failed to respond or we missed the SelectionNotify */
1538 WARN("Failed to retrieve TARGETS for selection %ld.\n", selection);
1539 return FALSE;
1540 }
1541
1542 return TRUE;
1543}
1544
1545
1546/**************************************************************************
Ulrich Czekalla5b1a13b2004-07-08 20:14:37 +00001547 * X11DRV_CLIPBOARD_InsertSelectionProperties
1548 *
1549 * Mark property available for future retrieval.
1550 */
1551static VOID X11DRV_CLIPBOARD_InsertSelectionProperties(Display *display, Atom* properties, UINT count)
1552{
Hans Leidekker5f6f63a2004-08-11 23:45:34 +00001553 UINT i, nb_atoms = 0;
Ulrich Czekalla5b1a13b2004-07-08 20:14:37 +00001554 Atom *atoms = NULL;
1555
1556 /* Cache these formats in the clipboard cache */
1557 for (i = 0; i < count; i++)
1558 {
1559 LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(properties[i]);
1560
1561 if (!lpFormat)
1562 lpFormat = X11DRV_CLIPBOARD_LookupAliasProperty(properties[i]);
1563
1564 if (!lpFormat)
1565 {
1566 /* add it to the list of atoms that we don't know about yet */
1567 if (!atoms) atoms = HeapAlloc( GetProcessHeap(), 0,
1568 (count - i) * sizeof(*atoms) );
1569 if (atoms) atoms[nb_atoms++] = properties[i];
1570 }
1571 else
1572 {
1573 TRACE("Atom#%d Property(%d): --> FormatID(%d) %s\n",
Jacek Caban7e2a7c92005-01-11 15:10:56 +00001574 i, lpFormat->drvData, lpFormat->wFormatID, debugstr_w(lpFormat->Name));
Ulrich Czekalla5b1a13b2004-07-08 20:14:37 +00001575 X11DRV_CLIPBOARD_InsertClipboardData(lpFormat->wFormatID, 0, 0, 0);
1576 }
1577 }
1578
1579 /* query all unknown atoms in one go */
1580 if (atoms)
1581 {
1582 char **names = HeapAlloc( GetProcessHeap(), 0, nb_atoms * sizeof(*names) );
1583 if (names)
1584 {
1585 wine_tsx11_lock();
1586 XGetAtomNames( display, atoms, nb_atoms, names );
1587 wine_tsx11_unlock();
1588 for (i = 0; i < nb_atoms; i++)
1589 {
Jacek Caban7e2a7c92005-01-11 15:10:56 +00001590 WINE_CLIPFORMAT *lpFormat;
1591 LPWSTR wname;
1592 int len = MultiByteToWideChar(CP_UNIXCP, 0, names[i], -1, NULL, 0);
1593 wname = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
1594 MultiByteToWideChar(CP_UNIXCP, 0, names[i], -1, wname, len);
1595
1596 lpFormat = register_format( wname, atoms[i] );
1597 HeapFree(GetProcessHeap(), 0, wname);
Ulrich Czekalla5b1a13b2004-07-08 20:14:37 +00001598 if (!lpFormat)
1599 {
1600 ERR("Failed to register %s property. Type will not be cached.\n", names[i]);
1601 continue;
1602 }
1603 TRACE("Atom#%d Property(%d): --> FormatID(%d) %s\n",
Jacek Caban7e2a7c92005-01-11 15:10:56 +00001604 i, lpFormat->drvData, lpFormat->wFormatID, debugstr_w(lpFormat->Name));
Ulrich Czekalla5b1a13b2004-07-08 20:14:37 +00001605 X11DRV_CLIPBOARD_InsertClipboardData(lpFormat->wFormatID, 0, 0, 0);
1606 }
1607 wine_tsx11_lock();
1608 for (i = 0; i < nb_atoms; i++) XFree( names[i] );
1609 wine_tsx11_unlock();
1610 HeapFree( GetProcessHeap(), 0, names );
1611 }
1612 HeapFree( GetProcessHeap(), 0, atoms );
1613 }
1614}
1615
1616
1617/**************************************************************************
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001618 * X11DRV_CLIPBOARD_QueryAvailableData
Noel Borthwick29700671999-09-03 15:17:57 +00001619 *
1620 * Caches the list of data formats available from the current selection.
1621 * This queries the selection owner for the TARGETS property and saves all
1622 * reported property types.
1623 */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001624static int X11DRV_CLIPBOARD_QueryAvailableData(LPCLIPBOARDINFO lpcbinfo)
Noel Borthwick29700671999-09-03 15:17:57 +00001625{
Alexandre Julliard43230042001-05-16 19:52:29 +00001626 Display *display = thread_display();
Noel Borthwick29700671999-09-03 15:17:57 +00001627 XEvent xe;
Noel Borthwick29700671999-09-03 15:17:57 +00001628 Atom atype=AnyPropertyType;
1629 int aformat;
1630 unsigned long remain;
1631 Atom* targetList=NULL;
1632 Window w;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001633 unsigned long cSelectionTargets = 0;
Vincent Béron9a624912002-05-31 23:06:46 +00001634
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001635 if (selectionAcquired & (S_PRIMARY | S_CLIPBOARD))
1636 {
1637 ERR("Received request to cache selection but process is owner=(%08x)\n",
1638 (unsigned) selectionWindow);
Ulrich Czekalla18fe91d2005-03-01 10:43:58 +00001639 return -1; /* Prevent self request */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001640 }
1641
Ulrich Czekalla50679092005-03-07 19:31:46 +00001642 w = thread_selection_wnd();
1643 if (!w)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001644 {
Ulrich Czekalla50679092005-03-07 19:31:46 +00001645 ERR("No window available to retrieve selection!\n");
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001646 return -1;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001647 }
1648
Noel Borthwick29700671999-09-03 15:17:57 +00001649 /*
1650 * Query the selection owner for the TARGETS property
1651 */
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001652 wine_tsx11_lock();
Ulrich Czekalla6af0df42004-01-08 00:43:46 +00001653 if ((usePrimary && XGetSelectionOwner(display,XA_PRIMARY)) ||
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001654 XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)))
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001655 {
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001656 wine_tsx11_unlock();
Ulrich Czekalla5b1a13b2004-07-08 20:14:37 +00001657 if (usePrimary && (X11DRV_CLIPBOARD_QueryTargets(display, w, XA_PRIMARY, x11drv_atom(TARGETS), &xe)))
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001658 selectionCacheSrc = XA_PRIMARY;
Ulrich Czekalla5b1a13b2004-07-08 20:14:37 +00001659 else if (X11DRV_CLIPBOARD_QueryTargets(display, w, x11drv_atom(CLIPBOARD), x11drv_atom(TARGETS), &xe))
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001660 selectionCacheSrc = x11drv_atom(CLIPBOARD);
1661 else
Ulrich Czekalla5b1a13b2004-07-08 20:14:37 +00001662 {
1663 Atom xstr = XA_PRIMARY;
1664
1665 /* Selection Owner doesn't understand TARGETS, try retrieving XA_STRING */
1666 if (X11DRV_CLIPBOARD_QueryTargets(display, w, XA_PRIMARY, XA_STRING, &xe))
1667 {
1668 X11DRV_CLIPBOARD_InsertSelectionProperties(display, &xstr, 1);
1669 selectionCacheSrc = XA_PRIMARY;
1670 return 1;
1671 }
1672 else if (X11DRV_CLIPBOARD_QueryTargets(display, w, x11drv_atom(CLIPBOARD), XA_STRING, &xe))
1673 {
1674 X11DRV_CLIPBOARD_InsertSelectionProperties(display, &xstr, 1);
1675 selectionCacheSrc = x11drv_atom(CLIPBOARD);
1676 return 1;
1677 }
1678 else
1679 {
1680 WARN("Failed to query selection owner for available data.\n");
1681 return -1;
1682 }
1683 }
Ulrich Czekalla18873e72003-07-08 21:02:51 +00001684 }
1685 else /* No selection owner so report 0 targets available */
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001686 {
1687 wine_tsx11_unlock();
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001688 return 0;
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001689 }
Noel Borthwick29700671999-09-03 15:17:57 +00001690
1691 /* Read the TARGETS property contents */
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001692 wine_tsx11_lock();
1693 if(XGetWindowProperty(display, xe.xselection.requestor, xe.xselection.property,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001694 0, 0x3FFF, True, AnyPropertyType/*XA_ATOM*/, &atype, &aformat, &cSelectionTargets,
1695 &remain, (unsigned char**)&targetList) != Success)
1696 {
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001697 wine_tsx11_unlock();
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001698 WARN("Failed to read TARGETS property\n");
1699 }
Noel Borthwick29700671999-09-03 15:17:57 +00001700 else
1701 {
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001702 wine_tsx11_unlock();
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +00001703 TRACE("Type %lx,Format %d,nItems %ld, Remain %ld\n",
1704 atype, aformat, cSelectionTargets, remain);
Noel Borthwick29700671999-09-03 15:17:57 +00001705 /*
1706 * The TARGETS property should have returned us a list of atoms
1707 * corresponding to each selection target format supported.
1708 */
Alexandre Julliardd09c3282003-11-20 04:24:18 +00001709 if ((atype == XA_ATOM || atype == x11drv_atom(TARGETS)) && aformat == 32)
Ulrich Czekalla5b1a13b2004-07-08 20:14:37 +00001710 X11DRV_CLIPBOARD_InsertSelectionProperties(display, targetList, cSelectionTargets);
Noel Borthwick29700671999-09-03 15:17:57 +00001711
1712 /* Free the list of targets */
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001713 wine_tsx11_lock();
1714 XFree(targetList);
1715 wine_tsx11_unlock();
Noel Borthwick29700671999-09-03 15:17:57 +00001716 }
Gerard Patel9289a5d2000-12-22 23:26:18 +00001717
Noel Borthwick29700671999-09-03 15:17:57 +00001718 return cSelectionTargets;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001719}
1720
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001721
1722/**************************************************************************
1723 * X11DRV_CLIPBOARD_ReadClipboardData
1724 *
1725 * This method is invoked only when we DO NOT own the X selection
1726 *
1727 * We always get the data from the selection client each time,
1728 * since we have no way of determining if the data in our cache is stale.
1729 */
1730static BOOL X11DRV_CLIPBOARD_ReadClipboardData(UINT wFormat)
1731{
1732 Display *display = thread_display();
1733 BOOL bRet = FALSE;
1734 Bool res;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001735 LPWINE_CLIPFORMAT lpFormat;
1736
1737 TRACE("%d\n", wFormat);
1738
1739 if (!selectionAcquired)
1740 {
Ulrich Czekalla50679092005-03-07 19:31:46 +00001741 Window w = thread_selection_wnd();
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001742 if(!w)
1743 {
Ulrich Czekalla50679092005-03-07 19:31:46 +00001744 ERR("No window available to read selection data!\n");
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001745 return FALSE;
1746 }
1747
1748 lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
1749
Rein Klazes46138d82004-04-05 20:17:13 +00001750 if (lpFormat && lpFormat->drvData)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001751 {
1752 DWORD i;
1753 UINT alias;
1754 XEvent xe;
1755
1756 TRACE("Requesting %s selection (%d) from win(%08x)\n",
Jacek Caban7e2a7c92005-01-11 15:10:56 +00001757 debugstr_w(lpFormat->Name), lpFormat->drvData, (UINT)selectionCacheSrc);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001758
1759 wine_tsx11_lock();
1760 XConvertSelection(display, selectionCacheSrc, lpFormat->drvData,
Alexandre Julliardd09c3282003-11-20 04:24:18 +00001761 x11drv_atom(SELECTION_DATA), w, CurrentTime);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001762 wine_tsx11_unlock();
1763
1764 /* wait until SelectionNotify is received */
1765 for (i = 0; i < SELECTION_RETRIES; i++)
1766 {
1767 wine_tsx11_lock();
1768 res = XCheckTypedWindowEvent(display, w, SelectionNotify, &xe);
1769 wine_tsx11_unlock();
1770 if (res && xe.xselection.selection == selectionCacheSrc) break;
1771
1772 usleep(SELECTION_WAIT);
1773 }
1774
1775 /* If the property wasn't available check for aliases */
1776 if (xe.xselection.property == None &&
1777 (alias = X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData)))
1778 {
1779 wine_tsx11_lock();
1780 XConvertSelection(display, selectionCacheSrc, alias,
Alexandre Julliardd09c3282003-11-20 04:24:18 +00001781 x11drv_atom(SELECTION_DATA), w, CurrentTime);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001782 wine_tsx11_unlock();
1783
1784 /* wait until SelectionNotify is received */
1785 for (i = 0; i < SELECTION_RETRIES; i++)
1786 {
1787 wine_tsx11_lock();
1788 res = XCheckTypedWindowEvent(display, w, SelectionNotify, &xe);
1789 wine_tsx11_unlock();
1790 if (res && xe.xselection.selection == selectionCacheSrc) break;
1791
1792 usleep(SELECTION_WAIT);
1793 }
1794 }
1795
1796 /* Verify that the selection returned a valid TARGETS property */
1797 if (xe.xselection.property != None)
1798 {
1799 /*
1800 * Read the contents of the X selection property
1801 * into WINE's clipboard cache converting the
1802 * selection to be compatible if possible.
1803 */
1804 bRet = X11DRV_CLIPBOARD_ReadSelection(lpFormat, xe.xselection.requestor,
1805 xe.xselection.property);
1806 }
1807 }
1808 }
1809 else
1810 {
1811 ERR("Received request to cache selection data but process is owner\n");
1812 }
1813
1814 TRACE("Returning %d\n", bRet);
1815
1816 return bRet;
1817}
1818
1819
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001820/**************************************************************************
1821 * X11DRV_CLIPBOARD_ReadSelection
Noel Borthwick29700671999-09-03 15:17:57 +00001822 * Reads the contents of the X selection property into the WINE clipboard cache
1823 * converting the selection into a format compatible with the windows clipboard
1824 * if possible.
1825 * This method is invoked only to read the contents of a the selection owned
1826 * by an external application. i.e. when we do not own the X selection.
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001827 */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001828static BOOL X11DRV_CLIPBOARD_ReadSelection(LPWINE_CLIPFORMAT lpData, Window w, Atom prop)
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001829{
Alexandre Julliard43230042001-05-16 19:52:29 +00001830 Display *display = thread_display();
Noel Borthwick29700671999-09-03 15:17:57 +00001831 Atom atype=AnyPropertyType;
1832 int aformat;
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001833 unsigned long total,nitems,remain,val_cnt;
1834 long reqlen, bwc;
Aric Stewart278dd152001-02-23 01:31:47 +00001835 unsigned char* val;
1836 unsigned char* buffer;
Noel Borthwick29700671999-09-03 15:17:57 +00001837 BOOL bRet = FALSE;
Vincent Béron9a624912002-05-31 23:06:46 +00001838
Noel Borthwick29700671999-09-03 15:17:57 +00001839 if(prop == None)
1840 return bRet;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001841
Jacek Caban7e2a7c92005-01-11 15:10:56 +00001842 TRACE("Reading X selection type %s\n", debugstr_w(lpData->Name));
Noel Borthwick29700671999-09-03 15:17:57 +00001843
1844 /*
Noel Borthwick29700671999-09-03 15:17:57 +00001845 * First request a zero length in order to figure out the request size.
1846 */
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001847 wine_tsx11_lock();
1848 if(XGetWindowProperty(display,w,prop,0,0,False, AnyPropertyType,
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001849 &atype, &aformat, &nitems, &remain, &buffer) != Success)
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001850 {
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001851 wine_tsx11_unlock();
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001852 WARN("Failed to get property size\n");
Noel Borthwick29700671999-09-03 15:17:57 +00001853 return bRet;
1854 }
Noel Borthwickd05b7be1999-09-20 15:42:47 +00001855
1856 /* Free zero length return data if any */
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001857 if (buffer)
Noel Borthwick29700671999-09-03 15:17:57 +00001858 {
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001859 XFree(buffer);
1860 buffer = NULL;
Noel Borthwick29700671999-09-03 15:17:57 +00001861 }
Vincent Béron9a624912002-05-31 23:06:46 +00001862
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001863 bwc = aformat/8;
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001864 reqlen = remain * bwc;
1865
1866 TRACE("Retrieving %ld bytes\n", reqlen);
1867
Jakob Eriksson9ed61de2005-03-24 21:01:35 +00001868 val = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, reqlen);
Aric Stewart278dd152001-02-23 01:31:47 +00001869
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001870 /* Read property in 4K blocks */
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001871 for (total = 0, val_cnt = 0; remain;)
Noel Borthwick29700671999-09-03 15:17:57 +00001872 {
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001873 if (XGetWindowProperty(display, w, prop, (total / 4), 4096, False,
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001874 AnyPropertyType, &atype, &aformat, &nitems, &remain, &buffer) != Success)
1875 {
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001876 wine_tsx11_unlock();
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001877 WARN("Failed to read property\n");
1878 HeapFree(GetProcessHeap(), 0, val);
1879 return bRet;
1880 }
Aric Stewart278dd152001-02-23 01:31:47 +00001881
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001882 bwc = aformat/8;
1883 memcpy(&val[val_cnt], buffer, nitems * bwc);
1884 val_cnt += nitems * bwc;
Aric Stewart278dd152001-02-23 01:31:47 +00001885 total += nitems*bwc;
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001886 XFree(buffer);
Noel Borthwick29700671999-09-03 15:17:57 +00001887 }
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00001888 wine_tsx11_unlock();
Vincent Béron9a624912002-05-31 23:06:46 +00001889
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001890 bRet = X11DRV_CLIPBOARD_InsertClipboardData(lpData->wFormatID, 0, lpData->lpDrvImportFunc(val, total), 0);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001891
Noel Borthwickd05b7be1999-09-20 15:42:47 +00001892 /* Delete the property on the window now that we are done
1893 * This will send a PropertyNotify event to the selection owner. */
Alexandre Julliard2496c082003-11-21 00:17:33 +00001894 wine_tsx11_lock();
1895 XDeleteProperty(display,w,prop);
1896 wine_tsx11_unlock();
Vincent Béron9a624912002-05-31 23:06:46 +00001897
Noel Borthwickd05b7be1999-09-20 15:42:47 +00001898 /* Free the retrieved property data */
Aric Stewart278dd152001-02-23 01:31:47 +00001899 HeapFree(GetProcessHeap(),0,val);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001900
Noel Borthwick29700671999-09-03 15:17:57 +00001901 return bRet;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001902}
1903
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001904
1905/**************************************************************************
1906 * CLIPBOARD_SerializeMetafile
1907 */
1908static HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, LPDWORD lpcbytes, BOOL out)
1909{
1910 HANDLE h = 0;
1911
1912 TRACE(" wFormat=%d hdata=%08x out=%d\n", wformat, (unsigned int) hdata, out);
1913
1914 if (out) /* Serialize out, caller should free memory */
1915 {
1916 *lpcbytes = 0; /* Assume failure */
1917
1918 if (wformat == CF_METAFILEPICT)
1919 {
1920 LPMETAFILEPICT lpmfp = (LPMETAFILEPICT) GlobalLock(hdata);
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001921 unsigned int size = GetMetaFileBitsEx(lpmfp->hMF, 0, NULL);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001922
1923 h = GlobalAlloc(0, size + sizeof(METAFILEPICT));
1924 if (h)
1925 {
1926 char *pdata = GlobalLock(h);
1927
1928 memcpy(pdata, lpmfp, sizeof(METAFILEPICT));
1929 GetMetaFileBitsEx(lpmfp->hMF, size, pdata + sizeof(METAFILEPICT));
1930
1931 *lpcbytes = size + sizeof(METAFILEPICT);
1932
1933 GlobalUnlock(h);
1934 }
1935
1936 GlobalUnlock(hdata);
1937 }
1938 else if (wformat == CF_ENHMETAFILE)
1939 {
1940 int size = GetEnhMetaFileBits(hdata, 0, NULL);
1941
1942 h = GlobalAlloc(0, size);
1943 if (h)
1944 {
1945 LPVOID pdata = GlobalLock(h);
1946
1947 GetEnhMetaFileBits(hdata, size, pdata);
1948 *lpcbytes = size;
1949
1950 GlobalUnlock(h);
1951 }
1952 }
1953 }
1954 else
1955 {
1956 if (wformat == CF_METAFILEPICT)
1957 {
1958 h = GlobalAlloc(0, sizeof(METAFILEPICT));
1959 if (h)
1960 {
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001961 unsigned int wiresize, size;
1962 LPMETAFILEPICT lpmfp = (LPMETAFILEPICT) GlobalLock(h);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001963
Ulrich Czekalla455a2232004-02-20 05:43:00 +00001964 memcpy(lpmfp, (LPVOID)hdata, sizeof(METAFILEPICT));
1965 wiresize = *lpcbytes - sizeof(METAFILEPICT);
1966 lpmfp->hMF = SetMetaFileBitsEx(wiresize,
1967 ((char *)hdata) + sizeof(METAFILEPICT));
1968 size = GetMetaFileBitsEx(lpmfp->hMF, 0, NULL);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001969 GlobalUnlock(h);
1970 }
1971 }
1972 else if (wformat == CF_ENHMETAFILE)
1973 {
1974 h = SetEnhMetaFileBits(*lpcbytes, (LPVOID)hdata);
1975 }
1976 }
1977
1978 return h;
1979}
1980
1981
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001982/**************************************************************************
1983 * X11DRV_CLIPBOARD_ReleaseSelection
1984 *
Ulrich Czekalla318b9632005-01-04 20:34:46 +00001985 * Release XA_CLIPBOARD and XA_PRIMARY in response to a SelectionClear event.
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001986 */
Ulrich Czekalla318b9632005-01-04 20:34:46 +00001987void X11DRV_CLIPBOARD_ReleaseSelection(Atom selType, Window w, HWND hwnd, Time time)
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001988{
Alexandre Julliard43230042001-05-16 19:52:29 +00001989 Display *display = thread_display();
Vincent Béron9a624912002-05-31 23:06:46 +00001990
Francis Beaudet56ab55d1999-10-24 20:22:24 +00001991 /* w is the window that lost the selection
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001992 */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00001993 TRACE("event->window = %08x (selectionWindow = %08x) selectionAcquired=0x%08x\n",
1994 (unsigned)w, (unsigned)selectionWindow, (unsigned)selectionAcquired);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001995
Ulrich Czekalla318b9632005-01-04 20:34:46 +00001996 if (selectionAcquired && (w == selectionWindow))
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001997 {
Ulrich Czekalla318b9632005-01-04 20:34:46 +00001998 CLIPBOARDINFO cbinfo;
1999
2000 /* completely give up the selection */
2001 TRACE("Lost CLIPBOARD (+PRIMARY) selection\n");
2002
2003 X11DRV_CLIPBOARD_GetClipboardInfo(&cbinfo);
2004
Ulrich Czekalla50679092005-03-07 19:31:46 +00002005 if (cbinfo.flags & CB_PROCESS)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002006 {
Ulrich Czekalla50679092005-03-07 19:31:46 +00002007 /* Since we're still the owner, this wasn't initiated by
Ulrich Czekalla318b9632005-01-04 20:34:46 +00002008 another Wine process */
2009 if (OpenClipboard(hwnd))
Noel Borthwick29700671999-09-03 15:17:57 +00002010 {
Ulrich Czekalla318b9632005-01-04 20:34:46 +00002011 /* Destroy private objects */
2012 SendMessageW(cbinfo.hWndOwner, WM_DESTROYCLIPBOARD, 0, 0);
Francis Beaudet56ab55d1999-10-24 20:22:24 +00002013
Ulrich Czekalla318b9632005-01-04 20:34:46 +00002014 /* Give up ownership of the windows clipboard */
2015 X11DRV_CLIPBOARD_ReleaseOwnership();
2016 CloseClipboard();
Noel Borthwick29700671999-09-03 15:17:57 +00002017 }
Ulrich Czekalla318b9632005-01-04 20:34:46 +00002018 }
2019
2020 if ((selType == x11drv_atom(CLIPBOARD)) && (selectionAcquired & S_PRIMARY))
2021 {
2022 TRACE("Lost clipboard. Check if we need to release PRIMARY\n");
2023
2024 wine_tsx11_lock();
2025 if (selectionWindow == XGetSelectionOwner(display, XA_PRIMARY))
Noel Borthwick29700671999-09-03 15:17:57 +00002026 {
Ulrich Czekalla318b9632005-01-04 20:34:46 +00002027 TRACE("We still own PRIMARY. Releasing PRIMARY.\n");
2028 XSetSelectionOwner(display, XA_PRIMARY, None, time);
Noel Borthwick29700671999-09-03 15:17:57 +00002029 }
Ulrich Czekalla318b9632005-01-04 20:34:46 +00002030 else
2031 TRACE("We no longer own PRIMARY\n");
2032 wine_tsx11_unlock();
2033 }
2034 else if ((selType == XA_PRIMARY) && (selectionAcquired & S_CLIPBOARD))
2035 {
2036 TRACE("Lost PRIMARY. Check if we need to release CLIPBOARD\n");
2037
2038 wine_tsx11_lock();
2039 if (selectionWindow == XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)))
2040 {
2041 TRACE("We still own CLIPBOARD. Releasing CLIPBOARD.\n");
2042 XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), None, time);
2043 }
2044 else
2045 TRACE("We no longer own CLIPBOARD\n");
2046 wine_tsx11_unlock();
2047 }
2048
2049 selectionWindow = None;
2050
2051 X11DRV_EmptyClipboard(FALSE);
2052
2053 /* Reset the selection flags now that we are done */
2054 selectionAcquired = S_NOSELECTION;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002055 }
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002056}
2057
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002058
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002059/**************************************************************************
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002060 * IsSelectionOwner (X11DRV.@)
2061 *
2062 * Returns: TRUE if the selection is owned by this process, FALSE otherwise
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002063 */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002064static BOOL X11DRV_CLIPBOARD_IsSelectionOwner(void)
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002065{
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002066 return selectionAcquired;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002067}
2068
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002069
2070/**************************************************************************
2071 * X11DRV Clipboard Exports
2072 **************************************************************************/
2073
2074
2075/**************************************************************************
2076 * RegisterClipboardFormat (X11DRV.@)
2077 *
2078 * Registers a custom X clipboard format
2079 * Returns: Format id or 0 on failure
2080 */
Jacek Caban7e2a7c92005-01-11 15:10:56 +00002081INT X11DRV_RegisterClipboardFormat(LPCWSTR FormatName)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002082{
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +00002083 LPWINE_CLIPFORMAT lpFormat;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002084
Alexandre Julliard3f6cb0c2003-11-21 05:23:17 +00002085 if (FormatName == NULL) return 0;
2086 if (!(lpFormat = register_format( FormatName, 0 ))) return 0;
2087 return lpFormat->wFormatID;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002088}
2089
2090
2091/**************************************************************************
2092 * X11DRV_GetClipboardFormatName
2093 */
Jacek Caban7e2a7c92005-01-11 15:10:56 +00002094INT X11DRV_GetClipboardFormatName(UINT wFormat, LPWSTR retStr, INT maxlen)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002095{
Dmitry Timoshkovb3569e72004-06-25 02:55:37 +00002096 LPWINE_CLIPFORMAT lpFormat;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002097
2098 TRACE("(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
2099
Dmitry Timoshkovb3569e72004-06-25 02:55:37 +00002100 if (wFormat < 0xc000)
2101 {
2102 SetLastError(ERROR_INVALID_PARAMETER);
2103 return 0;
2104 }
2105
2106 lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
2107
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002108 if (!lpFormat || (lpFormat->wFlags & CF_FLAG_BUILTINFMT))
2109 {
2110 TRACE("Unknown format 0x%08x!\n", wFormat);
Dmitry Timoshkovb3569e72004-06-25 02:55:37 +00002111 SetLastError(ERROR_INVALID_HANDLE);
2112 return 0;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002113 }
2114
Jacek Caban7e2a7c92005-01-11 15:10:56 +00002115 lstrcpynW(retStr, lpFormat->Name, maxlen);
Dmitry Timoshkovb3569e72004-06-25 02:55:37 +00002116
Jacek Caban7e2a7c92005-01-11 15:10:56 +00002117 return strlenW(retStr);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002118}
2119
2120
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002121/**************************************************************************
Patrik Stridvalldf75e892001-02-12 03:49:07 +00002122 * AcquireClipboard (X11DRV.@)
Noel Borthwick29700671999-09-03 15:17:57 +00002123 */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002124void X11DRV_AcquireClipboard(HWND hWndClipWindow)
Noel Borthwick29700671999-09-03 15:17:57 +00002125{
Alexandre Julliard43230042001-05-16 19:52:29 +00002126 Display *display = thread_display();
Noel Borthwick29700671999-09-03 15:17:57 +00002127
2128 /*
2129 * Acquire X selection if we don't already own it.
2130 * Note that we only acquire the selection if it hasn't been already
2131 * acquired by us, and ignore the fact that another X window may be
2132 * asserting ownership. The reason for this is we need *any* top level
2133 * X window to hold selection ownership. The actual clipboard data requests
2134 * are made via GetClipboardData from EVENT_SelectionRequest and this
2135 * ensures that the real HWND owner services the request.
2136 * If the owning X window gets destroyed the selection ownership is
2137 * re-cycled to another top level X window in X11DRV_CLIPBOARD_ResetOwner.
2138 *
2139 */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002140 if (!(selectionAcquired == (S_PRIMARY | S_CLIPBOARD)))
Noel Borthwick29700671999-09-03 15:17:57 +00002141 {
Ulrich Czekalla18873e72003-07-08 21:02:51 +00002142 Window owner;
2143
2144 if (!hWndClipWindow)
2145 hWndClipWindow = GetActiveWindow();
2146
Ulrich Czekalla50679092005-03-07 19:31:46 +00002147 hWndClipWindow = GetAncestor(hWndClipWindow, GA_ROOT);
2148
2149 if (GetCurrentThreadId() != GetWindowThreadProcessId(hWndClipWindow, NULL))
2150 {
2151 TRACE("Thread %lx is acquiring selection with thread %lx's window %p\n",
2152 GetCurrentThreadId(),
2153 GetWindowThreadProcessId(hWndClipWindow, NULL),
2154 hWndClipWindow);
2155 if (!SendMessageW(hWndClipWindow, WM_X11DRV_ACQUIRE_SELECTION, 0, 0))
2156 ERR("Failed to acquire selection\n");
2157 return;
2158 }
2159
2160 owner = X11DRV_get_whole_window(hWndClipWindow);
Noel Borthwick29700671999-09-03 15:17:57 +00002161
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00002162 wine_tsx11_lock();
Noel Borthwick29700671999-09-03 15:17:57 +00002163 /* Grab PRIMARY selection if not owned */
Ulrich Czekalla6af0df42004-01-08 00:43:46 +00002164 if (usePrimary && !(selectionAcquired & S_PRIMARY))
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00002165 XSetSelectionOwner(display, XA_PRIMARY, owner, CurrentTime);
Vincent Béron9a624912002-05-31 23:06:46 +00002166
Noel Borthwick29700671999-09-03 15:17:57 +00002167 /* Grab CLIPBOARD selection if not owned */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002168 if (!(selectionAcquired & S_CLIPBOARD))
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00002169 XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), owner, CurrentTime);
Noel Borthwick29700671999-09-03 15:17:57 +00002170
Ulrich Czekalla6af0df42004-01-08 00:43:46 +00002171 if (usePrimary && XGetSelectionOwner(display,XA_PRIMARY) == owner)
Noel Borthwick29700671999-09-03 15:17:57 +00002172 selectionAcquired |= S_PRIMARY;
2173
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00002174 if (XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)) == owner)
Noel Borthwick29700671999-09-03 15:17:57 +00002175 selectionAcquired |= S_CLIPBOARD;
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00002176 wine_tsx11_unlock();
Noel Borthwick29700671999-09-03 15:17:57 +00002177
2178 if (selectionAcquired)
2179 {
2180 selectionWindow = owner;
2181 TRACE("Grabbed X selection, owner=(%08x)\n", (unsigned) owner);
2182 }
2183 }
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002184 else
2185 {
Ulrich Czekalla18fe91d2005-03-01 10:43:58 +00002186 ERR("Received request to acquire selection but process is already owner=(%08x)\n", (unsigned) selectionWindow);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002187 }
Noel Borthwick29700671999-09-03 15:17:57 +00002188}
2189
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002190
Noel Borthwick29700671999-09-03 15:17:57 +00002191/**************************************************************************
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002192 * X11DRV_EmptyClipboard
Ulrich Czekallab41466b2004-05-06 23:40:30 +00002193 *
2194 * Empty cached clipboard data.
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002195 */
Ulrich Czekallab41466b2004-05-06 23:40:30 +00002196void X11DRV_EmptyClipboard(BOOL keepunowned)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002197{
2198 if (ClipData)
2199 {
Ulrich Czekallab41466b2004-05-06 23:40:30 +00002200 LPWINE_CLIPDATA lpData, lpStart;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002201 LPWINE_CLIPDATA lpNext = ClipData;
2202
Ulrich Czekallab41466b2004-05-06 23:40:30 +00002203 TRACE(" called with %d entries in cache.\n", ClipDataCount);
2204
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002205 do
2206 {
Ulrich Czekallab41466b2004-05-06 23:40:30 +00002207 lpStart = ClipData;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002208 lpData = lpNext;
2209 lpNext = lpData->NextData;
Ulrich Czekallab41466b2004-05-06 23:40:30 +00002210
2211 if (!keepunowned || !(lpData->wFlags & CF_FLAG_UNOWNED))
2212 {
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002213 lpData->PrevData->NextData = lpData->NextData;
2214 lpData->NextData->PrevData = lpData->PrevData;
Ulrich Czekallab41466b2004-05-06 23:40:30 +00002215
2216 if (lpData == ClipData)
2217 ClipData = lpNext != lpData ? lpNext : NULL;
2218
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002219 X11DRV_CLIPBOARD_FreeData(lpData);
2220 HeapFree(GetProcessHeap(), 0, lpData);
Ulrich Czekallab41466b2004-05-06 23:40:30 +00002221
2222 ClipDataCount--;
2223 }
2224 } while (lpNext != lpStart);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002225 }
2226
Ulrich Czekallab41466b2004-05-06 23:40:30 +00002227 TRACE(" %d entries remaining in cache.\n", ClipDataCount);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002228}
2229
2230
2231
2232/**************************************************************************
2233 * X11DRV_SetClipboardData
2234 */
Ulrich Czekallab41466b2004-05-06 23:40:30 +00002235BOOL X11DRV_SetClipboardData(UINT wFormat, HANDLE16 hData16, HANDLE hData32, BOOL owner)
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002236{
Ulrich Czekallab41466b2004-05-06 23:40:30 +00002237 DWORD flags = 0;
2238 BOOL bResult = TRUE;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002239
Ulrich Czekallab41466b2004-05-06 23:40:30 +00002240 /* If it's not owned, data can only be set if the format data is not already owned
2241 and its rendering is not delayed */
2242 if (!owner)
2243{
2244 CLIPBOARDINFO cbinfo;
2245 LPWINE_CLIPDATA lpRender;
2246
2247 X11DRV_CLIPBOARD_UpdateCache(&cbinfo);
2248
2249 if ((!hData16 && !hData32) ||
2250 ((lpRender = X11DRV_CLIPBOARD_LookupData(wFormat)) &&
2251 !(lpRender->wFlags & CF_FLAG_UNOWNED)))
2252 bResult = FALSE;
2253 else
2254 flags = CF_FLAG_UNOWNED;
2255 }
2256
2257 bResult &= X11DRV_CLIPBOARD_InsertClipboardData(wFormat, hData16, hData32, flags);
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002258
2259 return bResult;
2260}
2261
2262
2263/**************************************************************************
2264 * CountClipboardFormats
2265 */
2266INT X11DRV_CountClipboardFormats(void)
2267{
2268 CLIPBOARDINFO cbinfo;
2269
2270 X11DRV_CLIPBOARD_UpdateCache(&cbinfo);
2271
2272 TRACE(" count=%d\n", ClipDataCount);
2273
2274 return ClipDataCount;
2275}
2276
2277
2278/**************************************************************************
2279 * X11DRV_EnumClipboardFormats
2280 */
2281UINT X11DRV_EnumClipboardFormats(UINT wFormat)
2282{
2283 CLIPBOARDINFO cbinfo;
2284 UINT wNextFormat = 0;
2285
2286 TRACE("(%04X)\n", wFormat);
2287
2288 X11DRV_CLIPBOARD_UpdateCache(&cbinfo);
2289
2290 if (!wFormat)
2291 {
2292 if (ClipData)
2293 wNextFormat = ClipData->wFormatID;
2294 }
2295 else
2296 {
2297 LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(wFormat);
2298
2299 if (lpData && lpData->NextData != ClipData)
2300 wNextFormat = lpData->NextData->wFormatID;
2301 }
2302
2303 return wNextFormat;
2304}
2305
2306
2307/**************************************************************************
2308 * X11DRV_IsClipboardFormatAvailable
Noel Borthwick29700671999-09-03 15:17:57 +00002309 */
Alexandre Julliard42d20f92000-08-10 01:16:19 +00002310BOOL X11DRV_IsClipboardFormatAvailable(UINT wFormat)
Noel Borthwick29700671999-09-03 15:17:57 +00002311{
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002312 BOOL bRet = FALSE;
2313 CLIPBOARDINFO cbinfo;
Noel Borthwick29700671999-09-03 15:17:57 +00002314
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002315 TRACE("(%04X)\n", wFormat);
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +00002316
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002317 X11DRV_CLIPBOARD_UpdateCache(&cbinfo);
Noel Borthwick29700671999-09-03 15:17:57 +00002318
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002319 if (wFormat != 0 && X11DRV_CLIPBOARD_LookupData(wFormat))
2320 bRet = TRUE;
Noel Borthwick29700671999-09-03 15:17:57 +00002321
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002322 TRACE("(%04X)- ret(%d)\n", wFormat, bRet);
Vincent Béron9a624912002-05-31 23:06:46 +00002323
Alex Korobka44a1b591999-04-01 12:03:52 +00002324 return bRet;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002325}
2326
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002327
2328/**************************************************************************
2329 * GetClipboardData (USER.142)
2330 */
2331BOOL X11DRV_GetClipboardData(UINT wFormat, HANDLE16* phData16, HANDLE* phData32)
2332{
2333 CLIPBOARDINFO cbinfo;
2334 LPWINE_CLIPDATA lpRender;
2335
2336 TRACE("(%04X)\n", wFormat);
2337
2338 X11DRV_CLIPBOARD_UpdateCache(&cbinfo);
2339
2340 if ((lpRender = X11DRV_CLIPBOARD_LookupData(wFormat)))
2341 {
2342 if ( !lpRender->hData32 )
2343 X11DRV_CLIPBOARD_RenderFormat(lpRender);
2344
2345 /* Convert between 32 -> 16 bit data, if necessary */
2346 if (lpRender->hData32 && !lpRender->hData16)
2347 {
2348 int size;
2349
2350 if (lpRender->wFormatID == CF_METAFILEPICT)
2351 size = sizeof(METAFILEPICT16);
2352 else
2353 size = GlobalSize(lpRender->hData32);
2354
2355 lpRender->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);
2356
2357 if (!lpRender->hData16)
2358 ERR("(%04X) -- not enough memory in 16b heap\n", wFormat);
2359 else
2360 {
2361 if (lpRender->wFormatID == CF_METAFILEPICT)
2362 {
2363 FIXME("\timplement function CopyMetaFilePict32to16\n");
2364 FIXME("\tin the appropriate file.\n");
Alexandre Julliardd0ee9f92005-03-02 12:23:20 +00002365#ifdef SOMEONE_IMPLEMENTED_ME
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002366 CopyMetaFilePict32to16(GlobalLock16(lpRender->hData16),
2367 GlobalLock(lpRender->hData32));
Alexandre Julliardd0ee9f92005-03-02 12:23:20 +00002368#endif
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002369 }
2370 else
2371 {
2372 memcpy(GlobalLock16(lpRender->hData16),
2373 GlobalLock(lpRender->hData32), size);
2374 }
2375
2376 GlobalUnlock16(lpRender->hData16);
2377 GlobalUnlock(lpRender->hData32);
2378 }
2379 }
2380
2381 /* Convert between 32 -> 16 bit data, if necessary */
2382 if (lpRender->hData16 && !lpRender->hData32)
2383 {
2384 int size;
2385
2386 if (lpRender->wFormatID == CF_METAFILEPICT)
2387 size = sizeof(METAFILEPICT16);
2388 else
2389 size = GlobalSize(lpRender->hData32);
2390
2391 lpRender->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE |
2392 GMEM_DDESHARE, size);
2393
2394 if (lpRender->wFormatID == CF_METAFILEPICT)
2395 {
2396 FIXME("\timplement function CopyMetaFilePict16to32\n");
2397 FIXME("\tin the appropriate file.\n");
2398#ifdef SOMEONE_IMPLEMENTED_ME
2399 CopyMetaFilePict16to32(GlobalLock16(lpRender->hData32),
2400 GlobalLock(lpRender->hData16));
2401#endif
2402 }
2403 else
2404 {
2405 memcpy(GlobalLock(lpRender->hData32),
2406 GlobalLock16(lpRender->hData16), size);
2407 }
2408
2409 GlobalUnlock(lpRender->hData32);
2410 GlobalUnlock16(lpRender->hData16);
2411 }
2412
2413 if (phData16)
2414 *phData16 = lpRender->hData16;
2415
2416 if (phData32)
2417 *phData32 = lpRender->hData32;
2418
2419 TRACE(" returning hData16(%04x) hData32(%04x) (type %d)\n",
2420 lpRender->hData16, (unsigned int) lpRender->hData32, lpRender->wFormatID);
2421
2422 return lpRender->hData16 || lpRender->hData32;
2423 }
2424
2425 return 0;
2426}
2427
2428
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002429/**************************************************************************
Patrik Stridvalldf75e892001-02-12 03:49:07 +00002430 * ResetSelectionOwner (X11DRV.@)
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002431 *
Noel Borthwick29700671999-09-03 15:17:57 +00002432 * Called from DestroyWindow() to prevent X selection from being lost when
2433 * a top level window is destroyed, by switching ownership to another top
2434 * level window.
2435 * Any top level window can own the selection. See X11DRV_CLIPBOARD_Acquire
2436 * for a more detailed description of this.
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002437 */
Alexandre Julliard4ff32c82001-08-18 18:08:26 +00002438void X11DRV_ResetSelectionOwner(HWND hwnd, BOOL bFooBar)
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002439{
Alexandre Julliard43230042001-05-16 19:52:29 +00002440 Display *display = thread_display();
Noel Borthwick29700671999-09-03 15:17:57 +00002441 HWND hWndClipOwner = 0;
Alexandre Julliard4ff32c82001-08-18 18:08:26 +00002442 HWND tmp;
2443 Window XWnd = X11DRV_get_whole_window(hwnd);
Noel Borthwick29700671999-09-03 15:17:57 +00002444 BOOL bLostSelection = FALSE;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002445 Window selectionPrevWindow;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002446
Noel Borthwick29700671999-09-03 15:17:57 +00002447 /* There is nothing to do if we don't own the selection,
Ulrich Czekalla18873e72003-07-08 21:02:51 +00002448 * or if the X window which currently owns the selection is different
Noel Borthwick29700671999-09-03 15:17:57 +00002449 * from the one passed in.
2450 */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002451 if (!selectionAcquired || XWnd != selectionWindow
Noel Borthwick29700671999-09-03 15:17:57 +00002452 || selectionWindow == None )
2453 return;
Patrik Stridvall151170c1998-12-26 12:00:43 +00002454
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002455 if ((bFooBar && XWnd) || (!bFooBar && !XWnd))
Noel Borthwick29700671999-09-03 15:17:57 +00002456 return;
Patrik Stridvall151170c1998-12-26 12:00:43 +00002457
Noel Borthwick29700671999-09-03 15:17:57 +00002458 hWndClipOwner = GetClipboardOwner();
Vincent Béron9a624912002-05-31 23:06:46 +00002459
Alexandre Julliarde0315e42002-10-31 02:38:20 +00002460 TRACE("clipboard owner = %p, selection window = %08x\n",
Noel Borthwick29700671999-09-03 15:17:57 +00002461 hWndClipOwner, (unsigned)selectionWindow);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002462
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002463 /* now try to salvage current selection from being destroyed by X */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002464 TRACE("checking %08x\n", (unsigned) XWnd);
Noel Borthwick29700671999-09-03 15:17:57 +00002465
2466 selectionPrevWindow = selectionWindow;
2467 selectionWindow = None;
2468
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002469 if (!(tmp = GetWindow(hwnd, GW_HWNDNEXT)))
2470 tmp = GetWindow(hwnd, GW_HWNDFIRST);
Noel Borthwick29700671999-09-03 15:17:57 +00002471
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002472 if (tmp && tmp != hwnd)
2473 selectionWindow = X11DRV_get_whole_window(tmp);
2474
2475 if (selectionWindow != None)
Noel Borthwick29700671999-09-03 15:17:57 +00002476 {
2477 /* We must pretend that we don't own the selection while making the switch
2478 * since a SelectionClear event will be sent to the last owner.
2479 * If there is no owner X11DRV_CLIPBOARD_ReleaseSelection will do nothing.
2480 */
2481 int saveSelectionState = selectionAcquired;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002482 selectionAcquired = S_NOSELECTION;
Noel Borthwick29700671999-09-03 15:17:57 +00002483
Vincent Béron9a624912002-05-31 23:06:46 +00002484 TRACE("\tswitching selection from %08x to %08x\n",
Noel Borthwick29700671999-09-03 15:17:57 +00002485 (unsigned)selectionPrevWindow, (unsigned)selectionWindow);
Vincent Béron9a624912002-05-31 23:06:46 +00002486
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00002487 wine_tsx11_lock();
2488
Noel Borthwick29700671999-09-03 15:17:57 +00002489 /* Assume ownership for the PRIMARY and CLIPBOARD selection */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002490 if (saveSelectionState & S_PRIMARY)
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00002491 XSetSelectionOwner(display, XA_PRIMARY, selectionWindow, CurrentTime);
Vincent Béron9a624912002-05-31 23:06:46 +00002492
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00002493 XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), selectionWindow, CurrentTime);
Francis Beaudet56ab55d1999-10-24 20:22:24 +00002494
2495 /* Restore the selection masks */
2496 selectionAcquired = saveSelectionState;
2497
Noel Borthwick29700671999-09-03 15:17:57 +00002498 /* Lose the selection if something went wrong */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002499 if (((saveSelectionState & S_PRIMARY) &&
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00002500 (XGetSelectionOwner(display, XA_PRIMARY) != selectionWindow)) ||
2501 (XGetSelectionOwner(display, x11drv_atom(CLIPBOARD)) != selectionWindow))
Noel Borthwick29700671999-09-03 15:17:57 +00002502 {
2503 bLostSelection = TRUE;
Noel Borthwick29700671999-09-03 15:17:57 +00002504 }
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +00002505 wine_tsx11_unlock();
Noel Borthwick29700671999-09-03 15:17:57 +00002506 }
2507 else
2508 {
2509 bLostSelection = TRUE;
Noel Borthwick29700671999-09-03 15:17:57 +00002510 }
2511
Noel Borthwick29700671999-09-03 15:17:57 +00002512 if (bLostSelection)
2513 {
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002514 TRACE("Lost the selection!\n");
Vincent Béron9a624912002-05-31 23:06:46 +00002515
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002516 X11DRV_CLIPBOARD_ReleaseOwnership();
2517 selectionAcquired = S_NOSELECTION;
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002518 selectionWindow = 0;
Noel Borthwick29700671999-09-03 15:17:57 +00002519 }
Patrik Stridvalle35d6361998-12-07 09:13:40 +00002520}
2521
Ulrich Czekalla651c5982002-08-27 19:19:49 +00002522
2523/**************************************************************************
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002524 * X11DRV_CLIPBOARD_SynthesizeData
Ulrich Czekalla651c5982002-08-27 19:19:49 +00002525 */
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002526static BOOL X11DRV_CLIPBOARD_SynthesizeData(UINT wFormatID)
Ulrich Czekalla651c5982002-08-27 19:19:49 +00002527{
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002528 BOOL bsyn = TRUE;
2529 LPWINE_CLIPDATA lpSource = NULL;
Ulrich Czekalla651c5982002-08-27 19:19:49 +00002530
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002531 TRACE(" %d\n", wFormatID);
2532
2533 /* Don't need to synthesize if it already exists */
2534 if (X11DRV_CLIPBOARD_LookupData(wFormatID))
2535 return TRUE;
2536
2537 if (wFormatID == CF_UNICODETEXT || wFormatID == CF_TEXT || wFormatID == CF_OEMTEXT)
Ulrich Czekalla651c5982002-08-27 19:19:49 +00002538 {
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002539 bsyn = ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_UNICODETEXT)) &&
2540 ~lpSource->wFlags & CF_FLAG_SYNTHESIZED) ||
2541 ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_TEXT)) &&
2542 ~lpSource->wFlags & CF_FLAG_SYNTHESIZED) ||
2543 ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_OEMTEXT)) &&
2544 ~lpSource->wFlags & CF_FLAG_SYNTHESIZED);
Ulrich Czekalla651c5982002-08-27 19:19:49 +00002545 }
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002546 else if (wFormatID == CF_ENHMETAFILE)
Ulrich Czekalla651c5982002-08-27 19:19:49 +00002547 {
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002548 bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_METAFILEPICT)) &&
2549 ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
2550 }
2551 else if (wFormatID == CF_METAFILEPICT)
2552 {
2553 bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_METAFILEPICT)) &&
2554 ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
2555 }
2556 else if (wFormatID == CF_DIB)
2557 {
2558 bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) &&
2559 ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
2560 }
2561 else if (wFormatID == CF_BITMAP)
2562 {
2563 bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) &&
2564 ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
Ulrich Czekalla651c5982002-08-27 19:19:49 +00002565 }
2566
Ulrich Czekallab2df5f92003-06-23 23:02:02 +00002567 if (bsyn)
2568 X11DRV_CLIPBOARD_InsertClipboardData(wFormatID, 0, 0, CF_FLAG_SYNTHESIZED);
2569
2570 return bsyn;
2571}
2572
2573
2574
2575/**************************************************************************
2576 * X11DRV_EndClipboardUpdate
2577 * TODO:
2578 * Add locale if it hasn't already been added
2579 */
2580void X11DRV_EndClipboardUpdate(void)
2581{
2582 INT count = ClipDataCount;
2583
2584 /* Do Unicode <-> Text <-> OEM mapping */
2585 X11DRV_CLIPBOARD_SynthesizeData(CF_UNICODETEXT);
2586 X11DRV_CLIPBOARD_SynthesizeData(CF_TEXT);
2587 X11DRV_CLIPBOARD_SynthesizeData(CF_OEMTEXT);
2588
2589 /* Enhmetafile <-> MetafilePict mapping */
2590 X11DRV_CLIPBOARD_SynthesizeData(CF_ENHMETAFILE);
2591 X11DRV_CLIPBOARD_SynthesizeData(CF_METAFILEPICT);
2592
2593 /* DIB <-> Bitmap mapping */
2594 X11DRV_CLIPBOARD_SynthesizeData(CF_DIB);
2595 X11DRV_CLIPBOARD_SynthesizeData(CF_BITMAP);
2596
2597 TRACE("%d formats added to cached data\n", ClipDataCount - count);
Ulrich Czekalla651c5982002-08-27 19:19:49 +00002598}
Alexandre Julliard0778a452005-02-25 21:01:15 +00002599
2600
2601/***********************************************************************
2602 * add_targets
2603 *
2604 * Utility function for X11DRV_SelectionRequest_TARGETS.
2605 */
2606static BOOL add_targets(Atom* targets, unsigned long cTargets, Atom prop)
2607{
2608 unsigned int i;
2609 BOOL bExists;
2610
2611 /* Scan through what we have so far to avoid duplicates */
2612 for (i = 0, bExists = FALSE; i < cTargets; i++)
2613 {
2614 if (targets[i] == prop)
2615 {
2616 bExists = TRUE;
2617 break;
2618 }
2619 }
2620
2621 if (!bExists)
2622 targets[cTargets] = prop;
2623
2624 return !bExists;
2625}
2626
2627
2628/***********************************************************************
2629 * X11DRV_SelectionRequest_TARGETS
2630 * Service a TARGETS selection request event
2631 */
2632static Atom X11DRV_SelectionRequest_TARGETS( Display *display, Window requestor,
2633 Atom target, Atom rprop )
2634{
2635 Atom* targets;
2636 UINT wFormat;
2637 UINT alias;
2638 ULONG cTargets;
2639 LPWINE_CLIPFORMAT lpFormat;
2640
2641 /*
2642 * Count the number of items we wish to expose as selection targets.
2643 * We include the TARGETS item, and property aliases
2644 */
2645 cTargets = X11DRV_CountClipboardFormats() + 1;
2646
2647 for (wFormat = 0; (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
2648 {
2649 lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
2650
2651 if (lpFormat)
2652 {
2653 if (!lpFormat->lpDrvExportFunc)
2654 cTargets--;
2655
2656 if (X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData))
2657 cTargets++;
2658 }
2659 /* else most likely unregistered format such as CF_PRIVATE or CF_GDIOBJ */
2660 }
2661
2662 TRACE(" found %ld formats\n", cTargets);
2663
2664 /* Allocate temp buffer */
Jakob Eriksson9ed61de2005-03-24 21:01:35 +00002665 targets = HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
Alexandre Julliard0778a452005-02-25 21:01:15 +00002666 if(targets == NULL)
2667 return None;
2668
2669 /* Create TARGETS property list (First item in list is TARGETS itself) */
2670 for (targets[0] = x11drv_atom(TARGETS), cTargets = 1, wFormat = 0;
2671 (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
2672 {
2673 lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
2674
2675 if (lpFormat)
2676 {
2677 if (lpFormat->lpDrvExportFunc)
2678 {
2679 if (add_targets(targets, cTargets, lpFormat->drvData))
2680 cTargets++;
2681 }
2682
2683 /* Check if any alias should be listed */
2684 alias = X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData);
2685 if (alias)
2686 {
2687 if (add_targets(targets, cTargets, alias))
2688 cTargets++;
2689 }
2690 }
2691 }
2692
2693 wine_tsx11_lock();
2694
2695 if (TRACE_ON(clipboard))
2696 {
2697 unsigned int i;
2698 for ( i = 0; i < cTargets; i++)
2699 {
2700 if (targets[i])
2701 {
2702 char *itemFmtName = XGetAtomName(display, targets[i]);
2703 TRACE("\tAtom# %d: Property %ld Type %s\n", i, targets[i], itemFmtName);
2704 XFree(itemFmtName);
2705 }
2706 }
2707 }
2708
2709 /* We may want to consider setting the type to xaTargets instead,
2710 * in case some apps expect this instead of XA_ATOM */
2711 XChangeProperty(display, requestor, rprop, XA_ATOM, 32,
2712 PropModeReplace, (unsigned char *)targets, cTargets);
2713 wine_tsx11_unlock();
2714
2715 HeapFree(GetProcessHeap(), 0, targets);
2716
2717 return rprop;
2718}
2719
2720
2721/***********************************************************************
2722 * X11DRV_SelectionRequest_MULTIPLE
2723 * Service a MULTIPLE selection request event
2724 * rprop contains a list of (target,property) atom pairs.
2725 * The first atom names a target and the second names a property.
2726 * The effect is as if we have received a sequence of SelectionRequest events
2727 * (one for each atom pair) except that:
2728 * 1. We reply with a SelectionNotify only when all the requested conversions
2729 * have been performed.
2730 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
2731 * we replace the atom in the property by None.
2732 */
2733static Atom X11DRV_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
2734{
2735 Display *display = pevent->display;
2736 Atom rprop;
2737 Atom atype=AnyPropertyType;
2738 int aformat;
2739 unsigned long remain;
2740 Atom* targetPropList=NULL;
2741 unsigned long cTargetPropList = 0;
2742
2743 /* If the specified property is None the requestor is an obsolete client.
2744 * We support these by using the specified target atom as the reply property.
2745 */
2746 rprop = pevent->property;
2747 if( rprop == None )
2748 rprop = pevent->target;
2749 if (!rprop)
2750 return 0;
2751
2752 /* Read the MULTIPLE property contents. This should contain a list of
2753 * (target,property) atom pairs.
2754 */
2755 wine_tsx11_lock();
2756 if(XGetWindowProperty(display, pevent->requestor, rprop,
2757 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
2758 &cTargetPropList, &remain,
2759 (unsigned char**)&targetPropList) != Success)
2760 {
2761 wine_tsx11_unlock();
2762 TRACE("\tCouldn't read MULTIPLE property\n");
2763 }
2764 else
2765 {
2766 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
2767 XGetAtomName(display, atype), aformat, cTargetPropList, remain);
2768 wine_tsx11_unlock();
2769
2770 /*
2771 * Make sure we got what we expect.
2772 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
2773 * in a MULTIPLE selection request should be of type ATOM_PAIR.
2774 * However some X apps(such as XPaint) are not compliant with this and return
2775 * a user defined atom in atype when XGetWindowProperty is called.
2776 * The data *is* an atom pair but is not denoted as such.
2777 */
2778 if(aformat == 32 /* atype == xAtomPair */ )
2779 {
2780 unsigned int i;
2781
2782 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
2783 * for each (target,property) pair */
2784
2785 for (i = 0; i < cTargetPropList; i+=2)
2786 {
2787 XSelectionRequestEvent event;
2788
2789 if (TRACE_ON(clipboard))
2790 {
2791 char *targetName, *propName;
2792 wine_tsx11_lock();
2793 targetName = XGetAtomName(display, targetPropList[i]);
2794 propName = XGetAtomName(display, targetPropList[i+1]);
2795 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
2796 i/2, targetName, propName);
2797 XFree(targetName);
2798 XFree(propName);
2799 wine_tsx11_unlock();
2800 }
2801
2802 /* We must have a non "None" property to service a MULTIPLE target atom */
2803 if ( !targetPropList[i+1] )
2804 {
2805 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
2806 continue;
2807 }
2808
2809 /* Set up an XSelectionRequestEvent for this (target,property) pair */
2810 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
2811 event.target = targetPropList[i];
2812 event.property = targetPropList[i+1];
2813
2814 /* Fire a SelectionRequest, informing the handler that we are processing
2815 * a MULTIPLE selection request event.
2816 */
2817 X11DRV_HandleSelectionRequest( hWnd, &event, TRUE );
2818 }
2819 }
2820
2821 /* Free the list of targets/properties */
2822 wine_tsx11_lock();
2823 XFree(targetPropList);
2824 wine_tsx11_unlock();
2825 }
2826
2827 return rprop;
2828}
2829
2830
2831/***********************************************************************
2832 * X11DRV_HandleSelectionRequest
2833 * Process an event selection request event.
2834 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
2835 * recursively while servicing a "MULTIPLE" selection target.
2836 *
2837 * Note: We only receive this event when WINE owns the X selection
2838 */
2839static void X11DRV_HandleSelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
2840{
2841 Display *display = event->display;
2842 XSelectionEvent result;
2843 Atom rprop = None;
2844 Window request = event->requestor;
2845
2846 TRACE("\n");
2847
2848 /*
2849 * We can only handle the selection request if :
2850 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
2851 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
2852 * since this has been already done.
2853 */
2854 if ( !bIsMultiple )
2855 {
2856 if (((event->selection != XA_PRIMARY) && (event->selection != x11drv_atom(CLIPBOARD))))
2857 goto END;
2858 }
2859
2860 /* If the specified property is None the requestor is an obsolete client.
2861 * We support these by using the specified target atom as the reply property.
2862 */
2863 rprop = event->property;
2864 if( rprop == None )
2865 rprop = event->target;
2866
2867 if(event->target == x11drv_atom(TARGETS)) /* Return a list of all supported targets */
2868 {
2869 /* TARGETS selection request */
2870 rprop = X11DRV_SelectionRequest_TARGETS( display, request, event->target, rprop );
2871 }
2872 else if(event->target == x11drv_atom(MULTIPLE)) /* rprop contains a list of (target, property) atom pairs */
2873 {
2874 /* MULTIPLE selection request */
2875 rprop = X11DRV_SelectionRequest_MULTIPLE( hWnd, event );
2876 }
2877 else
2878 {
2879 LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(event->target);
2880
2881 if (!lpFormat)
2882 lpFormat = X11DRV_CLIPBOARD_LookupAliasProperty(event->target);
2883
2884 if (lpFormat && lpFormat->lpDrvExportFunc)
2885 {
2886 LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(lpFormat->wFormatID);
2887
2888 if (lpData)
2889 {
2890 unsigned char* lpClipData;
2891 DWORD cBytes;
2892 HANDLE hClipData = lpFormat->lpDrvExportFunc(request, event->target,
2893 rprop, lpData, &cBytes);
2894
2895 if (hClipData && (lpClipData = GlobalLock(hClipData)))
2896 {
2897 TRACE("\tUpdating property %s, %ld bytes\n", debugstr_w(lpFormat->Name), cBytes);
2898
2899 wine_tsx11_lock();
2900 XChangeProperty(display, request, rprop, event->target,
2901 8, PropModeReplace, (unsigned char *)lpClipData, cBytes);
2902 wine_tsx11_unlock();
2903
2904 GlobalUnlock(hClipData);
2905 GlobalFree(hClipData);
2906 }
2907 }
2908 }
2909 }
2910
2911END:
2912 /* reply to sender
2913 * SelectionNotify should be sent only at the end of a MULTIPLE request
2914 */
2915 if ( !bIsMultiple )
2916 {
2917 result.type = SelectionNotify;
2918 result.display = display;
2919 result.requestor = request;
2920 result.selection = event->selection;
2921 result.property = rprop;
2922 result.target = event->target;
2923 result.time = event->time;
2924 TRACE("Sending SelectionNotify event...\n");
2925 wine_tsx11_lock();
2926 XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
2927 wine_tsx11_unlock();
2928 }
2929}
2930
2931
2932/***********************************************************************
2933 * X11DRV_SelectionRequest
2934 */
Alexandre Julliard94846a32005-02-26 17:49:38 +00002935void X11DRV_SelectionRequest( HWND hWnd, XEvent *event )
Alexandre Julliard0778a452005-02-25 21:01:15 +00002936{
2937 if (!hWnd) return;
Alexandre Julliard94846a32005-02-26 17:49:38 +00002938 X11DRV_HandleSelectionRequest( hWnd, &event->xselectionrequest, FALSE );
Alexandre Julliard0778a452005-02-25 21:01:15 +00002939}
2940
2941
2942/***********************************************************************
2943 * X11DRV_SelectionClear
2944 */
Alexandre Julliard94846a32005-02-26 17:49:38 +00002945void X11DRV_SelectionClear( HWND hWnd, XEvent *xev )
Alexandre Julliard0778a452005-02-25 21:01:15 +00002946{
Alexandre Julliard94846a32005-02-26 17:49:38 +00002947 XSelectionClearEvent *event = &xev->xselectionclear;
Alexandre Julliard0778a452005-02-25 21:01:15 +00002948 if (!hWnd) return;
2949 if (event->selection == XA_PRIMARY || event->selection == x11drv_atom(CLIPBOARD))
2950 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd, event->time );
2951}