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