X11 driver changes.
[wine] / windows / x11drv / clipboard.c
1 /*
2  * X11 windows driver
3  *
4  * Copyright 1994 Martin Ayotte
5  *           1996 Alex Korobka
6  */
7
8 #include "config.h"
9
10 #ifndef X_DISPLAY_MISSING
11
12 #include <X11/Xatom.h>
13 #include "ts_xlib.h"
14
15 #include "clipboard.h"
16 #include "debug.h"
17 #include "message.h"
18 #include "win.h"
19 #include "wintypes.h"
20 #include "x11drv.h"
21
22 extern HWND32 hWndClipOwner;
23 extern HWND32 hWndClipWindow;
24 extern CLIPFORMAT ClipFormats[];
25
26 static Bool   selectionWait = False;
27 static Bool   selectionAcquired = False;
28 static Window selectionWindow = None;
29 static Window selectionPrevWindow = None;
30
31 /**************************************************************************
32  *              X11DRV_CLIPBOARD_CheckSelection [Internal]
33  *
34  * Prevent X selection from being lost when a top level window is
35  * destroyed.
36  */
37 static void X11DRV_CLIPBOARD_CheckSelection(WND* pWnd)
38 {
39     TRACE(clipboard,"\tchecking %08x\n",
40         (unsigned) X11DRV_WND_GetXWindow(pWnd)
41     );
42
43     if( selectionAcquired && selectionWindow != None &&
44         X11DRV_WND_GetXWindow(pWnd) == selectionWindow )
45     {
46         selectionPrevWindow = selectionWindow;
47         selectionWindow = None;
48
49         if( pWnd->next ) 
50             selectionWindow = X11DRV_WND_GetXWindow(pWnd->next);
51         else if( pWnd->parent )
52              if( pWnd->parent->child != pWnd ) 
53                  selectionWindow = X11DRV_WND_GetXWindow(pWnd->parent->child);
54
55         TRACE(clipboard,"\tswitching selection from %08x to %08x\n", 
56                     (unsigned)selectionPrevWindow, (unsigned)selectionWindow);
57
58         if( selectionWindow != None )
59         {
60             TSXSetSelectionOwner(display, XA_PRIMARY, selectionWindow, CurrentTime);
61             if( TSXGetSelectionOwner(display, XA_PRIMARY) != selectionWindow )
62                 selectionWindow = None;
63         }
64     }
65 }
66
67 /**************************************************************************
68  *              X11DRV_CLIPBOARD_ReadSelection
69  *
70  * Called from the SelectionNotify event handler. 
71  */
72 void X11DRV_CLIPBOARD_ReadSelection(Window w,Atom prop)
73 {
74     HANDLE32     hText = 0;
75     LPCLIPFORMAT lpFormat = ClipFormats; 
76
77     TRACE(clipboard,"ReadSelection callback\n");
78
79     if(prop != None)
80     {
81         Atom            atype=AnyPropertyType;
82         int             aformat;
83         unsigned long   nitems,remain;
84         unsigned char*  val=NULL;
85
86         TRACE(clipboard,"\tgot property %s\n",TSXGetAtomName(display,prop));
87
88         /* TODO: Properties longer than 64K */
89
90         if(TSXGetWindowProperty(display,w,prop,0,0x3FFF,True,XA_STRING,
91             &atype, &aformat, &nitems, &remain, &val) != Success)
92             WARN(clipboard, "\tcouldn't read property\n");
93         else
94         {
95            TRACE(clipboard,"\tType %s,Format %d,nitems %ld,value %s\n",
96                              TSXGetAtomName(display,atype),aformat,nitems,val);
97
98            if(atype == XA_STRING && aformat == 8)
99            {
100               int       i,inlcount = 0;
101               char*     lpstr;
102
103               TRACE(clipboard,"\tselection is '%s'\n",val);
104
105               for(i=0; i <= nitems; i++)
106                   if( val[i] == '\n' ) inlcount++;
107
108               if( nitems )
109               {
110                 hText=GlobalAlloc32(GMEM_MOVEABLE, nitems + inlcount + 1);
111                 if( (lpstr = (char*)GlobalLock32(hText)) )
112                   for(i=0,inlcount=0; i <= nitems; i++)
113                   {
114                      if( val[i] == '\n' ) lpstr[inlcount++]='\r';
115                      lpstr[inlcount++]=val[i];
116                   }
117                 else hText = 0;
118               }
119            }
120            TSXFree(val);
121         }
122    }
123
124    /* delete previous CF_TEXT and CF_OEMTEXT data */
125
126    if( hText )
127    {
128      lpFormat = &ClipFormats[CF_TEXT-1];
129      if (lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32) 
130          CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
131      lpFormat = &ClipFormats[CF_OEMTEXT-1];
132      if (lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32)  
133          CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
134
135      lpFormat->wDataPresent = 1;
136      lpFormat->hData32 = hText;
137      lpFormat->hData16 = 0;
138    }
139
140    selectionWait=False;
141 }
142
143 /**************************************************************************
144  *              X11DRV_CLIPBOARD_ReleaseSelection
145  *
146  * Wine might have lost XA_PRIMARY selection because of
147  * EmptyClipboard() or other client. 
148  */
149 void X11DRV_CLIPBOARD_ReleaseSelection(Window w, HWND32 hwnd)
150 {
151     /* w is the window that lost selection,
152      * 
153      * selectionPrevWindow is nonzero if CheckSelection() was called. 
154      */
155
156     TRACE(clipboard,"\tevent->window = %08x (sw = %08x, spw=%08x)\n", 
157           (unsigned)w, (unsigned)selectionWindow, (unsigned)selectionPrevWindow );
158
159     if( selectionAcquired )
160     {
161         if( w == selectionWindow || selectionPrevWindow == None)
162         {
163             /* alright, we really lost it */
164
165             selectionAcquired = False;
166             selectionWindow = None; 
167
168             /* but we'll keep existing data for internal use */
169         }
170         else if( w == selectionPrevWindow )
171         {
172             w = TSXGetSelectionOwner(display, XA_PRIMARY);
173             if( w == None )
174                 TSXSetSelectionOwner(display, XA_PRIMARY, selectionWindow, CurrentTime);
175         }
176     }
177
178     selectionPrevWindow = None;
179 }
180
181 /**************************************************************************
182  *              X11DRV_CLIPBOARD_EmptyClipboard
183  */
184 void X11DRV_CLIPBOARD_EmptyClipboard()
185 {
186   if(selectionAcquired)
187     {
188       selectionAcquired = False;
189       selectionPrevWindow       = selectionWindow;
190       selectionWindow   = None;
191       
192       TRACE(clipboard, "\tgiving up selection (spw = %08x)\n", 
193             (unsigned)selectionPrevWindow);
194       
195       TSXSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
196     }
197 }
198
199 /**************************************************************************
200  *              X11DRV_CLIPBOARD_SetClipboardData
201  */
202 void X11DRV_CLIPBOARD_SetClipboardData(UINT32 wFormat)
203 {
204     Window       owner;
205
206     /* Acquire X selection if text format */
207
208     if( !selectionAcquired && 
209         (wFormat == CF_TEXT || wFormat == CF_OEMTEXT) )
210     {
211         owner = X11DRV_WND_FindXWindow( 
212             WIN_FindWndPtr( hWndClipWindow ? hWndClipWindow : AnyPopup32() ) 
213         );
214
215         TSXSetSelectionOwner(display,XA_PRIMARY, owner, CurrentTime);
216         if( TSXGetSelectionOwner(display,XA_PRIMARY) == owner )
217         {
218             selectionAcquired = True;
219             selectionWindow = owner;
220
221             TRACE(clipboard,"Grabbed X selection, owner=(%08x)\n", 
222                                                 (unsigned) owner);
223         }
224     }
225 }
226
227 /**************************************************************************
228  *              X11DRV_CLIPBOARD_RequestSelection
229  */
230 BOOL32 X11DRV_CLIPBOARD_RequestSelection()
231 {
232     HWND32 hWnd = (hWndClipWindow) ? hWndClipWindow : GetActiveWindow32();
233
234     if( selectionAcquired )
235       return TRUE;
236
237     if( !hWnd ) return FALSE;
238
239     TRACE(clipboard,"Requesting selection...\n");
240
241   /* request data type XA_STRING, later
242    * CLIPBOARD_ReadSelection() will be invoked 
243    * from the SelectionNotify event handler */
244
245     TSXConvertSelection(display, XA_PRIMARY, XA_STRING,
246                         TSXInternAtom(display, "PRIMARY_TEXT", False),
247                         X11DRV_WND_FindXWindow( WIN_FindWndPtr( hWnd ) ),
248                         CurrentTime);
249
250   /* wait until SelectionNotify is processed 
251    *
252    * FIXME: Use TSXCheckTypedWindowEvent() instead ( same in the 
253    *        CLIPBOARD_CheckSelection() ). 
254    */
255
256     selectionWait=True;
257     while(selectionWait) EVENT_WaitNetEvent( TRUE, FALSE );
258
259   /* we treat Unix text as CF_OEMTEXT */
260     TRACE(clipboard,"\tgot CF_OEMTEXT = %i\n", 
261                       ClipFormats[CF_OEMTEXT-1].wDataPresent);
262
263     return (BOOL32)ClipFormats[CF_OEMTEXT-1].wDataPresent;
264 }
265
266 /**************************************************************************
267  *              X11DRV_CLIPBOARD_ResetOwner
268  *
269  * Called from DestroyWindow().
270  */
271 void X11DRV_CLIPBOARD_ResetOwner(WND *pWnd, BOOL32 bFooBar)
272 {
273     LPCLIPFORMAT lpFormat = ClipFormats;
274
275     if(bFooBar && X11DRV_WND_GetXWindow(pWnd))
276       return;
277
278     if(!bFooBar && !X11DRV_WND_GetXWindow(pWnd))
279       return;
280
281     TRACE(clipboard,"clipboard owner = %04x, selection = %08x\n", 
282                                 hWndClipOwner, (unsigned)selectionWindow);
283
284     if( pWnd->hwndSelf == hWndClipOwner)
285     {
286         SendMessage16(hWndClipOwner,WM_RENDERALLFORMATS,0,0L);
287
288         /* check if all formats were rendered */
289
290         while(lpFormat)
291         {
292             if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
293             {
294                 TRACE(clipboard,"\tdata missing for clipboard format %i\n", 
295                                    lpFormat->wFormatID); 
296                 lpFormat->wDataPresent = 0;
297             }
298             lpFormat = lpFormat->NextFormat;
299         }
300         hWndClipOwner = 0;
301     }
302
303     /* now try to salvage current selection from being destroyed by X */
304
305     if( X11DRV_WND_GetXWindow(pWnd) ) X11DRV_CLIPBOARD_CheckSelection(pWnd);
306 }
307
308 #endif /* !defined(X_DISPLAY_MISSING) */