Release 941122
[wine/multimedia.git] / misc / clipboard.c
blob5e82d529df9b52107e51471bb39cde6b2083d689
1 /*
2 * 'Wine' Clipboard function handling
4 * Copyright 1994 Martin Ayotte
5 */
7 static char Copyright[] = "Copyright Martin Ayotte, 1994";
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <windows.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <X11/Xlib.h>
17 #include <X11/Xatom.h>
18 #include "prototypes.h"
19 #include "heap.h"
20 #include "win.h"
21 #include "stddebug.h"
22 /* #define DEBUG_CLIPBOARD /* */
23 /* #undef DEBUG_CLIPBOARD /* */
24 #include "debug.h"
26 typedef struct tagCLIPFORMAT {
27 WORD wFormatID;
28 WORD wRefCount;
29 LPSTR Name;
30 HANDLE hData;
31 DWORD BufSize;
32 void *PrevFormat;
33 void *NextFormat;
34 } CLIPFORMAT;
35 typedef CLIPFORMAT FAR* LPCLIPFORMAT;
37 static HWND hWndClipboardOwner = 0;
38 static HWND hWndViewer = 0;
39 static WORD LastRegFormat = 0xC000;
40 static Bool wait_for_selection = False;
41 static Bool wineOwnsSelection = False;
43 CLIPFORMAT ClipFormats[12] = {
44 { CF_TEXT, 1, "Text", (HANDLE)NULL, 0, NULL, &ClipFormats[1] },
45 { CF_BITMAP, 1, "Bitmap", (HANDLE)NULL, 0, &ClipFormats[0], &ClipFormats[2] },
46 { CF_METAFILEPICT, 1, "MetaFile Picture", (HANDLE)NULL, 0, &ClipFormats[1], &ClipFormats[3] },
47 { CF_SYLK, 1, "Sylk", (HANDLE)NULL, 0, &ClipFormats[2], &ClipFormats[4] },
48 { CF_DIF, 1, "DIF", (HANDLE)NULL, 0, &ClipFormats[3], &ClipFormats[5] },
49 { CF_TIFF, 1, "TIFF", (HANDLE)NULL, 0, &ClipFormats[4], &ClipFormats[6] },
50 { CF_OEMTEXT, 1, "OEM Text", (HANDLE)NULL, 0, &ClipFormats[5], &ClipFormats[7] },
51 { CF_DIB, 1, "DIB", (HANDLE)NULL, 0, &ClipFormats[6], &ClipFormats[8] },
52 { CF_PALETTE, 1, "Palette", (HANDLE)NULL, 0, &ClipFormats[7], &ClipFormats[9] },
53 { CF_PENDATA, 1, "PenData", (HANDLE)NULL, 0, &ClipFormats[8], &ClipFormats[10] },
54 { CF_RIFF, 1, "RIFF", (HANDLE)NULL, 0, &ClipFormats[9], &ClipFormats[11] },
55 { CF_WAVE, 1, "Wave", (HANDLE)NULL, 0, &ClipFormats[10], NULL }
58 /**************************************************************************
59 * OpenClipboard [USER.137]
61 BOOL OpenClipboard(HWND hWnd)
63 if (hWndClipboardOwner != 0) return FALSE;
64 hWndClipboardOwner = hWnd;
65 dprintf_clipboard(stddeb,"OpenClipboard(%04X); !\n", hWnd);
66 return TRUE;
70 /**************************************************************************
71 * CloseClipboard [USER.138]
73 BOOL CloseClipboard()
75 if (hWndClipboardOwner == 0) return FALSE;
76 hWndClipboardOwner = 0;
77 dprintf_clipboard(stddeb,"CloseClipboard(); !\n");
78 return TRUE;
82 /**************************************************************************
83 * EmptyClipboard [USER.139]
85 BOOL EmptyClipboard()
87 LPCLIPFORMAT lpFormat = ClipFormats;
88 if (hWndClipboardOwner == 0) return FALSE;
89 dprintf_clipboard(stddeb,"EmptyClipboard(); !\n");
90 while(TRUE) {
91 if (lpFormat == NULL) break;
92 if (lpFormat->hData != 0) {
93 GlobalFree(lpFormat->hData);
94 lpFormat->hData = 0;
96 lpFormat = lpFormat->NextFormat;
98 if(wineOwnsSelection){
99 dprintf_clipboard(stddeb,"Losing selection\n");
100 wineOwnsSelection=False;
101 XSetSelectionOwner(display,XA_PRIMARY,None,CurrentTime);
103 return TRUE;
107 /**************************************************************************
108 * GetClipboardOwner [USER.140]
110 HWND GetClipboardOwner()
112 dprintf_clipboard(stddeb,
113 "GetClipboardOwner() = %04X !\n", hWndClipboardOwner);
114 return hWndClipboardOwner;
118 /**************************************************************************
119 * SetClipboardData [USER.141]
121 HANDLE SetClipboardData(WORD wFormat, HANDLE hData)
123 LPCLIPFORMAT lpFormat = ClipFormats;
124 dprintf_clipboard(stddeb,
125 "SetClipboardDate(%04X, %04X) !\n", wFormat, hData);
126 while(TRUE) {
127 if (lpFormat == NULL) return 0;
128 if (lpFormat->wFormatID == wFormat) break;
129 lpFormat = lpFormat->NextFormat;
131 /* doc says we shouldn't use CurrentTime */
132 /* should we become owner of CLIPBOARD as well? */
133 XSetSelectionOwner(display,XA_PRIMARY,WIN_GetXWindow(hWndClipboardOwner),CurrentTime);
134 wineOwnsSelection = True;
135 dprintf_clipboard(stddeb,"Getting selection\n");
136 if (lpFormat->hData != 0) GlobalFree(lpFormat->hData);
137 lpFormat->hData = hData;
138 return lpFormat->hData;
142 /**************************************************************************
143 * GetClipboardData [USER.142]
145 HANDLE GetClipboardData(WORD wFormat)
147 LPCLIPFORMAT lpFormat = ClipFormats;
148 dprintf_clipboard(stddeb,"GetClipboardData(%04X) !\n", wFormat);
149 if(wFormat == CF_TEXT && !wineOwnsSelection)
150 { wait_for_selection=True;
151 dprintf_clipboard(stddeb,"Requesting selection\n");
152 XConvertSelection(display,XA_PRIMARY,XA_STRING,
153 XInternAtom(display,"PRIMARY_TEXT",False),
154 WIN_GetXWindow(hWndClipboardOwner),CurrentTime);
155 /* TODO: need time-out for broken clients */
156 while(wait_for_selection)MSG_WaitXEvent(-1);
158 while(TRUE) {
159 if (lpFormat == NULL) return 0;
160 if (lpFormat->wFormatID == wFormat) break;
161 lpFormat = lpFormat->NextFormat;
163 return lpFormat->hData;
167 /**************************************************************************
168 * CountClipboardFormats [USER.143]
170 int CountClipboardFormats()
172 int FormatCount = 0;
173 LPCLIPFORMAT lpFormat = ClipFormats;
174 while(TRUE) {
175 if (lpFormat == NULL) break;
176 if (lpFormat->hData != 0) {
177 dprintf_clipboard(stddeb,
178 "CountClipboardFormats // Find Not Empty (%04X) !\n",
179 lpFormat->hData);
180 FormatCount++;
182 lpFormat = lpFormat->NextFormat;
184 dprintf_clipboard(stddeb,"CountClipboardFormats() = %d !\n", FormatCount);
185 return FormatCount;
189 /**************************************************************************
190 * EnumClipboardFormats [USER.144]
192 WORD EnumClipboardFormats(WORD wFormat)
194 LPCLIPFORMAT lpFormat = ClipFormats;
195 dprintf_clipboard(stddeb,"EnumClipboardFormats(%04X) !\n", wFormat);
196 if (wFormat == 0) {
197 if (lpFormat->hData != 0)
198 return lpFormat->wFormatID;
199 else
200 wFormat = lpFormat->wFormatID;
202 while(TRUE) {
203 if (lpFormat == NULL) return 0;
204 if (lpFormat->wFormatID == wFormat) break;
205 lpFormat = lpFormat->NextFormat;
207 dprintf_clipboard(stddeb,"EnumClipboardFormats // Find Last (%04X) !\n",
208 lpFormat->wFormatID);
209 lpFormat = lpFormat->NextFormat;
210 while(TRUE) {
211 if (lpFormat == NULL) return 0;
212 if (lpFormat->hData != 0) break;
213 lpFormat = lpFormat->NextFormat;
215 dprintf_clipboard(stddeb,
216 "EnumClipboardFormats // Find Not Empty Id=%04X hData=%04X !\n",
217 lpFormat->wFormatID, lpFormat->hData);
218 return lpFormat->wFormatID;
222 /**************************************************************************
223 * RegisterClipboardFormat [USER.145]
225 WORD RegisterClipboardFormat(LPCSTR FormatName)
227 LPCLIPFORMAT lpNewFormat;
228 LPCLIPFORMAT lpFormat = ClipFormats;
229 if (FormatName == NULL) return 0;
230 while(TRUE) {
231 if (lpFormat->NextFormat == NULL) break;
232 lpFormat = lpFormat->NextFormat;
234 lpNewFormat = (LPCLIPFORMAT)malloc(sizeof(CLIPFORMAT));
235 if (lpNewFormat == NULL) return 0;
236 lpFormat->NextFormat = lpNewFormat;
237 dprintf_clipboard(stddeb,"RegisterClipboardFormat('%s') !\n", FormatName);
238 lpNewFormat->wFormatID = LastRegFormat;
239 lpNewFormat->wRefCount = 1;
240 lpNewFormat->Name = (LPSTR)malloc(strlen(FormatName) + 1);
241 if (lpNewFormat->Name == NULL) {
242 free(lpNewFormat);
243 return 0;
245 strcpy(lpNewFormat->Name, FormatName);
246 lpNewFormat->hData = 0;
247 lpNewFormat->BufSize = 0;
248 lpNewFormat->PrevFormat = lpFormat;
249 lpNewFormat->NextFormat = NULL;
250 return LastRegFormat++;
254 /**************************************************************************
255 * GetClipboardFormatName [USER.146]
257 int GetClipboardFormatName(WORD wFormat, LPSTR retStr, short maxlen)
259 LPCLIPFORMAT lpFormat = ClipFormats;
260 dprintf_clipboard(stddeb,
261 "GetClipboardFormat(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
262 while(TRUE) {
263 if (lpFormat == NULL) return 0;
264 if (lpFormat->wFormatID == wFormat) break;
265 lpFormat = lpFormat->NextFormat;
267 if (lpFormat->Name == NULL) return 0;
268 dprintf_clipboard(stddeb,
269 "GetClipboardFormat // Name='%s' !\n", lpFormat->Name);
270 maxlen = min(maxlen - 1, strlen(lpFormat->Name));
271 dprintf_clipboard(stddeb,"GetClipboardFormat // maxlen=%d !\n", maxlen);
272 memcpy(retStr, lpFormat->Name, maxlen);
273 retStr[maxlen] = 0;
274 return maxlen;
278 /**************************************************************************
279 * SetClipboardViewer [USER.147]
281 HWND SetClipboardViewer(HWND hWnd)
283 HWND hwndPrev = hWndViewer;
284 dprintf_clipboard(stddeb,"SetClipboardViewer(%04X) !\n", hWnd);
285 hWndViewer = hWnd;
286 return hwndPrev;
290 /**************************************************************************
291 * GetClipboardViewer [USER.148]
293 HWND GetClipboardViewer()
295 dprintf_clipboard(stddeb,"GetClipboardFormat() = %04X !\n", hWndViewer);
296 return hWndViewer;
300 /**************************************************************************
301 * ChangeClipboardChain [USER.149]
303 BOOL ChangeClipboardChain(HWND hWnd, HWND hWndNext)
305 dprintf_clipboard(stdnimp,
306 "ChangeClipboardChain(%04X, %04X) !\n", hWnd, hWndNext);
310 /**************************************************************************
311 * IsClipboardFormatAvailable [USER.193]
313 BOOL IsClipboardFormatAvailable(WORD wFormat)
315 LPCLIPFORMAT lpFormat = ClipFormats;
316 dprintf_clipboard(stddeb,"IsClipboardFormatAvailable(%04X) !\n", wFormat);
317 if(wFormat == CF_TEXT && !wineOwnsSelection) /* obtain selection as text if possible */
318 return GetClipboardData(CF_TEXT)!=0;
319 while(TRUE) {
320 if (lpFormat == NULL) return FALSE;
321 if (lpFormat->wFormatID == wFormat) break;
322 lpFormat = lpFormat->NextFormat;
324 return (lpFormat->hData != 0);
328 /**************************************************************************
329 * GetOpenClipboardWindow [USER.248]
331 HWND GetOpenClipboardWindow()
333 dprintf_clipboard(stddeb,
334 "GetOpenClipboardWindow() = %04X !\n", hWndClipboardOwner);
335 return hWndClipboardOwner;
339 /**************************************************************************
340 * GetPriorityClipboardFormat [USER.402]
342 int GetPriorityClipboardFormat(WORD FAR *lpPriorityList, short nCount)
344 dprintf_clipboard(stdnimp,
345 "GetPriorityClipboardFormat(%p, %d) !\n", lpPriorityList, nCount);
349 /**************************************************************************
350 * CLIPBOARD_ReadSelection
352 * The current selection owner has set prop at our window w
353 * Transfer the property contents into the Clipboard
355 void CLIPBOARD_ReadSelection(Window w,Atom prop)
357 HANDLE hText;
358 LPCLIPFORMAT lpFormat = ClipFormats;
359 if(prop==None)
360 hText=0;
361 else{
362 Atom atype=None;
363 int aformat;
364 unsigned long nitems,remain;
365 unsigned char *val=NULL;
366 dprintf_clipboard(stddeb,"Received prop %s\n",XGetAtomName(display,prop));
367 /* TODO: Properties longer than 64K */
368 if(XGetWindowProperty(display,w,prop,0,0x3FFF,True,XA_STRING,
369 &atype, &aformat, &nitems, &remain, &val)!=Success)
370 printf("couldn't read property\n");
371 dprintf_clipboard(stddeb,"Type %s,Format %d,nitems %ld,value %s\n",
372 XGetAtomName(display,atype),aformat,nitems,val);
373 if(atype!=XA_STRING || aformat!=8){
374 fprintf(stderr,"Property not set\n");
375 hText=0;
376 } else {
377 dprintf_clipboard(stddeb,"Selection is %s\n",val);
378 hText=GlobalAlloc(GMEM_MOVEABLE, nitems);
379 memcpy(GlobalLock(hText),val,nitems+1);
380 GlobalUnlock(hText);
382 XFree(val);
384 while(TRUE) {
385 if (lpFormat == NULL) return;
386 if (lpFormat->wFormatID == CF_TEXT) break;
387 lpFormat = lpFormat->NextFormat;
389 if (lpFormat->hData != 0) GlobalFree(lpFormat->hData);
390 wait_for_selection=False;
391 lpFormat->hData = hText;
392 dprintf_clipboard(stddeb,"Received selection\n");
395 /**************************************************************************
396 * CLIPBOARD_ReleaseSelection
398 * Wine lost the primary selection.
399 * Empty the clipboard, but don't set the current owner to None.
400 * Make sure current get/put attempts fail.
402 void CLIPBOARD_ReleaseSelection(HWND hwnd)
404 wineOwnsSelection=False;
405 OpenClipboard(hwnd);
406 EmptyClipboard();
407 CloseClipboard();