Add some new messages to the spy and winuser.h.
[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
17 #include <stdlib.h>
18 #include <sys/types.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <string.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "wine/winuser16.h"
28 #include "wine/winbase16.h"
29 #include "heap.h"
30 #include "user.h"
31 #include "win.h"
32 #include "clipboard.h"
33 #include "debugtools.h"
34
35 DEFAULT_DEBUG_CHANNEL(clipboard);
36
37 #define  CF_REGFORMATBASE       0xC000
38
39 /**************************************************************************
40  *        Clipboard context global variables
41  */
42
43 static HANDLE hClipLock   = 0;
44 static BOOL bCBHasChanged  = FALSE;
45
46 static HWND hWndClipWindow;        /* window that last opened clipboard */
47 static HWND hWndClipOwner;         /* current clipboard owner */
48 static HANDLE16 hTaskClipOwner;    /* clipboard owner's task  */
49 static HWND hWndViewer;            /* start of viewers chain */
50
51 static WORD LastRegFormat = CF_REGFORMATBASE;
52
53 /* Clipboard cache initial data.
54  * WARNING: This data ordering is dependent on the WINE_CLIPFORMAT structure
55  * declared in clipboard.h
56  */
57 WINE_CLIPFORMAT ClipFormats[]  = {
58     { CF_TEXT, 1, 0, "Text",  0, 0, 0, 0, NULL, &ClipFormats[1]},
59     { CF_BITMAP, 1, 0, "Bitmap", 0, 0, 0, 0, &ClipFormats[0], &ClipFormats[2]},
60     { CF_METAFILEPICT, 1, 0, "MetaFile Picture", 0, 0, 0, 0, &ClipFormats[1], &ClipFormats[3]},
61     { CF_SYLK, 1, 0, "Sylk", 0, 0, 0, 0, &ClipFormats[2], &ClipFormats[4]},
62     { CF_DIF, 1, 0, "DIF", 0, 0, 0, 0, &ClipFormats[3], &ClipFormats[5]},
63     { CF_TIFF, 1, 0, "TIFF", 0, 0, 0, 0, &ClipFormats[4], &ClipFormats[6]},
64     { CF_OEMTEXT, 1, 0, "OEM Text", 0, 0, 0, 0, &ClipFormats[5], &ClipFormats[7]},
65     { CF_DIB, 1, 0, "DIB", 0, 0, 0, 0, &ClipFormats[6], &ClipFormats[8]},
66     { CF_PALETTE, 1, 0, "Palette", 0, 0, 0, 0, &ClipFormats[7], &ClipFormats[9]},
67     { CF_PENDATA, 1, 0, "PenData", 0, 0, 0, 0, &ClipFormats[8], &ClipFormats[10]},
68     { CF_RIFF, 1, 0, "RIFF", 0, 0, 0, 0, &ClipFormats[9], &ClipFormats[11]},
69     { CF_WAVE, 1, 0, "Wave", 0, 0, 0, 0, &ClipFormats[10], &ClipFormats[12]},
70     { CF_UNICODETEXT, 1, 0, "Unicode Text", 0, 0, 0, 0, &ClipFormats[11], &ClipFormats[13]},
71     { CF_OWNERDISPLAY, 1, 0, "Owner Display", 0, 0, 0, 0, &ClipFormats[12], &ClipFormats[14]},
72     { CF_DSPTEXT, 1, 0, "DSPText", 0, 0, 0, 0, &ClipFormats[13], &ClipFormats[15]},
73     { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", 0, 0, 0, 0, &ClipFormats[14], &ClipFormats[16]},
74     { CF_DSPBITMAP, 1, 0, "DSPBitmap", 0, 0, 0, 0, &ClipFormats[15], &ClipFormats[17]},
75     { CF_HDROP, 1, 0, "HDROP", 0, 0, 0, 0, &ClipFormats[16], NULL}
76 };
77
78
79 /**************************************************************************
80  *                Internal Clipboard implementation methods
81  **************************************************************************/
82
83
84 /**************************************************************************
85  *                      CLIPBOARD_LookupFormat
86  */
87 static LPWINE_CLIPFORMAT __lookup_format( LPWINE_CLIPFORMAT lpFormat, WORD wID )
88 {
89     while(TRUE)
90     {
91         if (lpFormat == NULL ||
92             lpFormat->wFormatID == wID) break;
93         lpFormat = lpFormat->NextFormat;
94     }
95     return lpFormat;
96 }
97
98 LPWINE_CLIPFORMAT CLIPBOARD_LookupFormat( WORD wID )
99 {
100   return __lookup_format( ClipFormats, wID );
101 }
102
103 /**************************************************************************
104  *                      CLIPBOARD_IsLocked
105  *  Check if the clipboard cache is available to the caller
106  */
107 BOOL CLIPBOARD_IsLocked()
108 {
109   BOOL bIsLocked = TRUE;
110   HANDLE16 hTaskCur = GetCurrentTask();
111
112   /*
113    * The clipboard is available:
114    * 1. if the caller's task has opened the clipboard,
115    * or
116    * 2. if the caller is the clipboard owners task, AND is responding to a
117    *    WM_RENDERFORMAT message.
118    */
119   if ( hClipLock == hTaskCur )
120       bIsLocked = FALSE;
121       
122   else if ( hTaskCur == hTaskClipOwner )
123   {
124       /* Check if we're currently executing inside a window procedure
125        * called in response to a WM_RENDERFORMAT message. A WM_RENDERFORMAT
126        * handler is not permitted to open the clipboard since it has been opened
127        * by another client. However the handler must have access to the
128        * clipboard in order to update data in response to this message.
129        */
130 #if 0
131       MESSAGEQUEUE *queue = QUEUE_Current();
132       
133       if ( queue
134            && queue->smWaiting
135            && queue->smWaiting->msg == WM_RENDERFORMAT
136            && queue->smWaiting->hSrcQueue
137          )
138         bIsLocked = FALSE;
139 #else
140       /* FIXME: queue check no longer possible */
141       bIsLocked = FALSE;
142 #endif
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 || wFormat == CF_UNICODETEXT )
280         return ClipFormats[CF_TEXT-1].wDataPresent ||
281                ClipFormats[CF_OEMTEXT-1].wDataPresent ||
282                ClipFormats[CF_UNICODETEXT-1].wDataPresent;
283     else
284     {
285         LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
286         if( lpFormat ) return (lpFormat->wDataPresent);
287     }
288     return FALSE;
289 }
290
291 /**************************************************************************
292  *                      CLIPBOARD_IsCacheRendered
293  *  Checks if any data needs to be rendered to the clipboard cache
294  *  RETURNS:
295  *    TRUE  - All clipboard data is available in the cache
296  *    FALSE - Some data is marked for delayed render and needs rendering
297  */
298 BOOL CLIPBOARD_IsCacheRendered()
299 {
300     LPWINE_CLIPFORMAT lpFormat = ClipFormats;
301     
302     /* check if all formats were rendered */
303     while(lpFormat)
304     {
305         if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
306             return FALSE;
307         
308         lpFormat = lpFormat->NextFormat;
309     }
310     
311     return TRUE;
312 }
313
314
315 /**************************************************************************
316  *                      CLIPBOARD_IsMemoryObject
317  *  Tests if the clipboard format specifies a memory object
318  */
319 BOOL CLIPBOARD_IsMemoryObject( WORD wFormat )
320 {
321     switch(wFormat)
322     {
323         case CF_BITMAP:
324         case CF_METAFILEPICT:
325         case CF_DSPTEXT:
326         case CF_ENHMETAFILE:
327         case CF_HDROP:
328         case CF_PALETTE:
329         case CF_PENDATA:
330             return FALSE;
331         default:
332             return TRUE;
333      }
334 }
335
336 /***********************************************************************
337  * CLIPBOARD_GlobalDupMem( HGLOBAL )
338  * Helper method to duplicate an HGLOBAL chunk of memory into shared memory
339  */
340 HGLOBAL CLIPBOARD_GlobalDupMem( HGLOBAL hGlobalSrc )
341 {
342     HGLOBAL hGlobalDest;
343     PVOID pGlobalSrc, pGlobalDest;
344     DWORD cBytes;
345     
346     if ( !hGlobalSrc )
347       return 0;
348
349     cBytes = GlobalSize(hGlobalSrc);
350     if ( 0 == cBytes )
351       return 0;
352
353     /* Turn on the DDESHARE and _MOVEABLE flags explicitly */
354     hGlobalDest = GlobalAlloc( GlobalFlags(hGlobalSrc) | GMEM_DDESHARE | GMEM_MOVEABLE,
355                                cBytes );
356     if ( !hGlobalDest )
357       return 0;
358     
359     pGlobalSrc = GlobalLock(hGlobalSrc);
360     pGlobalDest = GlobalLock(hGlobalDest);
361     if ( !pGlobalSrc || !pGlobalDest )
362       return 0;
363
364     memcpy(pGlobalDest, pGlobalSrc, cBytes);
365         
366     GlobalUnlock(hGlobalSrc);
367     GlobalUnlock(hGlobalDest);
368
369     return hGlobalDest;
370 }
371
372 /**************************************************************************
373  *                      CLIPBOARD_GetFormatName
374  *  Gets the format name associated with an ID
375  */
376 char * CLIPBOARD_GetFormatName(UINT wFormat)
377 {
378     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
379     return (lpFormat) ? lpFormat->Name : NULL;
380 }
381
382
383 /**************************************************************************
384  *                      CLIPBOARD_RenderFormat
385  */
386 static BOOL CLIPBOARD_RenderFormat(LPWINE_CLIPFORMAT lpFormat)
387 {
388   /*
389    * If WINE is not the selection owner, and the format is available
390    * we must ask the driver to render the data to the clipboard cache.
391    */
392   TRACE("enter format=%d\n", lpFormat->wFormatID);
393   if ( !USER_Driver.pIsSelectionOwner() 
394        && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) )
395   {
396     if ( !USER_Driver.pGetClipboardData( lpFormat->wFormatID ) )
397       return FALSE;
398   }
399   /*
400    * If Wine owns the clipboard, and the data is marked for delayed render,
401    * render it now.
402    */
403   else if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
404   {
405     if( IsWindow(hWndClipOwner) )
406     {
407       /* Send a WM_RENDERFORMAT message to notify the owner to render the
408        * data requested into the clipboard.
409        */
410       TRACE("Sending WM_RENDERFORMAT message\n");
411       SendMessageW( hWndClipOwner, WM_RENDERFORMAT, (WPARAM)lpFormat->wFormatID, 0 );
412     }
413     else
414     {
415       WARN("\thWndClipOwner (%04x) is lost!\n", 
416            hWndClipOwner);
417       CLIPBOARD_ReleaseOwner();
418       lpFormat->wDataPresent = 0;
419       return FALSE;
420     }
421   }
422
423   return (lpFormat->hData16 || lpFormat->hData32) ? TRUE : FALSE;
424 }
425
426 /**************************************************************************
427  *                      CLIPBOARD_ConvertText
428  * Returns number of required/converted characters - not bytes!
429  */
430 static INT CLIPBOARD_ConvertText(WORD src_fmt, void const *src, INT src_size,
431                                  WORD dst_fmt, void *dst, INT dst_size)
432 {
433     UINT cp;
434
435     if(src_fmt == CF_UNICODETEXT)
436     {
437         switch(dst_fmt)
438         {
439         case CF_TEXT:
440             cp = CP_ACP;
441             break;
442         case CF_OEMTEXT:
443             cp = CP_OEMCP;
444             break;
445         default:
446             return 0;
447         }
448         return WideCharToMultiByte(cp, 0, src, src_size, dst, dst_size, NULL, NULL);
449     }
450
451     if(dst_fmt == CF_UNICODETEXT)
452     {
453         switch(src_fmt)
454         {
455         case CF_TEXT:
456             cp = CP_ACP;
457             break;
458         case CF_OEMTEXT:
459             cp = CP_OEMCP;
460             break;
461         default:
462             return 0;
463         }
464         return MultiByteToWideChar(cp, 0, src, src_size, dst, dst_size);
465     }
466
467     if(!dst_size) return src_size;
468
469     if(dst_size > src_size) dst_size = src_size;
470
471     if(src_fmt == CF_TEXT )
472         CharToOemBuffA(src, dst, dst_size);
473     else
474         OemToCharBuffA(src, dst, dst_size);
475
476     return dst_size;
477 }
478
479 /**************************************************************************
480  *                      CLIPBOARD_RenderText
481  *
482  * Renders text to the clipboard buffer converting between UNIX and DOS formats.
483  *
484  * RETURNS: pointer to the WINE_CLIPFORMAT if successful, NULL otherwise
485  *
486  * FIXME: Should be a pair of driver functions that convert between OEM text and Windows.
487  *
488  */
489 static LPWINE_CLIPFORMAT CLIPBOARD_RenderText( UINT wFormat )
490 {
491     LPWINE_CLIPFORMAT lpSource = ClipFormats; 
492     LPWINE_CLIPFORMAT lpTarget = NULL;
493     BOOL foundData = FALSE;
494  
495     /* Asked for CF_TEXT */
496     if( wFormat == CF_TEXT)
497     {
498         if(ClipFormats[CF_TEXT-1].wDataPresent)
499         {
500             lpSource = &ClipFormats[CF_TEXT-1];
501             lpTarget = &ClipFormats[CF_TEXT-1];
502             foundData = TRUE;
503             TRACE("\t TEXT -> TEXT\n");
504         }
505         else if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
506         {
507             /* Convert UNICODETEXT -> TEXT */
508             lpSource = &ClipFormats[CF_UNICODETEXT-1];
509             lpTarget = &ClipFormats[CF_TEXT-1];
510             foundData = TRUE;
511             TRACE("\tUNICODETEXT -> TEXT\n");
512         }
513         else if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
514         {
515             /* Convert OEMTEXT -> TEXT */
516             lpSource = &ClipFormats[CF_OEMTEXT-1];
517             lpTarget = &ClipFormats[CF_TEXT-1];
518             foundData = TRUE;
519             TRACE("\tOEMTEXT -> TEXT\n");
520         }
521     }
522     /* Asked for CF_OEMTEXT  */
523     else if( wFormat == CF_OEMTEXT)
524     {
525         if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
526         {
527             lpSource = &ClipFormats[CF_OEMTEXT-1];
528             lpTarget = &ClipFormats[CF_OEMTEXT-1];
529             foundData = TRUE;
530             TRACE("\tOEMTEXT -> OEMTEXT\n");
531         }
532         else if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
533         {
534             /* Convert UNICODETEXT -> OEMTEXT */
535             lpSource = &ClipFormats[CF_UNICODETEXT-1];
536             lpTarget = &ClipFormats[CF_OEMTEXT-1];
537             foundData = TRUE;
538             TRACE("\tUNICODETEXT -> OEMTEXT\n");
539         }
540         else if(ClipFormats[CF_TEXT-1].wDataPresent)
541         {
542             /* Convert TEXT -> OEMTEXT */
543             lpSource = &ClipFormats[CF_TEXT-1];
544             lpTarget = &ClipFormats[CF_OEMTEXT-1];
545             foundData = TRUE;
546             TRACE("\tTEXT -> OEMTEXT\n");
547         }
548     }
549     /* Asked for CF_UNICODETEXT */
550     else if( wFormat == CF_UNICODETEXT )
551     {
552         if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
553         {
554             lpSource = &ClipFormats[CF_UNICODETEXT-1];
555             lpTarget = &ClipFormats[CF_UNICODETEXT-1];
556             foundData = TRUE;
557             TRACE("\tUNICODETEXT -> UNICODETEXT\n");
558         }
559         else if(ClipFormats[CF_TEXT-1].wDataPresent)
560         {
561             /* Convert TEXT -> UNICODETEXT */
562             lpSource = &ClipFormats[CF_TEXT-1];
563             lpTarget = &ClipFormats[CF_UNICODETEXT-1];
564             foundData = TRUE;
565             TRACE("\tTEXT -> UNICODETEXT\n");
566         }
567         else if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
568         {
569             /* Convert OEMTEXT -> UNICODETEXT */
570             lpSource = &ClipFormats[CF_OEMTEXT-1];
571             lpTarget = &ClipFormats[CF_UNICODETEXT-1];
572             foundData = TRUE;
573             TRACE("\tOEMTEXT -> UNICODETEXT\n");
574         }
575     }
576     if (!foundData)
577     {   
578         if ((wFormat == CF_TEXT) || (wFormat == CF_OEMTEXT))
579         {
580             lpSource = &ClipFormats[CF_UNICODETEXT-1];
581             lpTarget = __lookup_format( ClipFormats, wFormat );
582         }
583         else
584         {
585             lpSource = __lookup_format( ClipFormats, wFormat );
586             lpTarget = lpSource;
587         }
588     }
589
590     /* First render the source text format */
591     if ( !lpSource || !CLIPBOARD_RenderFormat(lpSource) ) return NULL;
592
593     /* Convert to the desired target text format, if necessary */
594     if( lpTarget != lpSource && !lpTarget->hData16 && !lpTarget->hData32 )
595     {
596         INT src_chars, dst_chars, alloc_size;
597         LPCSTR lpstrS; 
598         LPSTR  lpstrT;
599     
600         if (lpSource->hData32)
601         {
602           lpstrS = (LPSTR)GlobalLock(lpSource->hData32);
603         }
604         else
605         {
606           lpstrS = (LPSTR)GlobalLock16(lpSource->hData16);
607         }
608     
609         if( !lpstrS ) return NULL;
610
611         /* Text always NULL terminated */
612         if(lpSource->wFormatID == CF_UNICODETEXT)
613             src_chars = strlenW((LPCWSTR)lpstrS)+1;
614         else
615             src_chars = strlen(lpstrS)+1;
616
617         /* Calculate number of characters in the destination buffer */
618         dst_chars = CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
619                                      lpTarget->wFormatID, NULL, 0);
620         if(!dst_chars) return NULL;
621
622         TRACE("\tconverting from '%s' to '%s', %i chars\n",
623                 lpSource->Name, lpTarget->Name, src_chars);
624
625         /* Convert characters to bytes */
626         if(lpTarget->wFormatID == CF_UNICODETEXT)
627             alloc_size = dst_chars * sizeof(WCHAR);
628         else
629             alloc_size = dst_chars;
630
631         lpTarget->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, alloc_size);
632         lpstrT = (LPSTR)GlobalLock(lpTarget->hData32);
633
634         if( lpstrT )
635         {
636             CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
637                                   lpTarget->wFormatID, lpstrT, dst_chars);
638             GlobalUnlock(lpTarget->hData32);
639         }
640         else
641             lpTarget->hData32 = 0;
642
643         /* Unlock source */
644         if (lpSource->hData32)
645           GlobalUnlock(lpSource->hData32);
646         else
647           GlobalUnlock16(lpSource->hData16);
648     }
649
650     return (lpTarget->hData16 || lpTarget->hData32) ? lpTarget : NULL;
651 }
652
653 /**************************************************************************
654  *            CLIPBOARD_EnumClipboardFormats   (internal)
655  */
656 static UINT CLIPBOARD_EnumClipboardFormats( UINT wFormat )
657 {
658     LPWINE_CLIPFORMAT lpFormat = ClipFormats;
659     BOOL bFormatPresent;
660
661     if (wFormat == 0) /* start from the beginning */
662         lpFormat = ClipFormats;
663     else
664     {
665         /* walk up to the specified format record */
666
667         if( !(lpFormat = __lookup_format( lpFormat, wFormat )) ) 
668             return 0;
669         lpFormat = lpFormat->NextFormat; /* right */
670     }
671
672     while(TRUE) 
673     {
674         if (lpFormat == NULL) return 0;
675
676         if(CLIPBOARD_IsPresent(lpFormat->wFormatID))
677             break;
678
679         /* Query the driver if not yet in the cache */
680         if (!USER_Driver.pIsSelectionOwner())
681         {
682             if(lpFormat->wFormatID == CF_UNICODETEXT ||
683                lpFormat->wFormatID == CF_TEXT ||
684                lpFormat->wFormatID == CF_OEMTEXT)
685             {
686                 if(USER_Driver.pIsClipboardFormatAvailable(CF_UNICODETEXT) ||
687                    USER_Driver.pIsClipboardFormatAvailable(CF_TEXT) ||
688                    USER_Driver.pIsClipboardFormatAvailable(CF_OEMTEXT))
689                     bFormatPresent = TRUE;
690                 else
691                     bFormatPresent = FALSE;
692             }
693             else
694                 bFormatPresent = USER_Driver.pIsClipboardFormatAvailable(lpFormat->wFormatID);
695
696             if(bFormatPresent)
697                 break;
698         }
699
700         lpFormat = lpFormat->NextFormat;
701     }
702
703     TRACE("Next available format %d\n", lpFormat->wFormatID);
704
705     return lpFormat->wFormatID;
706 }
707
708
709 /**************************************************************************
710  *                WIN32 Clipboard implementation 
711  **************************************************************************/
712
713 /**************************************************************************
714  *              OpenClipboard (USER32.@)
715  *
716  * Note: Netscape uses NULL hWnd to open the clipboard.
717  */
718 BOOL WINAPI OpenClipboard( HWND hWnd )
719 {
720     BOOL bRet;
721
722     TRACE("(%04x)...\n", hWnd);
723
724     if (!hClipLock)
725     {
726         hClipLock = GetCurrentTask();
727
728         /* Save current user of the clipboard */
729         hWndClipWindow = WIN_GetFullHandle( hWnd );
730         bCBHasChanged = FALSE;
731         bRet = TRUE;
732     }
733     else bRet = FALSE;
734
735     TRACE("   returning %i\n", bRet);
736     return bRet;
737 }
738
739
740 /**************************************************************************
741  *              CloseClipboard (USER.138)
742  */
743 BOOL16 WINAPI CloseClipboard16(void)
744 {
745     return CloseClipboard();
746 }
747
748
749 /**************************************************************************
750  *              CloseClipboard (USER32.@)
751  */
752 BOOL WINAPI CloseClipboard(void)
753 {
754     TRACE("()\n");
755
756     if (hClipLock == GetCurrentTask())
757     {
758         hWndClipWindow = 0;
759
760         if (bCBHasChanged && hWndViewer) SendMessageW( hWndViewer, WM_DRAWCLIPBOARD, 0, 0 );
761         hClipLock = 0;
762     }
763     return TRUE;
764 }
765
766
767 /**************************************************************************
768  *              EmptyClipboard (USER.139)
769  */
770 BOOL16 WINAPI EmptyClipboard16(void)
771 {
772     return EmptyClipboard();
773 }
774
775
776 /**************************************************************************
777  *              EmptyClipboard (USER32.@)
778  *  Empties and acquires ownership of the clipboard
779  */
780 BOOL WINAPI EmptyClipboard(void)
781 {
782     TRACE("()\n");
783
784     if (hClipLock != GetCurrentTask())
785     {
786         WARN("Clipboard not opened by calling task!\n");
787         return FALSE;
788     }
789     
790     /* destroy private objects */
791
792     if (hWndClipOwner) SendMessageW( hWndClipOwner, WM_DESTROYCLIPBOARD, 0, 0 );
793
794     /* empty the cache */
795     CLIPBOARD_EmptyCache(TRUE);
796
797     /* Assign ownership of the clipboard to the current client */
798     hWndClipOwner = hWndClipWindow;
799
800     /* Save the current task */
801     hTaskClipOwner = GetCurrentTask();
802     
803     /* Tell the driver to acquire the selection */
804     USER_Driver.pAcquireClipboard();
805
806     return TRUE;
807 }
808
809
810 /**************************************************************************
811  *              GetClipboardOwner (USER32.@)
812  *  FIXME: Can't return the owner if the clipbard is owned by an external app
813  */
814 HWND WINAPI GetClipboardOwner(void)
815 {
816     TRACE("()\n");
817     return hWndClipOwner;
818 }
819
820
821 /**************************************************************************
822  *              SetClipboardData (USER.141)
823  */
824 HANDLE16 WINAPI SetClipboardData16( UINT16 wFormat, HANDLE16 hData )
825 {
826     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
827
828     TRACE("(%04X, %04x) !\n", wFormat, hData);
829
830     /* NOTE: If the hData is zero and current owner doesn't match
831      * the window that opened the clipboard then this application
832      * is screwed because WM_RENDERFORMAT will go to the owner.
833      * (to become the owner it must call EmptyClipboard() before
834      *  adding new data).
835      */
836
837     if( CLIPBOARD_IsLocked() || !lpFormat ||
838         (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
839     {
840         WARN("Invalid hData or clipboard not opened by calling task!\n");
841         return 0;
842     }
843
844     /* Pass on the request to the driver */
845     USER_Driver.pSetClipboardData(wFormat);
846
847     if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 ) 
848     {
849         CLIPBOARD_DeleteRecord(lpFormat, TRUE);
850
851         /* delete existing CF_UNICODETEXT/CF_TEXT/CF_OEMTEXT aliases */
852         if(wFormat == CF_UNICODETEXT)
853         {
854             CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
855             CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
856         }
857         else if(wFormat == CF_TEXT)
858         {
859             CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
860             CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
861         }
862         else if(wFormat == CF_OEMTEXT)
863         {
864             CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
865             CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
866         }
867     }
868
869     bCBHasChanged = TRUE;
870     lpFormat->wDataPresent = 1;
871     lpFormat->hData16 = hData;          /* 0 is legal, see WM_RENDERFORMAT */
872     lpFormat->hData32 = 0;
873
874     return lpFormat->hData16;
875 }
876
877
878 /**************************************************************************
879  *              SetClipboardData (USER32.@)
880  */
881 HANDLE WINAPI SetClipboardData( UINT wFormat, HANDLE hData )
882 {
883     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
884
885     TRACE("(%08X, %08x) !\n", wFormat, hData);
886
887     /* NOTE: If the hData is zero and current owner doesn't match
888      * the window that opened the clipboard then this application
889      * is screwed because WM_RENDERFORMAT will go to the owner.
890      * (to become the owner it must call EmptyClipboard() before
891      *  adding new data).
892      */
893
894     if( CLIPBOARD_IsLocked() || !lpFormat ||
895         (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
896     {
897         WARN("Invalid hData or clipboard not opened by calling task!\n");
898         return 0;
899     }
900
901     /* Tell the driver to acquire the selection */
902     USER_Driver.pAcquireClipboard();
903
904     if ( lpFormat->wDataPresent &&
905          (lpFormat->hData16 || lpFormat->hData32) )
906     {
907         CLIPBOARD_DeleteRecord(lpFormat, TRUE);
908
909         /* delete existing CF_UNICODETEXT/CF_TEXT/CF_OEMTEXT aliases */
910         if(wFormat == CF_UNICODETEXT)
911         {
912             CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
913             CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
914         }
915         else if(wFormat == CF_TEXT)
916         {
917             CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
918             CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
919         }
920         else if(wFormat == CF_OEMTEXT)
921         {
922             CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
923             CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
924         }
925     }
926
927     bCBHasChanged = TRUE;
928     lpFormat->wDataPresent = 1;
929     lpFormat->hDataSrc32 = hData;  /* Save the source handle */
930
931     /*
932      * Make a shared duplicate if the memory is not shared
933      * TODO: What should be done for non-memory objects
934      */
935     if ( CLIPBOARD_IsMemoryObject(wFormat) && hData && !(GlobalFlags(hData) & GMEM_DDESHARE) )
936         lpFormat->hData32 = CLIPBOARD_GlobalDupMem( hData );
937     else
938         lpFormat->hData32 = hData;          /* 0 is legal, see WM_RENDERFORMAT */
939     
940     lpFormat->hData16 = 0;
941
942     return lpFormat->hData32;   /* Should we return lpFormat->hDataSrc32 */
943 }
944
945
946 /**************************************************************************
947  *              GetClipboardData (USER.142)
948  */
949 HANDLE16 WINAPI GetClipboardData16( UINT16 wFormat )
950 {
951     LPWINE_CLIPFORMAT lpRender = ClipFormats; 
952
953     TRACE("(%04X)\n", wFormat);
954
955     if (CLIPBOARD_IsLocked())
956     {
957         WARN("Clipboard not opened by calling task!\n");
958         return 0;
959     }
960
961     if( wFormat == CF_UNICODETEXT || wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
962     {
963         lpRender = CLIPBOARD_RenderText(wFormat);
964         if ( !lpRender ) return 0;
965     }
966     else
967     {
968         lpRender = __lookup_format( ClipFormats, wFormat );
969         if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
970     }
971    
972     /* Convert between 32 -> 16 bit data, if necessary */
973     if( lpRender->hData32 && !lpRender->hData16
974         && CLIPBOARD_IsMemoryObject(wFormat) )
975     {
976       int size;
977       if( lpRender->wFormatID == CF_METAFILEPICT )
978         size = sizeof( METAFILEPICT16 );
979       else
980           size = GlobalSize(lpRender->hData32);
981       
982       lpRender->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);
983       if( !lpRender->hData16 )
984         ERR("(%04X) -- not enough memory in 16b heap\n", wFormat);
985       else
986       {
987         if( lpRender->wFormatID == CF_METAFILEPICT )
988         {
989           FIXME("\timplement function CopyMetaFilePict32to16\n");
990           FIXME("\tin the appropriate file.\n");
991   #ifdef SOMEONE_IMPLEMENTED_ME
992           CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16), 
993                                   GlobalLock(lpRender->hData32) );
994   #endif
995         }
996         else
997         {
998           memcpy( GlobalLock16(lpRender->hData16), 
999                   GlobalLock(lpRender->hData32), 
1000                   size );
1001         }
1002         GlobalUnlock16(lpRender->hData16);
1003         GlobalUnlock(lpRender->hData32);
1004       }
1005     }
1006
1007     TRACE("\treturning %04x (type %i)\n", 
1008                               lpRender->hData16, lpRender->wFormatID);
1009     return lpRender->hData16;
1010 }
1011
1012
1013 /**************************************************************************
1014  *              GetClipboardData (USER32.@)
1015  */
1016 HANDLE WINAPI GetClipboardData( UINT wFormat )
1017 {
1018     LPWINE_CLIPFORMAT lpRender = ClipFormats; 
1019
1020     TRACE("(%08X)\n", wFormat);
1021
1022     if (CLIPBOARD_IsLocked())
1023     {
1024         WARN("Clipboard not opened by calling task!\n");
1025         return 0;
1026     }
1027
1028     if( wFormat == CF_UNICODETEXT || wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
1029     {
1030         lpRender = CLIPBOARD_RenderText(wFormat);
1031         if ( !lpRender ) return 0;
1032     }
1033     else
1034     {
1035         lpRender = __lookup_format( ClipFormats, wFormat );
1036         if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
1037     }
1038    
1039     /* Convert between 16 -> 32 bit data, if necessary */
1040     if( lpRender->hData16 && !lpRender->hData32
1041         && CLIPBOARD_IsMemoryObject(wFormat) )
1042     {
1043       int size;
1044       if( lpRender->wFormatID == CF_METAFILEPICT )
1045         size = sizeof( METAFILEPICT );
1046       else
1047         size = GlobalSize16(lpRender->hData16);
1048       lpRender->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE,
1049                                       size);
1050       if( lpRender->wFormatID == CF_METAFILEPICT )
1051       {
1052         FIXME("\timplement function CopyMetaFilePict16to32\n");
1053         FIXME("\tin the appropriate file.\n");
1054 #ifdef SOMEONE_IMPLEMENTED_ME
1055         CopyMetaFilePict16to32( GlobalLock16(lpRender->hData32), 
1056                                 GlobalLock(lpRender->hData16) );
1057 #endif
1058       }
1059       else
1060       {
1061         memcpy( GlobalLock(lpRender->hData32), 
1062                 GlobalLock16(lpRender->hData16), 
1063                 size );
1064       }
1065       GlobalUnlock(lpRender->hData32);
1066       GlobalUnlock16(lpRender->hData16);
1067     }
1068
1069     TRACE("\treturning %04x (type %i)\n", 
1070                               lpRender->hData32, lpRender->wFormatID);
1071     return lpRender->hData32;
1072 }
1073
1074
1075 /**************************************************************************
1076  *              CountClipboardFormats (USER.143)
1077  */
1078 INT16 WINAPI CountClipboardFormats16(void)
1079 {
1080     return CountClipboardFormats();
1081 }
1082
1083
1084 /**************************************************************************
1085  *              CountClipboardFormats (USER32.@)
1086  */
1087 INT WINAPI CountClipboardFormats(void)
1088 {
1089     INT FormatCount = 0;
1090     LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
1091
1092     TRACE("()\n");
1093
1094     while(TRUE) 
1095     {
1096         if (lpFormat == NULL) break;
1097
1098         if( lpFormat->wFormatID != CF_TEXT ) /* Don't count CF_TEXT */
1099         {
1100           /*
1101            * The format is available if either:
1102            * 1. The data is already in the cache.
1103            * 2. The selection is not owned by us(WINE) and the data is
1104            *    available to the clipboard driver.
1105            */
1106           if ( lpFormat->wDataPresent ||
1107                ( !USER_Driver.pIsSelectionOwner()
1108                  && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) ) )
1109           {
1110               TRACE("\tdata found for format 0x%04x(%s)\n",
1111                     lpFormat->wFormatID, CLIPBOARD_GetFormatName(lpFormat->wFormatID));
1112               FormatCount++;
1113           }
1114         }
1115
1116         lpFormat = lpFormat->NextFormat;
1117     }
1118
1119     /* these are equivalent, adjust the total */
1120     FormatCount += (ClipFormats[CF_UNICODETEXT-1].wDataPresent ||
1121                     ClipFormats[CF_TEXT-1].wDataPresent ||
1122                     ClipFormats[CF_OEMTEXT-1].wDataPresent) ? 1 : 0;
1123
1124     TRACE("\ttotal %d\n", FormatCount);
1125     return FormatCount;
1126 }
1127
1128 /**************************************************************************
1129  *              EnumClipboardFormats (USER.144)
1130  */
1131 UINT16 WINAPI EnumClipboardFormats16( UINT16 wFormat )
1132 {
1133     return EnumClipboardFormats( wFormat );
1134 }
1135
1136
1137 /**************************************************************************
1138  *              EnumClipboardFormats (USER32.@)
1139  */
1140 UINT WINAPI EnumClipboardFormats( UINT wFormat )
1141 {
1142     TRACE("(%04X)\n", wFormat);
1143
1144     if (CLIPBOARD_IsLocked())
1145     {
1146         WARN("Clipboard not opened by calling task!\n");
1147         return 0;
1148     }
1149
1150     return CLIPBOARD_EnumClipboardFormats(wFormat);
1151 }
1152
1153
1154 /**************************************************************************
1155  *              RegisterClipboardFormatA (USER32.@)
1156  */
1157 UINT WINAPI RegisterClipboardFormatA( LPCSTR FormatName )
1158 {
1159     LPWINE_CLIPFORMAT lpNewFormat; 
1160     LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
1161
1162     if (FormatName == NULL) return 0;
1163
1164     TRACE("('%s') !\n", FormatName);
1165
1166     /* walk format chain to see if it's already registered */
1167
1168     while(TRUE) 
1169     {
1170         if ( !strcmp(lpFormat->Name,FormatName) )
1171         {
1172              lpFormat->wRefCount++;
1173              return lpFormat->wFormatID;
1174         }
1175  
1176         if ( lpFormat->NextFormat == NULL ) break;
1177
1178         lpFormat = lpFormat->NextFormat;
1179     }
1180
1181     /* allocate storage for new format entry */
1182
1183     lpNewFormat = (LPWINE_CLIPFORMAT)HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPFORMAT));
1184     if(lpNewFormat == NULL) {
1185         WARN("No more memory for a new format!\n");
1186         return 0;
1187     }
1188     lpFormat->NextFormat = lpNewFormat;
1189     lpNewFormat->wFormatID = LastRegFormat;
1190     lpNewFormat->wRefCount = 1;
1191
1192     if (!(lpNewFormat->Name = HeapAlloc(GetProcessHeap(), 0, strlen(FormatName)+1 )))
1193     {
1194         WARN("No more memory for the new format name!\n");
1195         HeapFree(GetProcessHeap(), 0, lpNewFormat);
1196         return 0;
1197     }
1198     strcpy( lpNewFormat->Name, FormatName );
1199
1200     lpNewFormat->wDataPresent = 0;
1201     lpNewFormat->hData16 = 0;
1202     lpNewFormat->hDataSrc32 = 0;
1203     lpNewFormat->hData32 = 0;
1204     lpNewFormat->drvData = 0;
1205     lpNewFormat->PrevFormat = lpFormat;
1206     lpNewFormat->NextFormat = NULL;
1207
1208     /* Pass on the registration request to the driver */
1209     USER_Driver.pRegisterClipboardFormat( FormatName );
1210     
1211     return LastRegFormat++;
1212 }
1213
1214
1215 /**************************************************************************
1216  *              RegisterClipboardFormat (USER.145)
1217  */
1218 UINT16 WINAPI RegisterClipboardFormat16( LPCSTR FormatName )
1219 {
1220     return RegisterClipboardFormatA( FormatName );
1221 }
1222
1223
1224 /**************************************************************************
1225  *              RegisterClipboardFormatW (USER32.@)
1226  */
1227 UINT WINAPI RegisterClipboardFormatW( LPCWSTR formatName )
1228 {
1229     LPSTR aFormat = HEAP_strdupWtoA( GetProcessHeap(), 0, formatName );
1230     UINT ret = RegisterClipboardFormatA( aFormat );
1231     HeapFree( GetProcessHeap(), 0, aFormat );
1232     return ret;
1233 }
1234
1235
1236 /**************************************************************************
1237  *              GetClipboardFormatName (USER.146)
1238  */
1239 INT16 WINAPI GetClipboardFormatName16( UINT16 wFormat, LPSTR retStr, INT16 maxlen )
1240 {
1241     return GetClipboardFormatNameA( wFormat, retStr, maxlen );
1242 }
1243
1244
1245 /**************************************************************************
1246  *              GetClipboardFormatNameA (USER32.@)
1247  */
1248 INT WINAPI GetClipboardFormatNameA( UINT wFormat, LPSTR retStr, INT maxlen )
1249 {
1250     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
1251
1252     TRACE("(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
1253
1254     if (lpFormat == NULL || lpFormat->Name == NULL || 
1255         lpFormat->wFormatID < CF_REGFORMATBASE) return 0;
1256
1257     TRACE("Name='%s' !\n", lpFormat->Name);
1258
1259     lstrcpynA( retStr, lpFormat->Name, maxlen );
1260     return strlen(retStr);
1261 }
1262
1263
1264 /**************************************************************************
1265  *              GetClipboardFormatNameW (USER32.@)
1266  */
1267 INT WINAPI GetClipboardFormatNameW( UINT wFormat, LPWSTR retStr, INT maxlen )
1268 {
1269     INT ret;
1270     LPSTR p = HeapAlloc( GetProcessHeap(), 0, maxlen );
1271     if(p == NULL) return 0; /* FIXME: is this the correct failure value? */
1272     
1273     ret = GetClipboardFormatNameA( wFormat, p, maxlen );
1274
1275     if (maxlen > 0 && !MultiByteToWideChar( CP_ACP, 0, p, -1, retStr, maxlen ))
1276         retStr[maxlen-1] = 0;
1277     HeapFree( GetProcessHeap(), 0, p );
1278     return ret;
1279 }
1280
1281
1282 /**************************************************************************
1283  *              SetClipboardViewer (USER32.@)
1284  */
1285 HWND WINAPI SetClipboardViewer( HWND hWnd )
1286 {
1287     HWND hwndPrev = hWndViewer;
1288
1289     TRACE("(%04x): returning %04x\n", hWnd, hwndPrev);
1290
1291     hWndViewer = WIN_GetFullHandle( hWnd );
1292     return hwndPrev;
1293 }
1294
1295
1296 /**************************************************************************
1297  *              GetClipboardViewer (USER32.@)
1298  */
1299 HWND WINAPI GetClipboardViewer(void)
1300 {
1301     TRACE("()\n");
1302     return hWndViewer;
1303 }
1304
1305
1306 /**************************************************************************
1307  *              ChangeClipboardChain (USER32.@)
1308  */
1309 BOOL WINAPI ChangeClipboardChain(HWND hWnd, HWND hWndNext)
1310 {
1311     BOOL bRet = 0;
1312
1313     FIXME("(0x%04x, 0x%04x): stub?\n", hWnd, hWndNext);
1314
1315     if( hWndViewer )
1316         bRet = !SendMessageW( hWndViewer, WM_CHANGECBCHAIN, (WPARAM)hWnd, (LPARAM)hWndNext );
1317     else
1318         WARN("hWndViewer is lost\n");
1319
1320     if( WIN_GetFullHandle(hWnd) == hWndViewer ) hWndViewer = WIN_GetFullHandle( hWndNext );
1321
1322     return bRet;
1323 }
1324
1325
1326 /**************************************************************************
1327  *              IsClipboardFormatAvailable (USER.193)
1328  */
1329 BOOL16 WINAPI IsClipboardFormatAvailable16( UINT16 wFormat )
1330 {
1331     return IsClipboardFormatAvailable( wFormat );
1332 }
1333
1334
1335 /**************************************************************************
1336  *              IsClipboardFormatAvailable (USER32.@)
1337  */
1338 BOOL WINAPI IsClipboardFormatAvailable( UINT wFormat )
1339 {
1340     BOOL bRet;
1341
1342     if (wFormat == 0)  /* Reject this case quickly */
1343         bRet = FALSE;
1344     else
1345     {
1346         UINT iret = CLIPBOARD_EnumClipboardFormats(wFormat - 1);
1347         if ((wFormat == CF_TEXT) || (wFormat == CF_OEMTEXT) || (wFormat == CF_UNICODETEXT))
1348             bRet = ((iret == CF_TEXT) || (iret == CF_OEMTEXT) || (iret == CF_UNICODETEXT));
1349         else
1350             bRet = iret == wFormat;
1351     }
1352     TRACE("(%04X)- ret(%d)\n", wFormat, bRet);
1353     return bRet;
1354 }
1355
1356
1357 /**************************************************************************
1358  *              GetOpenClipboardWindow (USER32.@)
1359  *  FIXME: This wont work if an external app owns the selection
1360  */
1361 HWND WINAPI GetOpenClipboardWindow(void)
1362 {
1363     TRACE("()\n");
1364     return hWndClipWindow;
1365 }
1366
1367
1368 /**************************************************************************
1369  *              GetPriorityClipboardFormat (USER32.@)
1370  */
1371 INT WINAPI GetPriorityClipboardFormat( UINT *list, INT nCount )
1372 {
1373     int i;
1374     TRACE("()\n");
1375
1376     if(CountClipboardFormats() == 0) return 0;
1377
1378     for (i = 0; i < nCount; i++)
1379         if (IsClipboardFormatAvailable( list[i] )) return list[i];
1380     return -1;
1381 }
1382
1383
1384 /**************************************************************************
1385  *              GetClipboardSequenceNumber (USER32.@)
1386  * Supported on Win2k/Win98
1387  * MSDN: Windows clipboard code keeps a serial number for the clipboard
1388  * for each window station.  The number is incremented whenever the
1389  * contents change or are emptied.
1390  * If you do not have WINSTA_ACCESSCLIPBOARD then the function returns 0
1391  */
1392 DWORD WINAPI GetClipboardSequenceNumber(VOID)
1393 {
1394         FIXME("Returning 0, see windows/clipboard.c\n");
1395         /* FIXME: Use serial numbers */
1396         return 0;
1397 }