Italian keyboard fixes.
[wine] / windows / clipboard.c
1 /*
2  * WIN32 clipboard implementation
3  *
4  * Copyright 1994 Martin Ayotte
5  *           1996 Alex Korobka
6  *           1999 Noel Borthwick
7  *
8  * NOTES:
9  *    This file contains the implementation for the WIN32 Clipboard API
10  * and Wine's internal clipboard cache.
11  * The actual contents of the clipboard are held in the clipboard cache.
12  * The internal implementation talks to a "clipboard driver" to fill or
13  * expose the cache to the native device. (Currently only the X11 and
14  * TTY clipboard  driver are available)
15  *
16  * TODO: 
17  *
18  */
19
20 #include <stdlib.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include "windef.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "wine/winuser16.h"
30 #include "wine/winbase16.h"
31 #include "heap.h"
32 #include "message.h"
33 #include "task.h"
34 #include "queue.h"
35 #include "user.h"
36 #include "clipboard.h"
37 #include "debugtools.h"
38
39 DEFAULT_DEBUG_CHANNEL(clipboard);
40
41 #define  CF_REGFORMATBASE       0xC000
42
43 /**************************************************************************
44  *        Clipboard context global variables
45  */
46
47 static HANDLE hClipLock   = 0;
48 static BOOL bCBHasChanged  = FALSE;
49
50 HWND hWndClipWindow = 0;          /* window that last opened clipboard */
51 HWND hWndClipOwner  = 0;          /* current clipboard owner */
52 HANDLE16 hTaskClipOwner = 0;      /* clipboard owner's task  */
53 static HWND hWndViewer     = 0;   /* start of viewers chain */
54
55 static WORD LastRegFormat = CF_REGFORMATBASE;
56
57 /* Clipboard cache initial data.
58  * WARNING: This data ordering is dependendent on the WINE_CLIPFORMAT structure
59  * declared in clipboard.h
60  */
61 WINE_CLIPFORMAT ClipFormats[17]  = {
62     { CF_TEXT, 1, 0, "Text",  0, 0, 0, 0, NULL, &ClipFormats[1]},
63     { CF_BITMAP, 1, 0, "Bitmap", 0, 0, 0, 0, &ClipFormats[0], &ClipFormats[2]},
64     { CF_METAFILEPICT, 1, 0, "MetaFile Picture", 0, 0, 0, 0, &ClipFormats[1], &ClipFormats[3]},
65     { CF_SYLK, 1, 0, "Sylk", 0, 0, 0, 0, &ClipFormats[2], &ClipFormats[4]},
66     { CF_DIF, 1, 0, "DIF", 0, 0, 0, 0, &ClipFormats[3], &ClipFormats[5]},
67     { CF_TIFF, 1, 0, "TIFF", 0, 0, 0, 0, &ClipFormats[4], &ClipFormats[6]},
68     { CF_OEMTEXT, 1, 0, "OEM Text", 0, 0, 0, 0, &ClipFormats[5], &ClipFormats[7]},
69     { CF_DIB, 1, 0, "DIB", 0, 0, 0, 0, &ClipFormats[6], &ClipFormats[8]},
70     { CF_PALETTE, 1, 0, "Palette", 0, 0, 0, 0, &ClipFormats[7], &ClipFormats[9]},
71     { CF_PENDATA, 1, 0, "PenData", 0, 0, 0, 0, &ClipFormats[8], &ClipFormats[10]},
72     { CF_RIFF, 1, 0, "RIFF", 0, 0, 0, 0, &ClipFormats[9], &ClipFormats[11]},
73     { CF_WAVE, 1, 0, "Wave", 0, 0, 0, 0, &ClipFormats[10], &ClipFormats[12]},
74     { CF_OWNERDISPLAY, 1, 0, "Owner Display", 0, 0, 0, 0, &ClipFormats[11], &ClipFormats[13]},
75     { CF_DSPTEXT, 1, 0, "DSPText", 0, 0, 0, 0, &ClipFormats[12], &ClipFormats[14]},
76     { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", 0, 0, 0, 0, &ClipFormats[13], &ClipFormats[15]},
77     { CF_DSPBITMAP, 1, 0, "DSPBitmap", 0, 0, 0, 0, &ClipFormats[14], &ClipFormats[16]},
78     { CF_HDROP, 1, 0, "HDROP", 0, 0, 0, 0, &ClipFormats[15], NULL}
79 };
80
81
82 /**************************************************************************
83  *                Internal Clipboard implementation methods
84  **************************************************************************/
85
86
87 /**************************************************************************
88  *                      CLIPBOARD_LookupFormat
89  */
90 static LPWINE_CLIPFORMAT __lookup_format( LPWINE_CLIPFORMAT lpFormat, WORD wID )
91 {
92     while(TRUE)
93     {
94         if (lpFormat == NULL ||
95             lpFormat->wFormatID == wID) break;
96         lpFormat = lpFormat->NextFormat;
97     }
98     return lpFormat;
99 }
100
101 LPWINE_CLIPFORMAT CLIPBOARD_LookupFormat( WORD wID )
102 {
103   return __lookup_format( ClipFormats, wID );
104 }
105
106 /**************************************************************************
107  *                      CLIPBOARD_IsLocked
108  *  Check if the clipboard cache is available to the caller
109  */
110 BOOL CLIPBOARD_IsLocked()
111 {
112   BOOL bIsLocked = TRUE;
113   HANDLE16 hTaskCur = GetCurrentTask();
114
115   /*
116    * The clipboard is available:
117    * 1. if the caller's task has opened the clipboard,
118    * or
119    * 2. if the caller is the clipboard owners task, AND is responding to a
120    *    WM_RENDERFORMAT message.
121    */
122   if ( hClipLock == hTaskCur )
123       bIsLocked = FALSE;
124       
125   else if ( hTaskCur == hTaskClipOwner )
126   {
127       /* Check if we're currently executing inside a window procedure
128        * called in response to a WM_RENDERFORMAT message. A WM_RENDERFORMAT
129        * handler is not permitted to open the clipboard since it has been opened
130        * by another client. However the handler must have access to the
131        * clipboard in order to update data in response to this message.
132        */
133       MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
134       
135       if ( queue
136            && queue->smWaiting
137            && queue->smWaiting->msg == WM_RENDERFORMAT
138            && queue->smWaiting->hSrcQueue
139          )
140         bIsLocked = FALSE;
141         
142       QUEUE_Unlock( queue );
143   }
144
145   return bIsLocked;
146 }
147
148 /**************************************************************************
149  *                      CLIPBOARD_ReleaseOwner
150  *   Gives up ownership of the clipboard
151  */
152 void CLIPBOARD_ReleaseOwner()
153 {
154    hWndClipOwner = 0;
155    hTaskClipOwner = 0;
156 }
157
158 /**************************************************************************
159  *                      CLIPBOARD_GlobalFreeProc
160  *
161  * This is a callback mechanism to allow HGLOBAL data to be released in
162  * the context of the process which allocated it. We post a WM_TIMER message
163  * to the owner window(in CLIPBOARD_DeleteRecord) and destroy the data(in idEvent)
164  * in this WndProc, which is invoked when the apps message loop calls DispatchMessage.
165  * This technique is discussed in Matt Pietrek's "Under the Hood".
166  * An article describing the same may be found in MSDN by searching for WM_TIMER.
167  * Note that this mechanism will probably stop working when WINE supports
168  * address space separation. When "queue events" are implemented in Wine we
169  * should switch to using that mechanism, since it is more robust and does not
170  * require a procedure address to be passed. See the SetWinEventHook API for
171  * more info on this.
172  */
173 VOID CALLBACK CLIPBOARD_GlobalFreeProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime )
174 {
175     /* idEvent is the HGLOBAL to be deleted */
176     GlobalFree( (HGLOBAL)idEvent );
177 }
178
179 /**************************************************************************
180  *                      CLIPBOARD_DeleteRecord
181  */
182 void CLIPBOARD_DeleteRecord(LPWINE_CLIPFORMAT lpFormat, BOOL bChange)
183 {
184     if( (lpFormat->wFormatID >= CF_GDIOBJFIRST &&
185          lpFormat->wFormatID <= CF_GDIOBJLAST) || lpFormat->wFormatID == CF_BITMAP 
186             || lpFormat->wFormatID == CF_PALETTE)
187     {
188       if (lpFormat->hData32)
189         DeleteObject(lpFormat->hData32);
190       if (lpFormat->hData16)
191         DeleteObject(lpFormat->hData16);
192     }
193     else if( lpFormat->wFormatID == CF_METAFILEPICT )
194     {
195       if (lpFormat->hData32)
196       {
197         DeleteMetaFile( ((METAFILEPICT *)GlobalLock( lpFormat->hData32 ))->hMF );
198         PostMessageA(hWndClipOwner, WM_TIMER,
199                      (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
200         if (lpFormat->hDataSrc32)
201         {
202           /* Release lpFormat->hData32 in the context of the process which created it.
203            * See CLIPBOARD_GlobalFreeProc for more details about this technique.
204            * GlobalFree(lpFormat->hDataSrc32);
205            */
206           PostMessageA(hWndClipOwner, WM_TIMER,
207                        (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
208         }
209           
210         if (lpFormat->hData16)
211           /* HMETAFILE16 and HMETAFILE32 are apparently the same thing, 
212              and a shallow copy is enough to share a METAFILEPICT
213              structure between 16bit and 32bit clipboards.  The MetaFile
214              should of course only be deleted once. */
215           GlobalFree16(lpFormat->hData16);
216       }
217       if (lpFormat->hData16)
218       {
219         DeleteMetaFile16( ((METAFILEPICT16 *)GlobalLock16( lpFormat->hData16 ))->hMF );
220         GlobalFree16(lpFormat->hData16);
221       }
222     }
223     else 
224     {
225       if (lpFormat->hData32)
226       {
227         /* Release lpFormat->hData32 in the context of the process which created it.
228          * See CLIPBOARD_GlobalFreeProc for more details about this technique.
229          * GlobalFree( lpFormat->hData32 );
230          */
231         PostMessageA(hWndClipOwner, WM_TIMER,
232                      (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
233       }
234       if (lpFormat->hDataSrc32)
235       {
236         /* Release lpFormat->hData32 in the context of the process which created it.
237          * See CLIPBOARD_GlobalFreeProc for more details about this technique.
238          * GlobalFree(lpFormat->hDataSrc32);
239          */
240         PostMessageA(hWndClipOwner, WM_TIMER,
241                      (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
242       }
243       if (lpFormat->hData16)
244         GlobalFree16(lpFormat->hData16);
245     }
246
247     lpFormat->wDataPresent = 0; 
248     lpFormat->hData16 = 0;
249     lpFormat->hData32 = 0;
250     lpFormat->hDataSrc32 = 0;
251     lpFormat->drvData = 0;
252
253     if( bChange ) bCBHasChanged = TRUE;
254 }
255
256 /**************************************************************************
257  *                      CLIPBOARD_EmptyCache
258  */
259 void CLIPBOARD_EmptyCache( BOOL bChange )
260 {
261     LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
262
263     while(lpFormat)
264     {
265         if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
266              CLIPBOARD_DeleteRecord( lpFormat, bChange );
267
268         lpFormat = lpFormat->NextFormat;
269     }
270 }
271
272 /**************************************************************************
273  *                      CLIPBOARD_IsPresent
274  */
275 BOOL CLIPBOARD_IsPresent(WORD wFormat)
276 {
277     /* special case */
278
279     if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
280         return ClipFormats[CF_TEXT-1].wDataPresent ||
281                ClipFormats[CF_OEMTEXT-1].wDataPresent;
282     else
283     {
284         LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
285         if( lpFormat ) return (lpFormat->wDataPresent);
286     }
287     return FALSE;
288 }
289
290 /**************************************************************************
291  *                      CLIPBOARD_IsCacheRendered
292  *  Checks if any data needs to be rendered to the clipboard cache
293  *  RETURNS:
294  *    TRUE  - All clipboard data is available in the cache
295  *    FALSE - Some data is marked for delayed render and needs rendering
296  */
297 BOOL CLIPBOARD_IsCacheRendered()
298 {
299     LPWINE_CLIPFORMAT lpFormat = ClipFormats;
300     
301     /* check if all formats were rendered */
302     while(lpFormat)
303     {
304         if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
305             return FALSE;
306         
307         lpFormat = lpFormat->NextFormat;
308     }
309     
310     return TRUE;
311 }
312
313
314 /**************************************************************************
315  *                      CLIPBOARD_IsMemoryObject
316  *  Tests if the clipboard format specifies a memory object
317  */
318 BOOL CLIPBOARD_IsMemoryObject( WORD wFormat )
319 {
320     switch(wFormat)
321     {
322         case CF_BITMAP:
323         case CF_METAFILEPICT:
324         case CF_DSPTEXT:
325         case CF_ENHMETAFILE:
326         case CF_HDROP:
327         case CF_PALETTE:
328         case CF_PENDATA:
329             return FALSE;
330         default:
331             return TRUE;
332      }
333 }
334
335 /***********************************************************************
336  * CLIPBOARD_GlobalDupMem( HGLOBAL )
337  * Helper method to duplicate an HGLOBAL chunk of memory into shared memory
338  */
339 HGLOBAL CLIPBOARD_GlobalDupMem( HGLOBAL hGlobalSrc )
340 {
341     HGLOBAL hGlobalDest;
342     PVOID pGlobalSrc, pGlobalDest;
343     DWORD cBytes;
344     
345     if ( !hGlobalSrc )
346       return 0;
347
348     cBytes = GlobalSize(hGlobalSrc);
349     if ( 0 == cBytes )
350       return 0;
351
352     /* Turn on the DDESHARE and _MOVEABLE flags explicitly */
353     hGlobalDest = GlobalAlloc( GlobalFlags(hGlobalSrc) | GMEM_DDESHARE | GMEM_MOVEABLE,
354                                cBytes );
355     if ( !hGlobalDest )
356       return 0;
357     
358     pGlobalSrc = GlobalLock(hGlobalSrc);
359     pGlobalDest = GlobalLock(hGlobalDest);
360     if ( !pGlobalSrc || !pGlobalDest )
361       return 0;
362
363     memcpy(pGlobalDest, pGlobalSrc, cBytes);
364         
365     GlobalUnlock(hGlobalSrc);
366     GlobalUnlock(hGlobalDest);
367
368     return hGlobalDest;
369 }
370
371 /**************************************************************************
372  *                      CLIPBOARD_GetFormatName
373  *  Gets the format name associated with an ID
374  */
375 char * CLIPBOARD_GetFormatName(UINT wFormat)
376 {
377     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
378     return (lpFormat) ? lpFormat->Name : NULL;
379 }
380
381
382 /**************************************************************************
383  *                      CLIPBOARD_RenderFormat
384  */
385 static BOOL CLIPBOARD_RenderFormat(LPWINE_CLIPFORMAT lpFormat)
386 {
387   /*
388    * If WINE is not the selection owner, and the format is available
389    * we must ask the the driver to render the data to the clipboard cache.
390    */
391   if ( !USER_Driver.pIsSelectionOwner() 
392        && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) )
393   {
394     if ( !USER_Driver.pGetClipboardData( lpFormat->wFormatID ) )
395       return FALSE;
396   }
397   /*
398    * If Wine owns the clipboard, and the data is marked for delayed render,
399    * render it now.
400    */
401   else if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
402   {
403     if( IsWindow(hWndClipOwner) )
404     {
405       /* Send a WM_RENDERFORMAT message to notify the owner to render the
406        * data requested into the clipboard.
407        */
408       TRACE("Sending WM_RENDERFORMAT message\n");
409       SendMessage16(hWndClipOwner,WM_RENDERFORMAT,
410                     (WPARAM16)lpFormat->wFormatID,0L);
411     }
412     else
413     {
414       WARN("\thWndClipOwner (%04x) is lost!\n", 
415            hWndClipOwner);
416       CLIPBOARD_ReleaseOwner();
417       lpFormat->wDataPresent = 0;
418       return FALSE;
419     }
420   }
421
422   return (lpFormat->hData16 || lpFormat->hData32) ? TRUE : FALSE;
423 }
424
425
426 /**************************************************************************
427  *                      CLIPBOARD_RenderText
428  *
429  * Renders text to the clipboard buffer converting between UNIX and DOS formats.
430  *
431  * RETURNS: pointer to the WINE_CLIPFORMAT if successful, NULL otherwise
432  *
433  * FIXME: Should be a pair of driver functions that convert between OEM text and Windows.
434  *
435  */
436 static LPWINE_CLIPFORMAT CLIPBOARD_RenderText( UINT wFormat )
437 {
438     LPWINE_CLIPFORMAT lpSource = ClipFormats; 
439     LPWINE_CLIPFORMAT lpTarget;
440     
441     /* Asked for CF_TEXT and not available - always attempt to convert from CF_OEM_TEXT */
442     if( wFormat == CF_TEXT && !ClipFormats[CF_TEXT-1].wDataPresent )
443     {
444         /* Convert OEMTEXT -> TEXT */
445         lpSource = &ClipFormats[CF_OEMTEXT-1];
446         lpTarget = &ClipFormats[CF_TEXT-1];
447
448         TRACE("\tOEMTEXT -> TEXT\n");
449     }
450     /* Asked for CF_OEM_TEXT, and CF_TEXT available */
451     else if( wFormat == CF_OEMTEXT && !ClipFormats[CF_OEMTEXT-1].wDataPresent
452                                    &&  ClipFormats[CF_TEXT-1].wDataPresent )
453     {
454         /* Convert TEXT -> OEMTEXT */
455         lpSource = &ClipFormats[CF_TEXT-1];
456         lpTarget = &ClipFormats[CF_OEMTEXT-1];
457         
458         TRACE("\tTEXT -> OEMTEXT\n");
459     }
460     /* Text format requested is available - no conversion necessary */
461     else
462     {
463         lpSource = __lookup_format( ClipFormats, wFormat );
464         lpTarget = lpSource;
465     }
466
467     /* First render the source text format */
468     if ( !lpSource || !CLIPBOARD_RenderFormat(lpSource) ) return NULL;
469
470     /* Convert to the desired target text format, if necessary */
471     if( lpTarget != lpSource && !lpTarget->hData16 && !lpTarget->hData32 )
472     {
473         UINT16 size;
474         LPCSTR lpstrS; 
475         LPSTR  lpstrT;
476     
477         if (lpSource->hData32)
478         {
479           size = GlobalSize( lpSource->hData32 );
480           lpstrS = (LPSTR)GlobalLock(lpSource->hData32);
481         }
482         else
483         {
484           size = GlobalSize16( lpSource->hData16 );
485           lpstrS = (LPSTR)GlobalLock16(lpSource->hData16);
486         }
487     
488         if( !lpstrS ) return NULL;
489         TRACE("\tconverting from '%s' to '%s', %i chars\n",
490                                           lpSource->Name, lpTarget->Name, size);
491     
492         lpTarget->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, size);
493         lpstrT = (LPSTR)GlobalLock(lpTarget->hData32);
494     
495         if( lpstrT )
496         {
497             if( lpSource->wFormatID == CF_TEXT )
498                 CharToOemBuffA(lpstrS, lpstrT, size);
499             else
500                 OemToCharBuffA(lpstrS, lpstrT, size);
501             TRACE("\tgot %s\n", lpstrT);
502             GlobalUnlock(lpTarget->hData32);
503         }
504         else
505             lpTarget->hData32 = 0;
506
507         /* Unlock source */
508         if (lpSource->hData32)
509           GlobalUnlock(lpSource->hData32);
510         else
511           GlobalUnlock16(lpSource->hData16);
512     }
513
514     return (lpTarget->hData16 || lpTarget->hData32) ? lpTarget : NULL;
515 }
516
517 /**************************************************************************
518  *                WIN32 Clipboard implementation 
519  **************************************************************************/
520
521 /**************************************************************************
522  *            OpenClipboard16   (USER.137)
523  */
524 BOOL16 WINAPI OpenClipboard16( HWND16 hWnd )
525 {
526     return OpenClipboard( hWnd );
527 }
528
529
530 /**************************************************************************
531  *            OpenClipboard   (USER32.407)
532  *
533  * Note: Netscape uses NULL hWnd to open the clipboard.
534  */
535 BOOL WINAPI OpenClipboard( HWND hWnd )
536 {
537     BOOL bRet;
538
539     TRACE("(%04x)...\n", hWnd);
540
541     if (!hClipLock)
542     {
543         hClipLock = GetCurrentTask();
544
545         /* Save current user of the clipboard */
546         hWndClipWindow = hWnd;
547         bCBHasChanged = FALSE;
548         bRet = TRUE;
549     }
550     else bRet = FALSE;
551
552     TRACE("   returning %i\n", bRet);
553     return bRet;
554 }
555
556
557 /**************************************************************************
558  *            CloseClipboard16   (USER.138)
559  */
560 BOOL16 WINAPI CloseClipboard16(void)
561 {
562     return CloseClipboard();
563 }
564
565
566 /**************************************************************************
567  *            CloseClipboard   (USER32.54)
568  */
569 BOOL WINAPI CloseClipboard(void)
570 {
571     TRACE("()\n");
572
573     if (hClipLock == GetCurrentTask())
574     {
575         hWndClipWindow = 0;
576
577         if (bCBHasChanged && hWndViewer) 
578             SendMessage16(hWndViewer, WM_DRAWCLIPBOARD, 0, 0L);
579         hClipLock = 0;
580     }
581     return TRUE;
582 }
583
584
585 /**************************************************************************
586  *            EmptyClipboard16   (USER.139)
587  */
588 BOOL16 WINAPI EmptyClipboard16(void)
589 {
590     return EmptyClipboard();
591 }
592
593
594 /**************************************************************************
595  *            EmptyClipboard   (USER32.169)
596  *  Empties and acquires ownership of the clipboard
597  */
598 BOOL WINAPI EmptyClipboard(void)
599 {
600     TRACE("()\n");
601
602     if (hClipLock != GetCurrentTask())
603     {
604         WARN("Clipboard not opened by calling task!");
605         return FALSE;
606     }
607     
608     /* destroy private objects */
609
610     if (hWndClipOwner)
611         SendMessage16(hWndClipOwner, WM_DESTROYCLIPBOARD, 0, 0L);
612
613     /* empty the cache */
614     CLIPBOARD_EmptyCache(TRUE);
615
616     /* Assign ownership of the clipboard to the current client */
617     hWndClipOwner = hWndClipWindow;
618
619     /* Save the current task */
620     hTaskClipOwner = GetCurrentTask();
621     
622     /* Tell the driver to acquire the selection */
623     USER_Driver.pAcquireClipboard();
624
625     return TRUE;
626 }
627
628
629 /**************************************************************************
630  *            GetClipboardOwner16   (USER.140)
631  *  FIXME: Can't return the owner if the clipbard is owned by an external app
632  */
633 HWND16 WINAPI GetClipboardOwner16(void)
634 {
635     TRACE("()\n");
636     return hWndClipOwner;
637 }
638
639
640 /**************************************************************************
641  *            GetClipboardOwner   (USER32.225)
642  *  FIXME: Can't return the owner if the clipbard is owned by an external app
643  */
644 HWND WINAPI GetClipboardOwner(void)
645 {
646     TRACE("()\n");
647     return hWndClipOwner;
648 }
649
650
651 /**************************************************************************
652  *            SetClipboardData16   (USER.141)
653  */
654 HANDLE16 WINAPI SetClipboardData16( UINT16 wFormat, HANDLE16 hData )
655 {
656     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
657
658     TRACE("(%04X, %04x) !\n", wFormat, hData);
659
660     /* NOTE: If the hData is zero and current owner doesn't match
661      * the window that opened the clipboard then this application
662      * is screwed because WM_RENDERFORMAT will go to the owner.
663      * (to become the owner it must call EmptyClipboard() before
664      *  adding new data).
665      */
666
667     if( CLIPBOARD_IsLocked() || !lpFormat ||
668         (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
669     {
670         WARN("Invalid hData or clipboard not opened by calling task!\n");
671         return 0;
672     }
673
674     /* Pass on the request to the driver */
675     USER_Driver.pSetClipboardData(wFormat);
676
677     if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 ) 
678     {
679         CLIPBOARD_DeleteRecord(lpFormat, TRUE);
680
681         /* delete existing CF_TEXT/CF_OEMTEXT aliases */
682
683         if( wFormat == CF_TEXT 
684             && ( ClipFormats[CF_OEMTEXT-1].hData16 
685                  ||  ClipFormats[CF_OEMTEXT-1].hData32 )
686             && !ClipFormats[CF_OEMTEXT-1].wDataPresent )
687             CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
688         if( wFormat == CF_OEMTEXT 
689             && ( ClipFormats[CF_OEMTEXT-1].hData16 
690                  ||  ClipFormats[CF_OEMTEXT-1].hData32 )
691             && !ClipFormats[CF_TEXT-1].wDataPresent )
692             CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
693     }
694
695     bCBHasChanged = TRUE;
696     lpFormat->wDataPresent = 1;
697     lpFormat->hData16 = hData;          /* 0 is legal, see WM_RENDERFORMAT */
698     lpFormat->hData32 = 0;
699
700     return lpFormat->hData16;
701 }
702
703
704 /**************************************************************************
705  *            SetClipboardData   (USER32.470)
706  */
707 HANDLE WINAPI SetClipboardData( UINT wFormat, HANDLE hData )
708 {
709     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
710
711     TRACE("(%08X, %08x) !\n", wFormat, hData);
712
713     /* NOTE: If the hData is zero and current owner doesn't match
714      * the window that opened the clipboard then this application
715      * is screwed because WM_RENDERFORMAT will go to the owner.
716      * (to become the owner it must call EmptyClipboard() before
717      *  adding new data).
718      */
719
720     if( CLIPBOARD_IsLocked() || !lpFormat ||
721         (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
722     {
723         WARN("Invalid hData or clipboard not opened by calling task!\n");
724         return 0;
725     }
726
727     /* Tell the driver to acquire the selection */
728     USER_Driver.pAcquireClipboard();
729
730     if ( lpFormat->wDataPresent &&
731          (lpFormat->hData16 || lpFormat->hData32) )
732     {
733         CLIPBOARD_DeleteRecord(lpFormat, TRUE);
734
735         /* delete existing CF_TEXT/CF_OEMTEXT aliases */
736
737         if( wFormat == CF_TEXT 
738             && ( ClipFormats[CF_OEMTEXT-1].hData16 
739                  ||  ClipFormats[CF_OEMTEXT-1].hData32 )
740             && !ClipFormats[CF_OEMTEXT-1].wDataPresent )
741             CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
742         if( wFormat == CF_OEMTEXT 
743             && ( ClipFormats[CF_OEMTEXT-1].hData16 
744                  ||  ClipFormats[CF_OEMTEXT-1].hData32 )
745             && !ClipFormats[CF_TEXT-1].wDataPresent )
746             CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
747     }
748
749     bCBHasChanged = TRUE;
750     lpFormat->wDataPresent = 1;
751     lpFormat->hDataSrc32 = hData;  /* Save the source handle */
752
753     /*
754      * Make a shared duplicate if the memory is not shared
755      * TODO: What should be done for non-memory objects
756      */
757     if ( CLIPBOARD_IsMemoryObject(wFormat) && hData && !(GlobalFlags(hData) & GMEM_DDESHARE) )
758         lpFormat->hData32 = CLIPBOARD_GlobalDupMem( hData );
759     else
760         lpFormat->hData32 = hData;          /* 0 is legal, see WM_RENDERFORMAT */
761     
762     lpFormat->hData16 = 0;
763
764     return lpFormat->hData32;   /* Should we return lpFormat->hDataSrc32 */
765 }
766
767
768 /**************************************************************************
769  *             GetClipboardData16   (USER.142)
770  */
771 HANDLE16 WINAPI GetClipboardData16( UINT16 wFormat )
772 {
773     LPWINE_CLIPFORMAT lpRender = ClipFormats; 
774
775     TRACE("(%04X)\n", wFormat);
776
777     if (CLIPBOARD_IsLocked())
778     {
779         WARN("Clipboard not opened by calling task!\n");
780         return 0;
781     }
782
783     if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
784     {
785         lpRender = CLIPBOARD_RenderText(wFormat);
786         if ( !lpRender ) return 0;
787     }
788     else
789     {
790         lpRender = __lookup_format( ClipFormats, wFormat );
791         if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
792     }
793    
794     /* Convert between 32 -> 16 bit data, if necessary */
795     if( lpRender->hData32 && !lpRender->hData16
796         && CLIPBOARD_IsMemoryObject(wFormat) )
797     {
798       int size;
799       if( lpRender->wFormatID == CF_METAFILEPICT )
800         size = sizeof( METAFILEPICT16 );
801       else
802           size = GlobalSize(lpRender->hData32);
803       
804       lpRender->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);
805       if( !lpRender->hData16 )
806         ERR("(%04X) -- not enough memory in 16b heap\n", wFormat);
807       else
808       {
809         if( lpRender->wFormatID == CF_METAFILEPICT )
810         {
811           FIXME("\timplement function CopyMetaFilePict32to16\n");
812           FIXME("\tin the appropriate file.\n");
813   #ifdef SOMEONE_IMPLEMENTED_ME
814           CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16), 
815                                   GlobalLock(lpRender->hData32) );
816   #endif
817         }
818         else
819         {
820           memcpy( GlobalLock16(lpRender->hData16), 
821                   GlobalLock(lpRender->hData32), 
822                   size );
823         }
824         GlobalUnlock16(lpRender->hData16);
825         GlobalUnlock(lpRender->hData32);
826       }
827     }
828
829     TRACE("\treturning %04x (type %i)\n", 
830                               lpRender->hData16, lpRender->wFormatID);
831     return lpRender->hData16;
832 }
833
834
835 /**************************************************************************
836  *             GetClipboardData   (USER32.222)
837  */
838 HANDLE WINAPI GetClipboardData( UINT wFormat )
839 {
840     LPWINE_CLIPFORMAT lpRender = ClipFormats; 
841
842     TRACE("(%08X)\n", wFormat);
843
844     if (CLIPBOARD_IsLocked())
845     {
846         WARN("Clipboard not opened by calling task!");
847         return 0;
848     }
849
850     if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
851     {
852         lpRender = CLIPBOARD_RenderText(wFormat);
853         if ( !lpRender ) return 0;
854     }
855     else
856     {
857         lpRender = __lookup_format( ClipFormats, wFormat );
858         if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
859     }
860    
861     /* Convert between 16 -> 32 bit data, if necessary */
862     if( lpRender->hData16 && !lpRender->hData32
863         && CLIPBOARD_IsMemoryObject(wFormat) )
864     {
865       int size;
866       if( lpRender->wFormatID == CF_METAFILEPICT )
867         size = sizeof( METAFILEPICT );
868       else
869         size = GlobalSize16(lpRender->hData16);
870       lpRender->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE,
871                                       size);
872       if( lpRender->wFormatID == CF_METAFILEPICT )
873       {
874         FIXME("\timplement function CopyMetaFilePict16to32\n");
875         FIXME("\tin the appropriate file.\n");
876 #ifdef SOMEONE_IMPLEMENTED_ME
877         CopyMetaFilePict16to32( GlobalLock16(lpRender->hData32), 
878                                 GlobalLock(lpRender->hData16) );
879 #endif
880       }
881       else
882       {
883         memcpy( GlobalLock(lpRender->hData32), 
884                 GlobalLock16(lpRender->hData16), 
885                 size );
886       }
887       GlobalUnlock(lpRender->hData32);
888       GlobalUnlock16(lpRender->hData16);
889     }
890
891     TRACE("\treturning %04x (type %i)\n", 
892                               lpRender->hData32, lpRender->wFormatID);
893     return lpRender->hData32;
894 }
895
896
897 /**************************************************************************
898  *           CountClipboardFormats16   (USER.143)
899  */
900 INT16 WINAPI CountClipboardFormats16(void)
901 {
902     return CountClipboardFormats();
903 }
904
905
906 /**************************************************************************
907  *           CountClipboardFormats   (USER32.63)
908  */
909 INT WINAPI CountClipboardFormats(void)
910 {
911     INT FormatCount = 0;
912     LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
913
914     TRACE("()\n");
915
916     while(TRUE) 
917     {
918         if (lpFormat == NULL) break;
919
920         if( lpFormat->wFormatID != CF_TEXT ) /* Don't count CF_TEXT */
921         {
922           /*
923            * The format is available if either:
924            * 1. The data is already in the cache.
925            * 2. The selection is not owned by us(WINE) and the data is
926            *    available to the clipboard driver.
927            */
928           if ( lpFormat->wDataPresent ||
929                ( !USER_Driver.pIsSelectionOwner()
930                  && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) ) )
931           {
932               TRACE("\tdata found for format 0x%04x(%s)\n",
933                     lpFormat->wFormatID, CLIPBOARD_GetFormatName(lpFormat->wFormatID));
934               FormatCount++;
935           }
936         }
937
938         lpFormat = lpFormat->NextFormat;
939     }
940
941     /* these two are equivalent, adjust the total */
942
943     FormatCount += abs(ClipFormats[CF_TEXT-1].wDataPresent -
944                        ClipFormats[CF_OEMTEXT-1].wDataPresent);
945
946     TRACE("\ttotal %d\n", FormatCount);
947     return FormatCount;
948 }
949
950
951 /**************************************************************************
952  *            EnumClipboardFormats16   (USER.144)
953  */
954 UINT16 WINAPI EnumClipboardFormats16( UINT16 wFormat )
955 {
956     return EnumClipboardFormats( wFormat );
957 }
958
959
960 /**************************************************************************
961  *            EnumClipboardFormats   (USER32.179)
962  */
963 UINT WINAPI EnumClipboardFormats( UINT wFormat )
964 {
965     LPWINE_CLIPFORMAT lpFormat = ClipFormats;
966     BOOL bFormatPresent;
967
968     TRACE("(%04X)\n", wFormat);
969
970     if (CLIPBOARD_IsLocked())
971     {
972         WARN("Clipboard not opened by calling task!");
973         return 0;
974     }
975
976     if (wFormat == 0) /* start from the beginning */
977         lpFormat = ClipFormats;
978     else
979     {
980         /* walk up to the specified format record */
981
982         if( !(lpFormat = __lookup_format( lpFormat, wFormat )) ) 
983             return 0;
984         lpFormat = lpFormat->NextFormat; /* right */
985     }
986
987     while(TRUE) 
988     {
989         if (lpFormat == NULL) return 0;
990
991         /* Synthesize CF_TEXT from CF_OEMTEXT and vice versa */
992         bFormatPresent = (lpFormat->wDataPresent ||
993            (lpFormat->wFormatID == CF_OEMTEXT && ClipFormats[CF_TEXT-1].wDataPresent) ||
994            (lpFormat->wFormatID == CF_TEXT && ClipFormats[CF_OEMTEXT-1].wDataPresent) );
995
996         /* Query the driver if not yet in the cache */
997         if (!bFormatPresent && !USER_Driver.pIsSelectionOwner())
998         {
999             bFormatPresent =
1000                USER_Driver.pIsClipboardFormatAvailable( (lpFormat->wFormatID == CF_TEXT) ?
1001                                                       CF_OEMTEXT : lpFormat->wFormatID );
1002         }
1003
1004         if (bFormatPresent)
1005             break;
1006
1007         lpFormat = lpFormat->NextFormat;
1008     }
1009
1010     return lpFormat->wFormatID;
1011 }
1012
1013
1014 /**************************************************************************
1015  *            RegisterClipboardFormat16  (USER.145)
1016  */
1017 UINT16 WINAPI RegisterClipboardFormat16( LPCSTR FormatName )
1018 {
1019     LPWINE_CLIPFORMAT lpNewFormat; 
1020     LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
1021
1022     if (FormatName == NULL) return 0;
1023
1024     TRACE("('%s') !\n", FormatName);
1025
1026     /* walk format chain to see if it's already registered */
1027
1028     while(TRUE) 
1029     {
1030         if ( !strcmp(lpFormat->Name,FormatName) )
1031         {
1032              lpFormat->wRefCount++;
1033              return lpFormat->wFormatID;
1034         }
1035  
1036         if ( lpFormat->NextFormat == NULL ) break;
1037
1038         lpFormat = lpFormat->NextFormat;
1039     }
1040
1041     /* allocate storage for new format entry */
1042
1043     lpNewFormat = (LPWINE_CLIPFORMAT)HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPFORMAT));
1044     if(lpNewFormat == NULL) {
1045         WARN("No more memory for a new format!");
1046         return 0;
1047     }
1048     lpFormat->NextFormat = lpNewFormat;
1049     lpNewFormat->wFormatID = LastRegFormat;
1050     lpNewFormat->wRefCount = 1;
1051
1052     lpNewFormat->Name = (LPSTR)HEAP_strdupA(GetProcessHeap(), 0, FormatName);
1053     if(lpNewFormat->Name == NULL) {
1054         WARN("No more memory for the new format name!");
1055         HeapFree(GetProcessHeap(), 0, lpNewFormat);
1056         return 0;
1057     }
1058
1059     lpNewFormat->wDataPresent = 0;
1060     lpNewFormat->hData16 = 0;
1061     lpNewFormat->hDataSrc32 = 0;
1062     lpNewFormat->hData32 = 0;
1063     lpNewFormat->drvData = 0;
1064     lpNewFormat->PrevFormat = lpFormat;
1065     lpNewFormat->NextFormat = NULL;
1066
1067     /* Pass on the registration request to the driver */
1068     USER_Driver.pRegisterClipboardFormat( FormatName );
1069     
1070     return LastRegFormat++;
1071 }
1072
1073
1074 /**************************************************************************
1075  *            RegisterClipboardFormatA   (USER32.431)
1076  */
1077 UINT WINAPI RegisterClipboardFormatA( LPCSTR formatName )
1078 {
1079     return RegisterClipboardFormat16( formatName );
1080 }
1081
1082
1083 /**************************************************************************
1084  *            RegisterClipboardFormatW   (USER32.432)
1085  */
1086 UINT WINAPI RegisterClipboardFormatW( LPCWSTR formatName )
1087 {
1088     LPSTR aFormat = HEAP_strdupWtoA( GetProcessHeap(), 0, formatName );
1089     UINT ret = RegisterClipboardFormatA( aFormat );
1090     HeapFree( GetProcessHeap(), 0, aFormat );
1091     return ret;
1092 }
1093
1094
1095 /**************************************************************************
1096  *            GetClipboardFormatName16   (USER.146)
1097  */
1098 INT16 WINAPI GetClipboardFormatName16( UINT16 wFormat, LPSTR retStr, INT16 maxlen )
1099 {
1100     return GetClipboardFormatNameA( wFormat, retStr, maxlen );
1101 }
1102
1103
1104 /**************************************************************************
1105  *            GetClipboardFormatNameA   (USER32.223)
1106  */
1107 INT WINAPI GetClipboardFormatNameA( UINT wFormat, LPSTR retStr, INT maxlen )
1108 {
1109     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
1110
1111     TRACE("(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
1112
1113     if (lpFormat == NULL || lpFormat->Name == NULL || 
1114         lpFormat->wFormatID < CF_REGFORMATBASE) return 0;
1115
1116     TRACE("Name='%s' !\n", lpFormat->Name);
1117
1118     lstrcpynA( retStr, lpFormat->Name, maxlen );
1119     return strlen(retStr);
1120 }
1121
1122
1123 /**************************************************************************
1124  *            GetClipboardFormatNameW   (USER32.224)
1125  */
1126 INT WINAPI GetClipboardFormatNameW( UINT wFormat, LPWSTR retStr, INT maxlen )
1127 {
1128     INT ret;
1129     LPSTR p = HeapAlloc( GetProcessHeap(), 0, maxlen );
1130     if(p == NULL) return 0; /* FIXME: is this the correct failure value? */
1131     
1132     ret = GetClipboardFormatNameA( wFormat, p, maxlen );
1133     lstrcpynAtoW( retStr, p, maxlen );
1134     HeapFree( GetProcessHeap(), 0, p );
1135     return ret;
1136 }
1137
1138
1139 /**************************************************************************
1140  *            SetClipboardViewer16   (USER.147)
1141  */
1142 HWND16 WINAPI SetClipboardViewer16( HWND16 hWnd )
1143 {
1144     TRACE("(%04x)\n", hWnd);
1145     return SetClipboardViewer( hWnd );
1146 }
1147
1148
1149 /**************************************************************************
1150  *            SetClipboardViewer   (USER32.471)
1151  */
1152 HWND WINAPI SetClipboardViewer( HWND hWnd )
1153 {
1154     HWND hwndPrev = hWndViewer;
1155
1156     TRACE("(%04x): returning %04x\n", hWnd, hwndPrev);
1157
1158     hWndViewer = hWnd;
1159     return hwndPrev;
1160 }
1161
1162
1163 /**************************************************************************
1164  *           GetClipboardViewer16   (USER.148)
1165  */
1166 HWND16 WINAPI GetClipboardViewer16(void)
1167 {
1168     TRACE("()\n");
1169     return hWndViewer;
1170 }
1171
1172
1173 /**************************************************************************
1174  *           GetClipboardViewer   (USER32.226)
1175  */
1176 HWND WINAPI GetClipboardViewer(void)
1177 {
1178     TRACE("()\n");
1179     return hWndViewer;
1180 }
1181
1182
1183 /**************************************************************************
1184  *           ChangeClipboardChain16   (USER.149)
1185  */
1186 BOOL16 WINAPI ChangeClipboardChain16(HWND16 hWnd, HWND16 hWndNext)
1187 {
1188     return ChangeClipboardChain(hWnd, hWndNext);
1189 }
1190
1191
1192 /**************************************************************************
1193  *           ChangeClipboardChain   (USER32.22)
1194  */
1195 BOOL WINAPI ChangeClipboardChain(HWND hWnd, HWND hWndNext)
1196 {
1197     BOOL bRet = 0;
1198
1199     FIXME("(0x%04x, 0x%04x): stub?\n", hWnd, hWndNext);
1200
1201     if( hWndViewer )
1202         bRet = !SendMessage16( hWndViewer, WM_CHANGECBCHAIN,
1203                              (WPARAM16)hWnd, (LPARAM)hWndNext);   
1204     else
1205         WARN("hWndViewer is lost\n");
1206
1207     if( hWnd == hWndViewer ) hWndViewer = hWndNext;
1208
1209     return bRet;
1210 }
1211
1212
1213 /**************************************************************************
1214  *           IsClipboardFormatAvailable16   (USER.193)
1215  */
1216 BOOL16 WINAPI IsClipboardFormatAvailable16( UINT16 wFormat )
1217 {
1218     return IsClipboardFormatAvailable( wFormat );
1219 }
1220
1221
1222 /**************************************************************************
1223  *           IsClipboardFormatAvailable   (USER32.340)
1224  */
1225 BOOL WINAPI IsClipboardFormatAvailable( UINT wFormat )
1226 {
1227     BOOL bRet;
1228
1229     if (wFormat == 0)  /* Reject this case quickly */
1230         bRet = FALSE;
1231
1232     /* If WINE is not the clipboard selection owner ask the clipboard driver */
1233     else if ( !USER_Driver.pIsSelectionOwner() )
1234         bRet = USER_Driver.pIsClipboardFormatAvailable( (wFormat == CF_TEXT) ?
1235                                                      CF_OEMTEXT : wFormat );
1236     /* Check if the format is in the local cache */
1237     else 
1238         bRet = CLIPBOARD_IsPresent(wFormat);
1239
1240     TRACE("(%04X)- ret(%d)\n", wFormat, bRet);
1241     return bRet;
1242 }
1243
1244
1245 /**************************************************************************
1246  *             GetOpenClipboardWindow16   (USER.248)
1247  *  FIXME: This wont work if an external app owns the selection
1248  */
1249 HWND16 WINAPI GetOpenClipboardWindow16(void)
1250 {
1251     TRACE("()\n");
1252     return hWndClipWindow;
1253 }
1254
1255
1256 /**************************************************************************
1257  *             GetOpenClipboardWindow   (USER32.277)
1258  *  FIXME: This wont work if an external app owns the selection
1259  */
1260 HWND WINAPI GetOpenClipboardWindow(void)
1261 {
1262     TRACE("()\n");
1263     return hWndClipWindow;
1264 }
1265
1266
1267 /**************************************************************************
1268  *             GetPriorityClipboardFormat16   (USER.402)
1269  */
1270 INT16 WINAPI GetPriorityClipboardFormat16( UINT16 *lpPriorityList, INT16 nCount)
1271 {
1272     FIXME("(%p,%d): stub\n", lpPriorityList, nCount );
1273     return 0;
1274 }
1275
1276
1277 /**************************************************************************
1278  *             GetPriorityClipboardFormat   (USER32.279)
1279  */
1280 INT WINAPI GetPriorityClipboardFormat( UINT *lpPriorityList, INT nCount )
1281 {
1282     int Counter;
1283     TRACE("()\n");
1284
1285     if(CountClipboardFormats() == 0) 
1286     { 
1287         return 0;
1288     }
1289
1290     for(Counter = 0; Counter <= nCount; Counter++)
1291     {
1292         if(IsClipboardFormatAvailable(*(lpPriorityList+sizeof(INT)*Counter)))
1293             return *(lpPriorityList+sizeof(INT)*Counter);
1294     }
1295
1296     return -1;
1297 }
1298