Release 950901
[wine] / misc / clipboard.c
1 /*
2  * 'Wine' Clipboard function handling
3  *
4  * Copyright 1994 Martin Ayotte
5 static char Copyright[] = "Copyright Martin Ayotte, 1994";
6 */
7
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"
22
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;
33
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;
39
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 }
53     };
54
55 /**************************************************************************
56  *                      OpenClipboard           [USER.137]
57  */
58 BOOL OpenClipboard(HWND hWnd)
59 {
60     if (hWndClipboardOwner != 0) return FALSE;
61     hWndClipboardOwner = hWnd;
62     dprintf_clipboard(stddeb,"OpenClipboard(%04X); !\n", hWnd);
63     return TRUE;
64 }
65
66
67 /**************************************************************************
68  *                      CloseClipboard          [USER.138]
69  */
70 BOOL CloseClipboard()
71 {
72     if (hWndClipboardOwner == 0) return FALSE;
73     hWndClipboardOwner = 0;
74     dprintf_clipboard(stddeb,"CloseClipboard(); !\n");
75     return TRUE;
76 }
77
78
79 /**************************************************************************
80  *                      EmptyClipboard          [USER.139]
81  */
82 BOOL EmptyClipboard()
83 {
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;
92             }
93         lpFormat = lpFormat->NextFormat;
94         }
95     if(wineOwnsSelection){
96         dprintf_clipboard(stddeb,"Losing selection\n");
97         wineOwnsSelection=False;
98         XSetSelectionOwner(display,XA_PRIMARY,None,CurrentTime);
99     }
100     return TRUE;
101 }
102
103
104 /**************************************************************************
105  *                      GetClipboardOwner       [USER.140]
106  */
107 HWND GetClipboardOwner()
108 {
109     dprintf_clipboard(stddeb,
110                 "GetClipboardOwner() = %04X !\n", hWndClipboardOwner);
111     return hWndClipboardOwner;
112 }
113
114
115 /**************************************************************************
116  *                      SetClipboardData        [USER.141]
117  */
118 HANDLE SetClipboardData(WORD wFormat, HANDLE hData)
119 {
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;
127         }
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;
136 }
137
138
139 /**************************************************************************
140  *                      GetClipboardData        [USER.142]
141  */
142 HANDLE GetClipboardData(WORD wFormat)
143 {
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);
155     }
156     while(TRUE) {
157         if (lpFormat == NULL) return 0;
158         if (lpFormat->wFormatID == wFormat) break;
159         lpFormat = lpFormat->NextFormat;
160         }
161     return lpFormat->hData;
162 }
163
164
165 /**************************************************************************
166  *                      CountClipboardFormats   [USER.143]
167  */
168 int CountClipboardFormats()
169 {
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 (%04X) !\n",
177                                         lpFormat->hData);
178             FormatCount++;
179             }
180         lpFormat = lpFormat->NextFormat;
181         }
182     dprintf_clipboard(stddeb,"CountClipboardFormats() = %d !\n", FormatCount);
183     return FormatCount;
184 }
185
186
187 /**************************************************************************
188  *                      EnumClipboardFormats    [USER.144]
189  */
190 WORD EnumClipboardFormats(WORD wFormat)
191 {
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;
199         }
200     while(TRUE) {
201         if (lpFormat == NULL) return 0;
202         if (lpFormat->wFormatID == wFormat) break;
203         lpFormat = lpFormat->NextFormat;
204         }
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;
212         }
213     dprintf_clipboard(stddeb,
214                 "EnumClipboardFormats // Find Not Empty Id=%04X hData=%04X !\n",
215                                 lpFormat->wFormatID, lpFormat->hData);
216     return lpFormat->wFormatID;
217 }
218
219
220 /**************************************************************************
221  *                      RegisterClipboardFormat [USER.145]
222  */
223 WORD RegisterClipboardFormat(LPCSTR FormatName)
224 {
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;
231         }
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;
242         }
243     strcpy(lpNewFormat->Name, FormatName);
244     lpNewFormat->hData = 0;
245     lpNewFormat->BufSize = 0;
246     lpNewFormat->PrevFormat = lpFormat;
247     lpNewFormat->NextFormat = NULL;
248     return LastRegFormat++;
249 }
250
251
252 /**************************************************************************
253  *                      GetClipboardFormatName  [USER.146]
254  */
255 int GetClipboardFormatName(WORD wFormat, LPSTR retStr, short maxlen)
256 {
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;
264         }
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;
273 }
274
275
276 /**************************************************************************
277  *                      SetClipboardViewer      [USER.147]
278  */
279 HWND SetClipboardViewer(HWND hWnd)
280 {
281     HWND hwndPrev = hWndViewer;
282     dprintf_clipboard(stddeb,"SetClipboardViewer(%04X) !\n", hWnd);
283     hWndViewer = hWnd;
284     return hwndPrev;
285 }
286
287
288 /**************************************************************************
289  *                      GetClipboardViewer      [USER.148]
290  */
291 HWND GetClipboardViewer()
292 {
293     dprintf_clipboard(stddeb,"GetClipboardFormat() = %04X !\n", hWndViewer);
294     return hWndViewer;
295 }
296
297
298 /**************************************************************************
299  *                      ChangeClipboardChain    [USER.149]
300  */
301 BOOL ChangeClipboardChain(HWND hWnd, HWND hWndNext)
302 {
303     dprintf_clipboard(stdnimp,
304                 "ChangeClipboardChain(%04X, %04X) !\n", hWnd, hWndNext);
305
306      return 0;
307 }
308
309
310 /**************************************************************************
311  *                      IsClipboardFormatAvailable      [USER.193]
312  */
313 BOOL IsClipboardFormatAvailable(WORD wFormat)
314 {
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;
323         }
324     return (lpFormat->hData != 0);
325 }
326
327
328 /**************************************************************************
329  *                      GetOpenClipboardWindow  [USER.248]
330  */
331 HWND GetOpenClipboardWindow()
332 {
333     dprintf_clipboard(stddeb,
334                 "GetOpenClipboardWindow() = %04X !\n", hWndClipboardOwner);
335     return hWndClipboardOwner;
336 }
337
338
339 /**************************************************************************
340  *                      GetPriorityClipboardFormat      [USER.402]
341  */
342 int GetPriorityClipboardFormat(WORD FAR *lpPriorityList, short nCount)
343 {
344     dprintf_clipboard(stdnimp,
345         "GetPriorityClipboardFormat(%p, %d) !\n", lpPriorityList, nCount);
346
347     return 0;
348 }
349
350
351 /**************************************************************************
352  *                      CLIPBOARD_ReadSelection
353  *
354  *      The current selection owner has set prop at our window w
355  *      Transfer the property contents into the Clipboard
356  */
357 void CLIPBOARD_ReadSelection(Window w,Atom prop)
358 {
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);
383         }
384         XFree(val);
385     }
386     while(TRUE) {
387         if (lpFormat == NULL) return;
388         if (lpFormat->wFormatID == CF_TEXT) break;
389         lpFormat = lpFormat->NextFormat;
390         }
391     if (lpFormat->hData != 0) GlobalFree(lpFormat->hData);
392     wait_for_selection=False;
393     lpFormat->hData = hText;
394     dprintf_clipboard(stddeb,"Received selection\n");
395 }
396
397 /**************************************************************************
398  *                      CLIPBOARD_ReleaseSelection
399  *
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.
403  */
404 void CLIPBOARD_ReleaseSelection(HWND hwnd)
405 {
406     wineOwnsSelection=False;
407     OpenClipboard(hwnd);
408     EmptyClipboard();
409     CloseClipboard();
410 }