Release 960611
[wine/multimedia.git] / misc / clipboard.c
blob4ff267ca3f4b05b26c36574a80ff542080e56340
1 /*
2 * 'Wine' Clipboard function handling
4 * Copyright 1994 Martin Ayotte
5 * 1996 Alex Korobka
7 */
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <X11/Xlib.h>
17 #include <X11/Xatom.h>
18 #include "windows.h"
19 #include "win.h"
20 #include "message.h"
21 #include "clipboard.h"
22 #include "xmalloc.h"
23 #include "stddebug.h"
24 #include "debug.h"
26 #define CF_REGFORMATBASE 0xC000
28 typedef struct tagCLIPFORMAT {
29 WORD wFormatID;
30 WORD wRefCount;
31 WORD wDataPresent;
32 LPSTR Name;
33 HANDLE hData;
34 DWORD BufSize;
35 struct tagCLIPFORMAT *PrevFormat;
36 struct tagCLIPFORMAT *NextFormat;
37 } CLIPFORMAT, *LPCLIPFORMAT;
39 /* *************************************************************************
40 * internal variables
43 static HWND hWndClipOwner = 0; /* current clipboard owner */
44 static HWND hWndClipWindow = 0; /* window that opened clipboard */
45 static HWND hWndViewer = 0; /* start of viewers chain */
47 static BOOL bClipChanged = FALSE;
48 static WORD LastRegFormat = CF_REGFORMATBASE;
50 static Bool wait_for_selection = False;
51 static Bool wineOwnsSelection = False;
53 static CLIPFORMAT ClipFormats[16] = {
54 { CF_TEXT, 1, 0, "Text", (HANDLE)NULL, 0, NULL, &ClipFormats[1] },
55 { CF_BITMAP, 1, 0, "Bitmap", (HANDLE)NULL, 0, &ClipFormats[0], &ClipFormats[2] },
56 { CF_METAFILEPICT, 1, 0, "MetaFile Picture", (HANDLE)NULL, 0, &ClipFormats[1], &ClipFormats[3] },
57 { CF_SYLK, 1, 0, "Sylk", (HANDLE)NULL, 0, &ClipFormats[2], &ClipFormats[4] },
58 { CF_DIF, 1, 0, "DIF", (HANDLE)NULL, 0, &ClipFormats[3], &ClipFormats[5] },
59 { CF_TIFF, 1, 0, "TIFF", (HANDLE)NULL, 0, &ClipFormats[4], &ClipFormats[6] },
60 { CF_OEMTEXT, 1, 0, "OEM Text", (HANDLE)NULL, 0, &ClipFormats[5], &ClipFormats[7] },
61 { CF_DIB, 1, 0, "DIB", (HANDLE)NULL, 0, &ClipFormats[6], &ClipFormats[8] },
62 { CF_PALETTE, 1, 0, "Palette", (HANDLE)NULL, 0, &ClipFormats[7], &ClipFormats[9] },
63 { CF_PENDATA, 1, 0, "PenData", (HANDLE)NULL, 0, &ClipFormats[8], &ClipFormats[10] },
64 { CF_RIFF, 1, 0, "RIFF", (HANDLE)NULL, 0, &ClipFormats[9], &ClipFormats[11] },
65 { CF_WAVE, 1, 0, "Wave", (HANDLE)NULL, 0, &ClipFormats[10], &ClipFormats[12] },
66 { CF_OWNERDISPLAY, 1, 0, "Owner Display", (HANDLE)NULL, 0, &ClipFormats[11], &ClipFormats[13] },
67 { CF_DSPTEXT, 1, 0, "DSPText", (HANDLE)NULL, 0, &ClipFormats[12], &ClipFormats[14] },
68 { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", (HANDLE)NULL, 0, &ClipFormats[13], &ClipFormats[15] },
69 { CF_DSPBITMAP, 1, 0, "DSPBitmap", (HANDLE)NULL, 0, &ClipFormats[14], NULL }
72 /**************************************************************************
73 * CLIPBOARD_DisOwn
75 void CLIPBOARD_DisOwn(HWND hWnd)
77 LPCLIPFORMAT lpFormat = ClipFormats;
79 if( hWnd != hWndClipOwner || !hWndClipOwner ) return;
81 SendMessage16(hWndClipOwner,WM_RENDERALLFORMATS,0,0L);
83 /* check if all formats were rendered */
85 while(lpFormat)
87 if( lpFormat->wDataPresent && !lpFormat->hData )
89 dprintf_clipboard(stddeb,"\tdata missing for clipboard format %i\n", lpFormat->wFormatID);
90 lpFormat->wDataPresent = 0;
92 lpFormat = lpFormat->NextFormat;
95 hWndClipOwner = 0;
98 /**************************************************************************
99 * CLIPBOARD_DeleteRecord
101 void CLIPBOARD_DeleteRecord(LPCLIPFORMAT lpFormat)
103 if( lpFormat->wFormatID >= CF_GDIOBJFIRST &&
104 lpFormat->wFormatID <= CF_GDIOBJLAST )
105 DeleteObject(lpFormat->hData);
106 else if( lpFormat->hData )
107 GlobalFree16(lpFormat->hData);
109 lpFormat->wDataPresent = 0;
110 lpFormat->hData = 0;
112 bClipChanged = TRUE;
115 /**************************************************************************
116 * CLIPBOARD_RequestXSelection
118 BOOL CLIPBOARD_RequestXSelection()
120 HWND hWnd = hWndClipWindow;
122 if( !hWnd ) hWnd = GetActiveWindow();
124 wait_for_selection=True;
125 dprintf_clipboard(stddeb,"Requesting selection\n");
127 XConvertSelection(display,XA_PRIMARY,XA_STRING,
128 XInternAtom(display,"PRIMARY_TEXT",False),
129 WIN_GetXWindow(hWnd),CurrentTime);
131 /* TODO: need time-out for broken clients */
132 while(wait_for_selection) EVENT_WaitXEvent(-1);
134 return (BOOL)ClipFormats[0].wDataPresent;
137 /**************************************************************************
138 * CLIPBOARD_IsPresent
140 BOOL CLIPBOARD_IsPresent(WORD wFormat)
142 LPCLIPFORMAT lpFormat = ClipFormats;
144 while(TRUE) {
145 if (lpFormat == NULL) return FALSE;
146 if (lpFormat->wFormatID == wFormat) break;
147 lpFormat = lpFormat->NextFormat;
149 return (lpFormat->wDataPresent);
152 /**************************************************************************
153 * OpenClipboard [USER.137]
155 BOOL OpenClipboard(HWND hWnd)
157 BOOL bRet = FALSE;
158 dprintf_clipboard(stddeb,"OpenClipboard(%04x) = ", hWnd);
160 if (!hWndClipWindow)
162 hWndClipWindow = hWnd;
163 bRet = TRUE;
165 bClipChanged = FALSE;
167 dprintf_clipboard(stddeb,"%i\n", bRet);
168 return bRet;
172 /**************************************************************************
173 * CloseClipboard [USER.138]
175 BOOL CloseClipboard()
177 dprintf_clipboard(stddeb,"CloseClipboard(); !\n");
179 if (hWndClipWindow == 0) return FALSE;
180 hWndClipWindow = 0;
182 if (bClipChanged && hWndViewer) SendMessage16(hWndViewer,WM_DRAWCLIPBOARD,0,0L);
184 return TRUE;
188 /**************************************************************************
189 * EmptyClipboard [USER.139]
191 BOOL EmptyClipboard()
193 LPCLIPFORMAT lpFormat = ClipFormats;
195 dprintf_clipboard(stddeb,"EmptyClipboard()\n");
197 if (hWndClipWindow == 0) return FALSE;
199 /* destroy private objects */
201 if (hWndClipOwner)
202 SendMessage16(hWndClipOwner,WM_DESTROYCLIPBOARD,0,0L);
204 while(lpFormat)
206 if ( lpFormat->wDataPresent )
207 CLIPBOARD_DeleteRecord( lpFormat );
209 lpFormat = lpFormat->NextFormat;
212 hWndClipOwner = hWndClipWindow;
214 if(wineOwnsSelection){
215 dprintf_clipboard(stddeb,"Losing selection\n");
216 wineOwnsSelection=False;
217 XSetSelectionOwner(display,XA_PRIMARY,None,CurrentTime);
219 return TRUE;
223 /**************************************************************************
224 * GetClipboardOwner [USER.140]
226 HWND GetClipboardOwner()
228 dprintf_clipboard(stddeb,
229 "GetClipboardOwner() = %04x !\n", hWndClipOwner);
230 return hWndClipOwner;
234 /**************************************************************************
235 * SetClipboardData [USER.141]
237 HANDLE SetClipboardData(WORD wFormat, HANDLE hData)
239 LPCLIPFORMAT lpFormat = ClipFormats;
240 Window owner;
242 dprintf_clipboard(stddeb,
243 "SetClipboardDate(%04X, %04x) !\n", wFormat, hData);
245 while(TRUE)
247 if (lpFormat == NULL) return 0;
248 if (lpFormat->wFormatID == wFormat) break;
249 lpFormat = lpFormat->NextFormat;
252 /* Acquire X selection:
254 * doc says we shouldn't use CurrentTime
255 * should we become owner of CLIPBOARD as well?
258 owner = WIN_GetXWindow(hWndClipWindow);
260 XSetSelectionOwner(display,XA_PRIMARY,owner,CurrentTime);
261 if( XGetSelectionOwner(display,XA_PRIMARY) == owner )
263 wineOwnsSelection = True;
264 dprintf_clipboard(stddeb,"Getting selection\n");
267 if ( lpFormat->wDataPresent )
268 CLIPBOARD_DeleteRecord(lpFormat);
270 bClipChanged = TRUE;
271 lpFormat->wDataPresent = TRUE;
272 lpFormat->hData = hData;
274 return lpFormat->hData;
278 /**************************************************************************
279 * GetClipboardData [USER.142]
281 HANDLE GetClipboardData(WORD wFormat)
283 LPCLIPFORMAT lpFormat = ClipFormats;
284 dprintf_clipboard(stddeb,"GetClipboardData(%04X)\n", wFormat);
286 if (!hWndClipWindow) return 0;
288 /* if(wFormat == CF_TEXT && !wineOwnsSelection)
289 CLIPBOARD_RequestXSelection();
292 while(TRUE) {
293 if (lpFormat == NULL) return 0;
294 if (lpFormat->wFormatID == wFormat) break;
295 lpFormat = lpFormat->NextFormat;
298 if( lpFormat->wDataPresent && !lpFormat->hData )
299 if( IsWindow(hWndClipOwner) )
300 SendMessage16(hWndClipOwner,WM_RENDERFORMAT,(WPARAM)lpFormat->wFormatID,0L);
301 else
302 dprintf_clipboard(stddeb,"\thWndClipOwner is lost\n");
304 return lpFormat->hData;
308 /**************************************************************************
309 * CountClipboardFormats [USER.143]
311 INT CountClipboardFormats()
313 int FormatCount = 0;
314 LPCLIPFORMAT lpFormat = ClipFormats;
316 dprintf_clipboard(stddeb,"CountClipboardFormats()\n");
318 while(TRUE) {
319 if (lpFormat == NULL) break;
320 if (lpFormat->wDataPresent)
322 dprintf_clipboard(stddeb, "\tdata found for format %i\n", lpFormat->wFormatID);
324 FormatCount++;
326 lpFormat = lpFormat->NextFormat;
329 dprintf_clipboard(stddeb,"\ttotal %d\n", FormatCount);
330 return FormatCount;
334 /**************************************************************************
335 * EnumClipboardFormats [USER.144]
337 UINT EnumClipboardFormats(UINT wFormat)
339 LPCLIPFORMAT lpFormat = ClipFormats;
341 dprintf_clipboard(stddeb,"EnumClipboardFormats(%04X)\n", wFormat);
343 if( (!wFormat || wFormat == CF_TEXT) && !wineOwnsSelection)
344 CLIPBOARD_RequestXSelection();
346 if (wFormat == 0) {
347 if (lpFormat->wDataPresent)
348 return lpFormat->wFormatID;
349 else
350 wFormat = lpFormat->wFormatID;
353 /* walk up to the specified format record */
355 while(TRUE) {
356 if (lpFormat == NULL) return 0;
357 if (lpFormat->wFormatID == wFormat) break;
358 lpFormat = lpFormat->NextFormat;
361 /* find next format with available data */
363 lpFormat = lpFormat->NextFormat;
364 while(TRUE) {
365 if (lpFormat == NULL) return 0;
366 if (lpFormat->wDataPresent ) break;
367 lpFormat = lpFormat->NextFormat;
370 dprintf_clipboard(stddeb, "\t got not empty - Id=%04X hData=%04x !\n",
371 lpFormat->wFormatID, lpFormat->hData);
372 return lpFormat->wFormatID;
376 /**************************************************************************
377 * RegisterClipboardFormat [USER.145]
379 WORD RegisterClipboardFormat(LPCSTR FormatName)
381 LPCLIPFORMAT lpNewFormat;
382 LPCLIPFORMAT lpFormat = ClipFormats;
384 if (FormatName == NULL) return 0;
386 dprintf_clipboard(stddeb,"RegisterClipboardFormat('%s') !\n", FormatName);
388 /* walk format chain to see if it's already registered */
390 while(TRUE) {
391 if ( !strcmp(lpFormat->Name,FormatName) )
393 lpFormat->wRefCount++;
394 return lpFormat->wFormatID;
397 if ( lpFormat->NextFormat == NULL ) break;
399 lpFormat = lpFormat->NextFormat;
402 /* allocate storage for new format entry */
404 lpNewFormat = (LPCLIPFORMAT)xmalloc(sizeof(CLIPFORMAT));
405 lpFormat->NextFormat = lpNewFormat;
406 lpNewFormat->wFormatID = LastRegFormat;
407 lpNewFormat->wRefCount = 1;
409 lpNewFormat->Name = (LPSTR)xmalloc(strlen(FormatName) + 1);
410 strcpy(lpNewFormat->Name, FormatName);
412 lpNewFormat->wDataPresent = 0;
413 lpNewFormat->hData = 0;
414 lpNewFormat->BufSize = 0;
415 lpNewFormat->PrevFormat = lpFormat;
416 lpNewFormat->NextFormat = NULL;
418 return LastRegFormat++;
422 /**************************************************************************
423 * GetClipboardFormatName [USER.146]
425 int GetClipboardFormatName(WORD wFormat, LPSTR retStr, short maxlen)
427 LPCLIPFORMAT lpFormat = ClipFormats;
429 dprintf_clipboard(stddeb,
430 "GetClipboardFormat(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
432 while(TRUE) {
433 if (lpFormat == NULL) return 0;
434 if (lpFormat->wFormatID == wFormat) break;
435 lpFormat = lpFormat->NextFormat;
438 if (lpFormat->Name == NULL ||
439 lpFormat->wFormatID < CF_REGFORMATBASE) return 0;
441 dprintf_clipboard(stddeb,
442 "GetClipboardFormat // Name='%s' !\n", lpFormat->Name);
444 strncpy(retStr, lpFormat->Name, maxlen - 1);
445 retStr[maxlen] = 0;
447 return strlen(retStr);
451 /**************************************************************************
452 * SetClipboardViewer [USER.147]
454 HWND SetClipboardViewer(HWND hWnd)
456 HWND hwndPrev = hWndViewer;
458 dprintf_clipboard(stddeb,"SetClipboardViewer(%04x)\n", hWnd);
460 hWndViewer = hWnd;
461 return hwndPrev;
465 /**************************************************************************
466 * GetClipboardViewer [USER.148]
468 HWND GetClipboardViewer()
470 dprintf_clipboard(stddeb,"GetClipboardFormat() = %04x\n", hWndViewer);
472 return hWndViewer;
476 /**************************************************************************
477 * ChangeClipboardChain [USER.149]
479 BOOL ChangeClipboardChain(HWND hWnd, HWND hWndNext)
481 BOOL bRet = 0;
483 dprintf_clipboard(stdnimp, "ChangeClipboardChain(%04x, %04x)\n", hWnd, hWndNext);
485 if( hWndViewer )
486 bRet = !SendMessage16( hWndViewer, WM_CHANGECBCHAIN, (WPARAM)hWnd, (LPARAM)hWndNext);
487 else
488 dprintf_clipboard(stddeb,"ChangeClipboardChain: hWndViewer is lost\n");
490 if( hWnd == hWndViewer ) hWndViewer = hWndNext;
492 return 0;
496 /**************************************************************************
497 * IsClipboardFormatAvailable [USER.193]
499 BOOL IsClipboardFormatAvailable(WORD wFormat)
501 dprintf_clipboard(stddeb,"IsClipboardFormatAvailable(%04X) !\n", wFormat);
503 if(wFormat == CF_TEXT && !wineOwnsSelection)
504 CLIPBOARD_RequestXSelection();
506 return CLIPBOARD_IsPresent(wFormat);
510 /**************************************************************************
511 * GetOpenClipboardWindow [USER.248]
513 HWND GetOpenClipboardWindow()
515 dprintf_clipboard(stddeb,
516 "GetOpenClipboardWindow() = %04x\n", hWndClipWindow);
517 return hWndClipWindow;
521 /**************************************************************************
522 * GetPriorityClipboardFormat [USER.402]
524 int GetPriorityClipboardFormat(WORD *lpPriorityList, short nCount)
526 dprintf_clipboard(stdnimp,
527 "GetPriorityClipboardFormat(%p, %d) !\n", lpPriorityList, nCount);
529 return 0;
533 /**************************************************************************
534 * CLIPBOARD_ReadSelection
536 * The current selection owner has set prop at our window w
537 * Transfer the property contents into the Clipboard
539 void CLIPBOARD_ReadSelection(Window w,Atom prop)
541 HANDLE hText;
542 LPCLIPFORMAT lpFormat = ClipFormats;
543 if(prop==None)
544 hText=0;
545 else
547 Atom atype=None;
548 int aformat;
549 unsigned long nitems,remain;
550 unsigned char *val=NULL;
552 dprintf_clipboard(stddeb,"Received prop %s\n",XGetAtomName(display,prop));
554 /* TODO: Properties longer than 64K */
556 if(XGetWindowProperty(display,w,prop,0,0x3FFF,True,XA_STRING,
557 &atype, &aformat, &nitems, &remain, &val)!=Success)
558 fprintf(stderr,"couldn't read property\n");
560 dprintf_clipboard(stddeb,"Type %s,Format %d,nitems %ld,value %s\n",
561 XGetAtomName(display,atype),aformat,nitems,val);
563 if(atype!=XA_STRING || aformat!=8){
564 fprintf(stderr,"Property not set\n");
565 hText=0;
566 } else {
567 dprintf_clipboard(stddeb,"Selection is %s\n",val);
568 hText=GlobalAlloc16(GMEM_MOVEABLE, nitems+1);
569 memcpy(GlobalLock16(hText),val,nitems+1);
570 GlobalUnlock16(hText);
572 XFree(val);
575 while(TRUE) {
576 if (lpFormat == NULL) return;
577 if (lpFormat->wFormatID == CF_TEXT) break;
578 lpFormat = lpFormat->NextFormat;
581 if (lpFormat->wDataPresent)
582 CLIPBOARD_DeleteRecord(lpFormat);
584 wait_for_selection=False;
586 lpFormat->wDataPresent = TRUE;
587 lpFormat->hData = hText;
588 dprintf_clipboard(stddeb,"Received selection\n");
591 /**************************************************************************
592 * CLIPBOARD_ReleaseSelection
594 * Wine lost the primary selection.
595 * Empty the clipboard, but don't set the current owner to None.
596 * Make sure current get/put attempts fail.
598 void CLIPBOARD_ReleaseSelection(HWND hwnd)
600 wineOwnsSelection=False;
601 OpenClipboard(hwnd);
602 EmptyClipboard();
603 CloseClipboard();