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