2 * 'Wine' Clipboard function handling
4 * Copyright 1994 Martin Ayotte
11 #include <sys/types.h>
17 #include <X11/Xatom.h>
21 #include "clipboard.h"
26 #define CF_REGFORMATBASE 0xC000
28 typedef struct tagCLIPFORMAT
{
35 struct tagCLIPFORMAT
*PrevFormat
;
36 struct tagCLIPFORMAT
*NextFormat
;
37 } CLIPFORMAT
, *LPCLIPFORMAT
;
39 /* *************************************************************************
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 /**************************************************************************
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 */
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
;
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;
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
;
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
)
158 dprintf_clipboard(stddeb
,"OpenClipboard(%04x) = ", hWnd
);
162 hWndClipWindow
= hWnd
;
165 bClipChanged
= FALSE
;
167 dprintf_clipboard(stddeb
,"%i\n", bRet
);
172 /**************************************************************************
173 * CloseClipboard [USER.138]
175 BOOL
CloseClipboard()
177 dprintf_clipboard(stddeb
,"CloseClipboard(); !\n");
179 if (hWndClipWindow
== 0) return FALSE
;
182 if (bClipChanged
&& hWndViewer
) SendMessage16(hWndViewer
,WM_DRAWCLIPBOARD
,0,0L);
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 */
202 SendMessage16(hWndClipOwner
,WM_DESTROYCLIPBOARD
,0,0L);
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
);
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
;
242 dprintf_clipboard(stddeb
,
243 "SetClipboardDate(%04X, %04x) !\n", wFormat
, hData
);
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
);
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();
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);
302 dprintf_clipboard(stddeb
,"\thWndClipOwner is lost\n");
304 return lpFormat
->hData
;
308 /**************************************************************************
309 * CountClipboardFormats [USER.143]
311 INT
CountClipboardFormats()
314 LPCLIPFORMAT lpFormat
= ClipFormats
;
316 dprintf_clipboard(stddeb
,"CountClipboardFormats()\n");
319 if (lpFormat
== NULL
) break;
320 if (lpFormat
->wDataPresent
)
322 dprintf_clipboard(stddeb
, "\tdata found for format %i\n", lpFormat
->wFormatID
);
326 lpFormat
= lpFormat
->NextFormat
;
329 dprintf_clipboard(stddeb
,"\ttotal %d\n", 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();
347 if (lpFormat
->wDataPresent
)
348 return lpFormat
->wFormatID
;
350 wFormat
= lpFormat
->wFormatID
;
353 /* walk up to the specified format record */
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
;
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 */
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
);
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);
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
);
465 /**************************************************************************
466 * GetClipboardViewer [USER.148]
468 HWND
GetClipboardViewer()
470 dprintf_clipboard(stddeb
,"GetClipboardFormat() = %04x\n", hWndViewer
);
476 /**************************************************************************
477 * ChangeClipboardChain [USER.149]
479 BOOL
ChangeClipboardChain(HWND hWnd
, HWND hWndNext
)
483 dprintf_clipboard(stdnimp
, "ChangeClipboardChain(%04x, %04x)\n", hWnd
, hWndNext
);
486 bRet
= !SendMessage16( hWndViewer
, WM_CHANGECBCHAIN
, (WPARAM
)hWnd
, (LPARAM
)hWndNext
);
488 dprintf_clipboard(stddeb
,"ChangeClipboardChain: hWndViewer is lost\n");
490 if( hWnd
== hWndViewer
) hWndViewer
= hWndNext
;
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
);
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
)
542 LPCLIPFORMAT lpFormat
= ClipFormats
;
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");
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
);
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
;