Release 950522
[wine.git] / misc / clipboard.c
blobe11c4a8128a9f7c45099b5ca29fd6f69e9a569c3
1 /*
2 * 'Wine' Clipboard function handling
4 * Copyright 1994 Martin Ayotte
5 static char Copyright[] = "Copyright Martin Ayotte, 1994";
6 */
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <windows.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include <X11/Xlib.h>
16 #include <X11/Xatom.h>
17 #include "win.h"
18 #include "message.h"
19 #include "clipboard.h"
20 #include "stddebug.h"
21 #include "debug.h"
23 typedef struct tagCLIPFORMAT {
24 WORD wFormatID;
25 WORD wRefCount;
26 LPSTR Name;
27 HANDLE hData;
28 DWORD BufSize;
29 void *PrevFormat;
30 void *NextFormat;
31 } CLIPFORMAT;
32 typedef CLIPFORMAT FAR* LPCLIPFORMAT;
34 static HWND hWndClipboardOwner = 0;
35 static HWND hWndViewer = 0;
36 static WORD LastRegFormat = 0xC000;
37 static Bool wait_for_selection = False;
38 static Bool wineOwnsSelection = False;
40 CLIPFORMAT ClipFormats[12] = {
41 { CF_TEXT, 1, "Text", (HANDLE)NULL, 0, NULL, &ClipFormats[1] },
42 { CF_BITMAP, 1, "Bitmap", (HANDLE)NULL, 0, &ClipFormats[0], &ClipFormats[2] },
43 { CF_METAFILEPICT, 1, "MetaFile Picture", (HANDLE)NULL, 0, &ClipFormats[1], &ClipFormats[3] },
44 { CF_SYLK, 1, "Sylk", (HANDLE)NULL, 0, &ClipFormats[2], &ClipFormats[4] },
45 { CF_DIF, 1, "DIF", (HANDLE)NULL, 0, &ClipFormats[3], &ClipFormats[5] },
46 { CF_TIFF, 1, "TIFF", (HANDLE)NULL, 0, &ClipFormats[4], &ClipFormats[6] },
47 { CF_OEMTEXT, 1, "OEM Text", (HANDLE)NULL, 0, &ClipFormats[5], &ClipFormats[7] },
48 { CF_DIB, 1, "DIB", (HANDLE)NULL, 0, &ClipFormats[6], &ClipFormats[8] },
49 { CF_PALETTE, 1, "Palette", (HANDLE)NULL, 0, &ClipFormats[7], &ClipFormats[9] },
50 { CF_PENDATA, 1, "PenData", (HANDLE)NULL, 0, &ClipFormats[8], &ClipFormats[10] },
51 { CF_RIFF, 1, "RIFF", (HANDLE)NULL, 0, &ClipFormats[9], &ClipFormats[11] },
52 { CF_WAVE, 1, "Wave", (HANDLE)NULL, 0, &ClipFormats[10], NULL }
55 /**************************************************************************
56 * OpenClipboard [USER.137]
58 BOOL OpenClipboard(HWND hWnd)
60 if (hWndClipboardOwner != 0) return FALSE;
61 hWndClipboardOwner = hWnd;
62 dprintf_clipboard(stddeb,"OpenClipboard(%04X); !\n", hWnd);
63 return TRUE;
67 /**************************************************************************
68 * CloseClipboard [USER.138]
70 BOOL CloseClipboard()
72 if (hWndClipboardOwner == 0) return FALSE;
73 hWndClipboardOwner = 0;
74 dprintf_clipboard(stddeb,"CloseClipboard(); !\n");
75 return TRUE;
79 /**************************************************************************
80 * EmptyClipboard [USER.139]
82 BOOL EmptyClipboard()
84 LPCLIPFORMAT lpFormat = ClipFormats;
85 if (hWndClipboardOwner == 0) return FALSE;
86 dprintf_clipboard(stddeb,"EmptyClipboard(); !\n");
87 while(TRUE) {
88 if (lpFormat == NULL) break;
89 if (lpFormat->hData != 0) {
90 GlobalFree(lpFormat->hData);
91 lpFormat->hData = 0;
93 lpFormat = lpFormat->NextFormat;
95 if(wineOwnsSelection){
96 dprintf_clipboard(stddeb,"Losing selection\n");
97 wineOwnsSelection=False;
98 XSetSelectionOwner(display,XA_PRIMARY,None,CurrentTime);
100 return TRUE;
104 /**************************************************************************
105 * GetClipboardOwner [USER.140]
107 HWND GetClipboardOwner()
109 dprintf_clipboard(stddeb,
110 "GetClipboardOwner() = %04X !\n", hWndClipboardOwner);
111 return hWndClipboardOwner;
115 /**************************************************************************
116 * SetClipboardData [USER.141]
118 HANDLE SetClipboardData(WORD wFormat, HANDLE hData)
120 LPCLIPFORMAT lpFormat = ClipFormats;
121 dprintf_clipboard(stddeb,
122 "SetClipboardDate(%04X, %04X) !\n", wFormat, hData);
123 while(TRUE) {
124 if (lpFormat == NULL) return 0;
125 if (lpFormat->wFormatID == wFormat) break;
126 lpFormat = lpFormat->NextFormat;
128 /* doc says we shouldn't use CurrentTime */
129 /* should we become owner of CLIPBOARD as well? */
130 XSetSelectionOwner(display,XA_PRIMARY,WIN_GetXWindow(hWndClipboardOwner),CurrentTime);
131 wineOwnsSelection = True;
132 dprintf_clipboard(stddeb,"Getting selection\n");
133 if (lpFormat->hData != 0) GlobalFree(lpFormat->hData);
134 lpFormat->hData = hData;
135 return lpFormat->hData;
139 /**************************************************************************
140 * GetClipboardData [USER.142]
142 HANDLE GetClipboardData(WORD wFormat)
144 LPCLIPFORMAT lpFormat = ClipFormats;
145 dprintf_clipboard(stddeb,"GetClipboardData(%04X) !\n", wFormat);
146 if(wFormat == CF_TEXT && !wineOwnsSelection)
147 { wait_for_selection=True;
148 dprintf_clipboard(stddeb,"Requesting selection\n");
149 XConvertSelection(display,XA_PRIMARY,XA_STRING,
150 XInternAtom(display,"PRIMARY_TEXT",False),
151 WIN_GetXWindow(hWndClipboardOwner),CurrentTime);
152 /* TODO: need time-out for broken clients */
153 while(wait_for_selection)MSG_WaitXEvent(-1);
155 while(TRUE) {
156 if (lpFormat == NULL) return 0;
157 if (lpFormat->wFormatID == wFormat) break;
158 lpFormat = lpFormat->NextFormat;
160 return lpFormat->hData;
164 /**************************************************************************
165 * CountClipboardFormats [USER.143]
167 int CountClipboardFormats()
169 int FormatCount = 0;
170 LPCLIPFORMAT lpFormat = ClipFormats;
171 while(TRUE) {
172 if (lpFormat == NULL) break;
173 if (lpFormat->hData != 0) {
174 dprintf_clipboard(stddeb,
175 "CountClipboardFormats // Find Not Empty (%04X) !\n",
176 lpFormat->hData);
177 FormatCount++;
179 lpFormat = lpFormat->NextFormat;
181 dprintf_clipboard(stddeb,"CountClipboardFormats() = %d !\n", FormatCount);
182 return FormatCount;
186 /**************************************************************************
187 * EnumClipboardFormats [USER.144]
189 WORD EnumClipboardFormats(WORD wFormat)
191 LPCLIPFORMAT lpFormat = ClipFormats;
192 dprintf_clipboard(stddeb,"EnumClipboardFormats(%04X) !\n", wFormat);
193 if (wFormat == 0) {
194 if (lpFormat->hData != 0)
195 return lpFormat->wFormatID;
196 else
197 wFormat = lpFormat->wFormatID;
199 while(TRUE) {
200 if (lpFormat == NULL) return 0;
201 if (lpFormat->wFormatID == wFormat) break;
202 lpFormat = lpFormat->NextFormat;
204 dprintf_clipboard(stddeb,"EnumClipboardFormats // Find Last (%04X) !\n",
205 lpFormat->wFormatID);
206 lpFormat = lpFormat->NextFormat;
207 while(TRUE) {
208 if (lpFormat == NULL) return 0;
209 if (lpFormat->hData != 0) break;
210 lpFormat = lpFormat->NextFormat;
212 dprintf_clipboard(stddeb,
213 "EnumClipboardFormats // Find Not Empty Id=%04X hData=%04X !\n",
214 lpFormat->wFormatID, lpFormat->hData);
215 return lpFormat->wFormatID;
219 /**************************************************************************
220 * RegisterClipboardFormat [USER.145]
222 WORD RegisterClipboardFormat(LPCSTR FormatName)
224 LPCLIPFORMAT lpNewFormat;
225 LPCLIPFORMAT lpFormat = ClipFormats;
226 if (FormatName == NULL) return 0;
227 while(TRUE) {
228 if (lpFormat->NextFormat == NULL) break;
229 lpFormat = lpFormat->NextFormat;
231 lpNewFormat = (LPCLIPFORMAT)malloc(sizeof(CLIPFORMAT));
232 if (lpNewFormat == NULL) return 0;
233 lpFormat->NextFormat = lpNewFormat;
234 dprintf_clipboard(stddeb,"RegisterClipboardFormat('%s') !\n", FormatName);
235 lpNewFormat->wFormatID = LastRegFormat;
236 lpNewFormat->wRefCount = 1;
237 lpNewFormat->Name = (LPSTR)malloc(strlen(FormatName) + 1);
238 if (lpNewFormat->Name == NULL) {
239 free(lpNewFormat);
240 return 0;
242 strcpy(lpNewFormat->Name, FormatName);
243 lpNewFormat->hData = 0;
244 lpNewFormat->BufSize = 0;
245 lpNewFormat->PrevFormat = lpFormat;
246 lpNewFormat->NextFormat = NULL;
247 return LastRegFormat++;
251 /**************************************************************************
252 * GetClipboardFormatName [USER.146]
254 int GetClipboardFormatName(WORD wFormat, LPSTR retStr, short maxlen)
256 LPCLIPFORMAT lpFormat = ClipFormats;
257 dprintf_clipboard(stddeb,
258 "GetClipboardFormat(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
259 while(TRUE) {
260 if (lpFormat == NULL) return 0;
261 if (lpFormat->wFormatID == wFormat) break;
262 lpFormat = lpFormat->NextFormat;
264 if (lpFormat->Name == NULL) return 0;
265 dprintf_clipboard(stddeb,
266 "GetClipboardFormat // Name='%s' !\n", lpFormat->Name);
267 maxlen = min(maxlen - 1, strlen(lpFormat->Name));
268 dprintf_clipboard(stddeb,"GetClipboardFormat // maxlen=%d !\n", maxlen);
269 memcpy(retStr, lpFormat->Name, maxlen);
270 retStr[maxlen] = 0;
271 return maxlen;
275 /**************************************************************************
276 * SetClipboardViewer [USER.147]
278 HWND SetClipboardViewer(HWND hWnd)
280 HWND hwndPrev = hWndViewer;
281 dprintf_clipboard(stddeb,"SetClipboardViewer(%04X) !\n", hWnd);
282 hWndViewer = hWnd;
283 return hwndPrev;
287 /**************************************************************************
288 * GetClipboardViewer [USER.148]
290 HWND GetClipboardViewer()
292 dprintf_clipboard(stddeb,"GetClipboardFormat() = %04X !\n", hWndViewer);
293 return hWndViewer;
297 /**************************************************************************
298 * ChangeClipboardChain [USER.149]
300 BOOL ChangeClipboardChain(HWND hWnd, HWND hWndNext)
302 dprintf_clipboard(stdnimp,
303 "ChangeClipboardChain(%04X, %04X) !\n", hWnd, hWndNext);
305 return 0;
309 /**************************************************************************
310 * IsClipboardFormatAvailable [USER.193]
312 BOOL IsClipboardFormatAvailable(WORD wFormat)
314 LPCLIPFORMAT lpFormat = ClipFormats;
315 dprintf_clipboard(stddeb,"IsClipboardFormatAvailable(%04X) !\n", wFormat);
316 if(wFormat == CF_TEXT && !wineOwnsSelection) /* obtain selection as text if possible */
317 return GetClipboardData(CF_TEXT)!=0;
318 while(TRUE) {
319 if (lpFormat == NULL) return FALSE;
320 if (lpFormat->wFormatID == wFormat) break;
321 lpFormat = lpFormat->NextFormat;
323 return (lpFormat->hData != 0);
327 /**************************************************************************
328 * GetOpenClipboardWindow [USER.248]
330 HWND GetOpenClipboardWindow()
332 dprintf_clipboard(stddeb,
333 "GetOpenClipboardWindow() = %04X !\n", hWndClipboardOwner);
334 return hWndClipboardOwner;
338 /**************************************************************************
339 * GetPriorityClipboardFormat [USER.402]
341 int GetPriorityClipboardFormat(WORD FAR *lpPriorityList, short nCount)
343 dprintf_clipboard(stdnimp,
344 "GetPriorityClipboardFormat(%p, %d) !\n", lpPriorityList, nCount);
346 return 0;
350 /**************************************************************************
351 * CLIPBOARD_ReadSelection
353 * The current selection owner has set prop at our window w
354 * Transfer the property contents into the Clipboard
356 void CLIPBOARD_ReadSelection(Window w,Atom prop)
358 HANDLE hText;
359 LPCLIPFORMAT lpFormat = ClipFormats;
360 if(prop==None)
361 hText=0;
362 else{
363 Atom atype=None;
364 int aformat;
365 unsigned long nitems,remain;
366 unsigned char *val=NULL;
367 dprintf_clipboard(stddeb,"Received prop %s\n",XGetAtomName(display,prop));
368 /* TODO: Properties longer than 64K */
369 if(XGetWindowProperty(display,w,prop,0,0x3FFF,True,XA_STRING,
370 &atype, &aformat, &nitems, &remain, &val)!=Success)
371 printf("couldn't read property\n");
372 dprintf_clipboard(stddeb,"Type %s,Format %d,nitems %ld,value %s\n",
373 XGetAtomName(display,atype),aformat,nitems,val);
374 if(atype!=XA_STRING || aformat!=8){
375 fprintf(stderr,"Property not set\n");
376 hText=0;
377 } else {
378 dprintf_clipboard(stddeb,"Selection is %s\n",val);
379 hText=GlobalAlloc(GMEM_MOVEABLE, nitems);
380 memcpy(GlobalLock(hText),val,nitems+1);
381 GlobalUnlock(hText);
383 XFree(val);
385 while(TRUE) {
386 if (lpFormat == NULL) return;
387 if (lpFormat->wFormatID == CF_TEXT) break;
388 lpFormat = lpFormat->NextFormat;
390 if (lpFormat->hData != 0) GlobalFree(lpFormat->hData);
391 wait_for_selection=False;
392 lpFormat->hData = hText;
393 dprintf_clipboard(stddeb,"Received selection\n");
396 /**************************************************************************
397 * CLIPBOARD_ReleaseSelection
399 * Wine lost the primary selection.
400 * Empty the clipboard, but don't set the current owner to None.
401 * Make sure current get/put attempts fail.
403 void CLIPBOARD_ReleaseSelection(HWND hwnd)
405 wineOwnsSelection=False;
406 OpenClipboard(hwnd);
407 EmptyClipboard();
408 CloseClipboard();