Release 951105
[wine/multimedia.git] / misc / clipboard.c
blob68f5fe76c555a4ce276a339ee7075f4fbe28d0ec
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("NPFMT"); !\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() = "NPFMT" !\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, "NPFMT") !\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 (!hWndClipboardOwner) return 0;
147 if(wFormat == CF_TEXT && !wineOwnsSelection)
148 { wait_for_selection=True;
149 dprintf_clipboard(stddeb,"Requesting selection\n");
150 XConvertSelection(display,XA_PRIMARY,XA_STRING,
151 XInternAtom(display,"PRIMARY_TEXT",False),
152 WIN_GetXWindow(hWndClipboardOwner),CurrentTime);
153 /* TODO: need time-out for broken clients */
154 while(wait_for_selection)MSG_WaitXEvent(-1);
156 while(TRUE) {
157 if (lpFormat == NULL) return 0;
158 if (lpFormat->wFormatID == wFormat) break;
159 lpFormat = lpFormat->NextFormat;
161 return lpFormat->hData;
165 /**************************************************************************
166 * CountClipboardFormats [USER.143]
168 int CountClipboardFormats()
170 int FormatCount = 0;
171 LPCLIPFORMAT lpFormat = ClipFormats;
172 while(TRUE) {
173 if (lpFormat == NULL) break;
174 if (lpFormat->hData != 0) {
175 dprintf_clipboard(stddeb,
176 "CountClipboardFormats // Find Not Empty ("NPFMT") !\n",
177 lpFormat->hData);
178 FormatCount++;
180 lpFormat = lpFormat->NextFormat;
182 dprintf_clipboard(stddeb,"CountClipboardFormats() = %d !\n", FormatCount);
183 return FormatCount;
187 /**************************************************************************
188 * EnumClipboardFormats [USER.144]
190 WORD EnumClipboardFormats(WORD wFormat)
192 LPCLIPFORMAT lpFormat = ClipFormats;
193 dprintf_clipboard(stddeb,"EnumClipboardFormats(%04X) !\n", wFormat);
194 if (wFormat == 0) {
195 if (lpFormat->hData != 0)
196 return lpFormat->wFormatID;
197 else
198 wFormat = lpFormat->wFormatID;
200 while(TRUE) {
201 if (lpFormat == NULL) return 0;
202 if (lpFormat->wFormatID == wFormat) break;
203 lpFormat = lpFormat->NextFormat;
205 dprintf_clipboard(stddeb,"EnumClipboardFormats // Find Last (%04X) !\n",
206 lpFormat->wFormatID);
207 lpFormat = lpFormat->NextFormat;
208 while(TRUE) {
209 if (lpFormat == NULL) return 0;
210 if (lpFormat->hData != 0) break;
211 lpFormat = lpFormat->NextFormat;
213 dprintf_clipboard(stddeb,
214 "EnumClipboardFormats // Find Not Empty Id=%04X hData="NPFMT" !\n",
215 lpFormat->wFormatID, lpFormat->hData);
216 return lpFormat->wFormatID;
220 /**************************************************************************
221 * RegisterClipboardFormat [USER.145]
223 WORD RegisterClipboardFormat(LPCSTR FormatName)
225 LPCLIPFORMAT lpNewFormat;
226 LPCLIPFORMAT lpFormat = ClipFormats;
227 if (FormatName == NULL) return 0;
228 while(TRUE) {
229 if (lpFormat->NextFormat == NULL) break;
230 lpFormat = lpFormat->NextFormat;
232 lpNewFormat = (LPCLIPFORMAT)malloc(sizeof(CLIPFORMAT));
233 if (lpNewFormat == NULL) return 0;
234 lpFormat->NextFormat = lpNewFormat;
235 dprintf_clipboard(stddeb,"RegisterClipboardFormat('%s') !\n", FormatName);
236 lpNewFormat->wFormatID = LastRegFormat;
237 lpNewFormat->wRefCount = 1;
238 lpNewFormat->Name = (LPSTR)malloc(strlen(FormatName) + 1);
239 if (lpNewFormat->Name == NULL) {
240 free(lpNewFormat);
241 return 0;
243 strcpy(lpNewFormat->Name, FormatName);
244 lpNewFormat->hData = 0;
245 lpNewFormat->BufSize = 0;
246 lpNewFormat->PrevFormat = lpFormat;
247 lpNewFormat->NextFormat = NULL;
248 return LastRegFormat++;
252 /**************************************************************************
253 * GetClipboardFormatName [USER.146]
255 int GetClipboardFormatName(WORD wFormat, LPSTR retStr, short maxlen)
257 LPCLIPFORMAT lpFormat = ClipFormats;
258 dprintf_clipboard(stddeb,
259 "GetClipboardFormat(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
260 while(TRUE) {
261 if (lpFormat == NULL) return 0;
262 if (lpFormat->wFormatID == wFormat) break;
263 lpFormat = lpFormat->NextFormat;
265 if (lpFormat->Name == NULL) return 0;
266 dprintf_clipboard(stddeb,
267 "GetClipboardFormat // Name='%s' !\n", lpFormat->Name);
268 maxlen = MIN(maxlen - 1, strlen(lpFormat->Name));
269 dprintf_clipboard(stddeb,"GetClipboardFormat // maxlen=%d !\n", maxlen);
270 memcpy(retStr, lpFormat->Name, maxlen);
271 retStr[maxlen] = 0;
272 return maxlen;
276 /**************************************************************************
277 * SetClipboardViewer [USER.147]
279 HWND SetClipboardViewer(HWND hWnd)
281 HWND hwndPrev = hWndViewer;
282 dprintf_clipboard(stddeb,"SetClipboardViewer("NPFMT") !\n", hWnd);
283 hWndViewer = hWnd;
284 return hwndPrev;
288 /**************************************************************************
289 * GetClipboardViewer [USER.148]
291 HWND GetClipboardViewer()
293 dprintf_clipboard(stddeb,"GetClipboardFormat() = "NPFMT" !\n", hWndViewer);
294 return hWndViewer;
298 /**************************************************************************
299 * ChangeClipboardChain [USER.149]
301 BOOL ChangeClipboardChain(HWND hWnd, HWND hWndNext)
303 dprintf_clipboard(stdnimp,
304 "ChangeClipboardChain("NPFMT", "NPFMT") !\n", hWnd, hWndNext);
306 return 0;
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() = "NPFMT" !\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);
347 return 0;
351 /**************************************************************************
352 * CLIPBOARD_ReadSelection
354 * The current selection owner has set prop at our window w
355 * Transfer the property contents into the Clipboard
357 void CLIPBOARD_ReadSelection(Window w,Atom prop)
359 HANDLE hText;
360 LPCLIPFORMAT lpFormat = ClipFormats;
361 if(prop==None)
362 hText=0;
363 else{
364 Atom atype=None;
365 int aformat;
366 unsigned long nitems,remain;
367 unsigned char *val=NULL;
368 dprintf_clipboard(stddeb,"Received prop %s\n",XGetAtomName(display,prop));
369 /* TODO: Properties longer than 64K */
370 if(XGetWindowProperty(display,w,prop,0,0x3FFF,True,XA_STRING,
371 &atype, &aformat, &nitems, &remain, &val)!=Success)
372 printf("couldn't read property\n");
373 dprintf_clipboard(stddeb,"Type %s,Format %d,nitems %ld,value %s\n",
374 XGetAtomName(display,atype),aformat,nitems,val);
375 if(atype!=XA_STRING || aformat!=8){
376 fprintf(stderr,"Property not set\n");
377 hText=0;
378 } else {
379 dprintf_clipboard(stddeb,"Selection is %s\n",val);
380 hText=GlobalAlloc(GMEM_MOVEABLE, nitems);
381 memcpy(GlobalLock(hText),val,nitems+1);
382 GlobalUnlock(hText);
384 XFree(val);
386 while(TRUE) {
387 if (lpFormat == NULL) return;
388 if (lpFormat->wFormatID == CF_TEXT) break;
389 lpFormat = lpFormat->NextFormat;
391 if (lpFormat->hData != 0) GlobalFree(lpFormat->hData);
392 wait_for_selection=False;
393 lpFormat->hData = hText;
394 dprintf_clipboard(stddeb,"Received selection\n");
397 /**************************************************************************
398 * CLIPBOARD_ReleaseSelection
400 * Wine lost the primary selection.
401 * Empty the clipboard, but don't set the current owner to None.
402 * Make sure current get/put attempts fail.
404 void CLIPBOARD_ReleaseSelection(HWND hwnd)
406 wineOwnsSelection=False;
407 OpenClipboard(hwnd);
408 EmptyClipboard();
409 CloseClipboard();