Fix large item label calculation when not focused.
[wine.git] / windows / clipboard.c
blob46ee038b93d146db104662783ec09802f6d06e1a
1 /*
2 * WIN32 clipboard implementation
4 * Copyright 1994 Martin Ayotte
5 * 1996 Alex Korobka
6 * 1999 Noel Borthwick
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * NOTES:
23 * This file contains the implementation for the WIN32 Clipboard API
24 * and Wine's internal clipboard cache.
25 * The actual contents of the clipboard are held in the clipboard cache.
26 * The internal implementation talks to a "clipboard driver" to fill or
27 * expose the cache to the native device. (Currently only the X11 and
28 * TTY clipboard driver are available)
31 #include "config.h"
32 #include "wine/port.h"
34 #include <stdlib.h>
35 #include <sys/types.h>
36 #include <fcntl.h>
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 #include <string.h>
42 #include "windef.h"
43 #include "winbase.h"
44 #include "wingdi.h"
45 #include "winuser.h"
46 #include "wine/winuser16.h"
47 #include "wine/winbase16.h"
48 #include "heap.h"
49 #include "user.h"
50 #include "win.h"
51 #include "clipboard.h"
52 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
56 #define CF_REGFORMATBASE 0xC000
58 /**************************************************************************
59 * Clipboard context global variables
62 static HANDLE hClipLock = 0;
63 static BOOL bCBHasChanged = FALSE;
65 static HWND hWndClipWindow; /* window that last opened clipboard */
66 static HWND hWndClipOwner; /* current clipboard owner */
67 static HANDLE16 hTaskClipOwner; /* clipboard owner's task */
68 static HWND hWndViewer; /* start of viewers chain */
70 /* Clipboard cache initial data.
71 * WARNING: This data ordering is dependent on the WINE_CLIPFORMAT structure
72 * declared in clipboard.h
74 WINE_CLIPFORMAT ClipFormats[] = {
75 { CF_TEXT, 1, 0, "Text", 0, 0, 0, 0, NULL, &ClipFormats[1]},
76 { CF_BITMAP, 1, 0, "Bitmap", 0, 0, 0, 0, &ClipFormats[0], &ClipFormats[2]},
77 { CF_METAFILEPICT, 1, 0, "MetaFile Picture", 0, 0, 0, 0, &ClipFormats[1], &ClipFormats[3]},
78 { CF_SYLK, 1, 0, "Sylk", 0, 0, 0, 0, &ClipFormats[2], &ClipFormats[4]},
79 { CF_DIF, 1, 0, "DIF", 0, 0, 0, 0, &ClipFormats[3], &ClipFormats[5]},
80 { CF_TIFF, 1, 0, "TIFF", 0, 0, 0, 0, &ClipFormats[4], &ClipFormats[6]},
81 { CF_OEMTEXT, 1, 0, "OEM Text", 0, 0, 0, 0, &ClipFormats[5], &ClipFormats[7]},
82 { CF_DIB, 1, 0, "DIB", 0, 0, 0, 0, &ClipFormats[6], &ClipFormats[8]},
83 { CF_PALETTE, 1, 0, "Palette", 0, 0, 0, 0, &ClipFormats[7], &ClipFormats[9]},
84 { CF_PENDATA, 1, 0, "PenData", 0, 0, 0, 0, &ClipFormats[8], &ClipFormats[10]},
85 { CF_RIFF, 1, 0, "RIFF", 0, 0, 0, 0, &ClipFormats[9], &ClipFormats[11]},
86 { CF_WAVE, 1, 0, "Wave", 0, 0, 0, 0, &ClipFormats[10], &ClipFormats[12]},
87 { CF_UNICODETEXT, 1, 0, "Unicode Text", 0, 0, 0, 0, &ClipFormats[11], &ClipFormats[13]},
88 { CF_OWNERDISPLAY, 1, 0, "Owner Display", 0, 0, 0, 0, &ClipFormats[12], &ClipFormats[14]},
89 { CF_DSPTEXT, 1, 0, "DSPText", 0, 0, 0, 0, &ClipFormats[13], &ClipFormats[15]},
90 { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", 0, 0, 0, 0, &ClipFormats[14], &ClipFormats[16]},
91 { CF_DSPBITMAP, 1, 0, "DSPBitmap", 0, 0, 0, 0, &ClipFormats[15], &ClipFormats[17]},
92 { CF_HDROP, 1, 0, "HDROP", 0, 0, 0, 0, &ClipFormats[16], &ClipFormats[18]},
93 { CF_ENHMETAFILE, 1, 0, "Enhmetafile", 0, 0, 0, 0, &ClipFormats[17], NULL}
97 /**************************************************************************
98 * Internal Clipboard implementation methods
99 **************************************************************************/
102 /**************************************************************************
103 * CLIPBOARD_LookupFormat
105 static LPWINE_CLIPFORMAT __lookup_format( LPWINE_CLIPFORMAT lpFormat, WORD wID )
107 while(TRUE)
109 if (lpFormat == NULL ||
110 lpFormat->wFormatID == wID) break;
111 lpFormat = lpFormat->NextFormat;
113 return lpFormat;
116 LPWINE_CLIPFORMAT CLIPBOARD_LookupFormat( WORD wID )
118 return __lookup_format( ClipFormats, wID );
121 /**************************************************************************
122 * CLIPBOARD_IsLocked
123 * Check if the clipboard cache is available to the caller
125 BOOL CLIPBOARD_IsLocked()
127 BOOL bIsLocked = TRUE;
128 HANDLE16 hTaskCur = GetCurrentTask();
131 * The clipboard is available:
132 * 1. if the caller's task has opened the clipboard,
133 * or
134 * 2. if the caller is the clipboard owners task, AND is responding to a
135 * WM_RENDERFORMAT message.
137 if ( hClipLock == hTaskCur )
138 bIsLocked = FALSE;
140 else if ( hTaskCur == hTaskClipOwner )
142 /* Check if we're currently executing inside a window procedure
143 * called in response to a WM_RENDERFORMAT message. A WM_RENDERFORMAT
144 * handler is not permitted to open the clipboard since it has been opened
145 * by another client. However the handler must have access to the
146 * clipboard in order to update data in response to this message.
148 #if 0
149 MESSAGEQUEUE *queue = QUEUE_Current();
151 if ( queue
152 && queue->smWaiting
153 && queue->smWaiting->msg == WM_RENDERFORMAT
154 && queue->smWaiting->hSrcQueue
156 bIsLocked = FALSE;
157 #else
158 /* FIXME: queue check no longer possible */
159 bIsLocked = FALSE;
160 #endif
163 return bIsLocked;
166 /**************************************************************************
167 * CLIPBOARD_ReleaseOwner
168 * Gives up ownership of the clipboard
170 void CLIPBOARD_ReleaseOwner()
172 hWndClipOwner = 0;
173 hTaskClipOwner = 0;
176 /**************************************************************************
177 * CLIPBOARD_GlobalFreeProc
179 * This is a callback mechanism to allow HGLOBAL data to be released in
180 * the context of the process which allocated it. We post a WM_TIMER message
181 * to the owner window(in CLIPBOARD_DeleteRecord) and destroy the data(in idEvent)
182 * in this WndProc, which is invoked when the apps message loop calls DispatchMessage.
183 * This technique is discussed in Matt Pietrek's "Under the Hood".
184 * An article describing the same may be found in MSDN by searching for WM_TIMER.
185 * Note that this mechanism will probably stop working when WINE supports
186 * address space separation. When "queue events" are implemented in Wine we
187 * should switch to using that mechanism, since it is more robust and does not
188 * require a procedure address to be passed. See the SetWinEventHook API for
189 * more info on this.
191 VOID CALLBACK CLIPBOARD_GlobalFreeProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime )
193 /* idEvent is the HGLOBAL to be deleted */
194 GlobalFree( (HGLOBAL)idEvent );
197 /**************************************************************************
198 * CLIPBOARD_DeleteRecord
200 void CLIPBOARD_DeleteRecord(LPWINE_CLIPFORMAT lpFormat, BOOL bChange)
202 if( (lpFormat->wFormatID >= CF_GDIOBJFIRST &&
203 lpFormat->wFormatID <= CF_GDIOBJLAST) || lpFormat->wFormatID == CF_BITMAP
204 || lpFormat->wFormatID == CF_PALETTE)
206 if (lpFormat->hData32)
207 DeleteObject(lpFormat->hData32);
208 if (lpFormat->hData16)
209 DeleteObject(lpFormat->hData16);
211 else if( lpFormat->wFormatID == CF_METAFILEPICT )
213 if (lpFormat->hData32)
215 DeleteMetaFile( ((METAFILEPICT *)GlobalLock( lpFormat->hData32 ))->hMF );
216 PostMessageA(hWndClipOwner, WM_TIMER,
217 (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
218 if (lpFormat->hDataSrc32)
220 /* Release lpFormat->hData32 in the context of the process which created it.
221 * See CLIPBOARD_GlobalFreeProc for more details about this technique.
222 * GlobalFree(lpFormat->hDataSrc32);
224 PostMessageA(hWndClipOwner, WM_TIMER,
225 (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
228 if (lpFormat->hData16)
229 /* HMETAFILE16 and HMETAFILE32 are apparently the same thing,
230 and a shallow copy is enough to share a METAFILEPICT
231 structure between 16bit and 32bit clipboards. The MetaFile
232 should of course only be deleted once. */
233 GlobalFree16(lpFormat->hData16);
235 if (lpFormat->hData16)
237 DeleteMetaFile16( ((METAFILEPICT16 *)GlobalLock16( lpFormat->hData16 ))->hMF );
238 GlobalFree16(lpFormat->hData16);
241 else
243 if (lpFormat->hData32)
245 /* Release lpFormat->hData32 in the context of the process which created it.
246 * See CLIPBOARD_GlobalFreeProc for more details about this technique.
247 * GlobalFree( lpFormat->hData32 );
249 PostMessageA(hWndClipOwner, WM_TIMER,
250 (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
252 if (lpFormat->hDataSrc32)
254 /* Release lpFormat->hData32 in the context of the process which created it.
255 * See CLIPBOARD_GlobalFreeProc for more details about this technique.
256 * GlobalFree(lpFormat->hDataSrc32);
258 PostMessageA(hWndClipOwner, WM_TIMER,
259 (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
261 if (lpFormat->hData16)
262 GlobalFree16(lpFormat->hData16);
265 lpFormat->wDataPresent = 0;
266 lpFormat->hData16 = 0;
267 lpFormat->hData32 = 0;
268 lpFormat->hDataSrc32 = 0;
269 lpFormat->drvData = 0;
271 if( bChange ) bCBHasChanged = TRUE;
274 /**************************************************************************
275 * CLIPBOARD_EmptyCache
277 void CLIPBOARD_EmptyCache( BOOL bChange )
279 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
281 while(lpFormat)
283 if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
284 CLIPBOARD_DeleteRecord( lpFormat, bChange );
286 lpFormat = lpFormat->NextFormat;
290 /**************************************************************************
291 * CLIPBOARD_IsPresent
293 BOOL CLIPBOARD_IsPresent(WORD wFormat)
295 /* special case */
297 if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT || wFormat == CF_UNICODETEXT )
298 return ClipFormats[CF_TEXT-1].wDataPresent ||
299 ClipFormats[CF_OEMTEXT-1].wDataPresent ||
300 ClipFormats[CF_UNICODETEXT-1].wDataPresent;
301 else
303 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
304 if( lpFormat ) return (lpFormat->wDataPresent);
306 return FALSE;
309 /**************************************************************************
310 * CLIPBOARD_IsCacheRendered
311 * Checks if any data needs to be rendered to the clipboard cache
312 * RETURNS:
313 * TRUE - All clipboard data is available in the cache
314 * FALSE - Some data is marked for delayed render and needs rendering
316 BOOL CLIPBOARD_IsCacheRendered()
318 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
320 /* check if all formats were rendered */
321 while(lpFormat)
323 if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
324 return FALSE;
326 lpFormat = lpFormat->NextFormat;
329 return TRUE;
333 /**************************************************************************
334 * CLIPBOARD_IsMemoryObject
335 * Tests if the clipboard format specifies a memory object
337 BOOL CLIPBOARD_IsMemoryObject( WORD wFormat )
339 switch(wFormat)
341 case CF_BITMAP:
342 case CF_METAFILEPICT:
343 case CF_DSPTEXT:
344 case CF_ENHMETAFILE:
345 case CF_HDROP:
346 case CF_PALETTE:
347 case CF_PENDATA:
348 return FALSE;
349 default:
350 return TRUE;
354 /***********************************************************************
355 * CLIPBOARD_GlobalDupMem( HGLOBAL )
356 * Helper method to duplicate an HGLOBAL chunk of memory into shared memory
358 HGLOBAL CLIPBOARD_GlobalDupMem( HGLOBAL hGlobalSrc )
360 HGLOBAL hGlobalDest;
361 PVOID pGlobalSrc, pGlobalDest;
362 DWORD cBytes;
364 if ( !hGlobalSrc )
365 return 0;
367 cBytes = GlobalSize(hGlobalSrc);
368 if ( 0 == cBytes )
369 return 0;
371 /* Turn on the DDESHARE and _MOVEABLE flags explicitly */
372 hGlobalDest = GlobalAlloc( GlobalFlags(hGlobalSrc) | GMEM_DDESHARE | GMEM_MOVEABLE,
373 cBytes );
374 if ( !hGlobalDest )
375 return 0;
377 pGlobalSrc = GlobalLock(hGlobalSrc);
378 pGlobalDest = GlobalLock(hGlobalDest);
379 if ( !pGlobalSrc || !pGlobalDest )
380 return 0;
382 memcpy(pGlobalDest, pGlobalSrc, cBytes);
384 GlobalUnlock(hGlobalSrc);
385 GlobalUnlock(hGlobalDest);
387 return hGlobalDest;
390 /**************************************************************************
391 * CLIPBOARD_GetFormatName
392 * Gets the format name associated with an ID
394 char * CLIPBOARD_GetFormatName(UINT wFormat, LPSTR buf, INT size)
396 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
398 if (lpFormat)
400 if (buf)
402 strncpy(buf, lpFormat->Name, size);
403 CharLowerA(buf);
406 return lpFormat->Name;
408 else
409 return NULL;
413 /**************************************************************************
414 * CLIPBOARD_RenderFormat
416 static BOOL CLIPBOARD_RenderFormat(LPWINE_CLIPFORMAT lpFormat)
419 * If WINE is not the selection owner, and the format is available
420 * we must ask the driver to render the data to the clipboard cache.
422 TRACE("enter format=%d\n", lpFormat->wFormatID);
423 if ( !USER_Driver.pIsSelectionOwner()
424 && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) )
426 if ( !USER_Driver.pGetClipboardData( lpFormat->wFormatID ) )
427 return FALSE;
430 * If Wine owns the clipboard, and the data is marked for delayed render,
431 * render it now.
433 else if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
435 if( IsWindow(hWndClipOwner) )
437 /* Send a WM_RENDERFORMAT message to notify the owner to render the
438 * data requested into the clipboard.
440 TRACE("Sending WM_RENDERFORMAT message\n");
441 SendMessageW( hWndClipOwner, WM_RENDERFORMAT, (WPARAM)lpFormat->wFormatID, 0 );
443 else
445 WARN("\thWndClipOwner (%04x) is lost!\n",
446 hWndClipOwner);
447 CLIPBOARD_ReleaseOwner();
448 lpFormat->wDataPresent = 0;
449 return FALSE;
453 return (lpFormat->hData16 || lpFormat->hData32) ? TRUE : FALSE;
456 /**************************************************************************
457 * CLIPBOARD_ConvertText
458 * Returns number of required/converted characters - not bytes!
460 static INT CLIPBOARD_ConvertText(WORD src_fmt, void const *src, INT src_size,
461 WORD dst_fmt, void *dst, INT dst_size)
463 UINT cp;
465 if(src_fmt == CF_UNICODETEXT)
467 switch(dst_fmt)
469 case CF_TEXT:
470 cp = CP_ACP;
471 break;
472 case CF_OEMTEXT:
473 cp = CP_OEMCP;
474 break;
475 default:
476 return 0;
478 return WideCharToMultiByte(cp, 0, src, src_size, dst, dst_size, NULL, NULL);
481 if(dst_fmt == CF_UNICODETEXT)
483 switch(src_fmt)
485 case CF_TEXT:
486 cp = CP_ACP;
487 break;
488 case CF_OEMTEXT:
489 cp = CP_OEMCP;
490 break;
491 default:
492 return 0;
494 return MultiByteToWideChar(cp, 0, src, src_size, dst, dst_size);
497 if(!dst_size) return src_size;
499 if(dst_size > src_size) dst_size = src_size;
501 if(src_fmt == CF_TEXT )
502 CharToOemBuffA(src, dst, dst_size);
503 else
504 OemToCharBuffA(src, dst, dst_size);
506 return dst_size;
509 /**************************************************************************
510 * CLIPBOARD_RenderText
512 * Renders text to the clipboard buffer converting between UNIX and DOS formats.
514 * RETURNS: pointer to the WINE_CLIPFORMAT if successful, NULL otherwise
516 * FIXME: Should be a pair of driver functions that convert between OEM text and Windows.
519 static LPWINE_CLIPFORMAT CLIPBOARD_RenderText( UINT wFormat )
521 LPWINE_CLIPFORMAT lpSource = ClipFormats;
522 LPWINE_CLIPFORMAT lpTarget = NULL;
523 BOOL foundData = FALSE;
525 /* Asked for CF_TEXT */
526 if( wFormat == CF_TEXT)
528 if(ClipFormats[CF_TEXT-1].wDataPresent)
530 lpSource = &ClipFormats[CF_TEXT-1];
531 lpTarget = &ClipFormats[CF_TEXT-1];
532 foundData = TRUE;
533 TRACE("\t TEXT -> TEXT\n");
535 else if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
537 /* Convert UNICODETEXT -> TEXT */
538 lpSource = &ClipFormats[CF_UNICODETEXT-1];
539 lpTarget = &ClipFormats[CF_TEXT-1];
540 foundData = TRUE;
541 TRACE("\tUNICODETEXT -> TEXT\n");
543 else if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
545 /* Convert OEMTEXT -> TEXT */
546 lpSource = &ClipFormats[CF_OEMTEXT-1];
547 lpTarget = &ClipFormats[CF_TEXT-1];
548 foundData = TRUE;
549 TRACE("\tOEMTEXT -> TEXT\n");
552 /* Asked for CF_OEMTEXT */
553 else if( wFormat == CF_OEMTEXT)
555 if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
557 lpSource = &ClipFormats[CF_OEMTEXT-1];
558 lpTarget = &ClipFormats[CF_OEMTEXT-1];
559 foundData = TRUE;
560 TRACE("\tOEMTEXT -> OEMTEXT\n");
562 else if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
564 /* Convert UNICODETEXT -> OEMTEXT */
565 lpSource = &ClipFormats[CF_UNICODETEXT-1];
566 lpTarget = &ClipFormats[CF_OEMTEXT-1];
567 foundData = TRUE;
568 TRACE("\tUNICODETEXT -> OEMTEXT\n");
570 else if(ClipFormats[CF_TEXT-1].wDataPresent)
572 /* Convert TEXT -> OEMTEXT */
573 lpSource = &ClipFormats[CF_TEXT-1];
574 lpTarget = &ClipFormats[CF_OEMTEXT-1];
575 foundData = TRUE;
576 TRACE("\tTEXT -> OEMTEXT\n");
579 /* Asked for CF_UNICODETEXT */
580 else if( wFormat == CF_UNICODETEXT )
582 if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
584 lpSource = &ClipFormats[CF_UNICODETEXT-1];
585 lpTarget = &ClipFormats[CF_UNICODETEXT-1];
586 foundData = TRUE;
587 TRACE("\tUNICODETEXT -> UNICODETEXT\n");
589 else if(ClipFormats[CF_TEXT-1].wDataPresent)
591 /* Convert TEXT -> UNICODETEXT */
592 lpSource = &ClipFormats[CF_TEXT-1];
593 lpTarget = &ClipFormats[CF_UNICODETEXT-1];
594 foundData = TRUE;
595 TRACE("\tTEXT -> UNICODETEXT\n");
597 else if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
599 /* Convert OEMTEXT -> UNICODETEXT */
600 lpSource = &ClipFormats[CF_OEMTEXT-1];
601 lpTarget = &ClipFormats[CF_UNICODETEXT-1];
602 foundData = TRUE;
603 TRACE("\tOEMTEXT -> UNICODETEXT\n");
606 if (!foundData)
608 if ((wFormat == CF_TEXT) || (wFormat == CF_OEMTEXT))
610 lpSource = &ClipFormats[CF_UNICODETEXT-1];
611 lpTarget = __lookup_format( ClipFormats, wFormat );
613 else
615 lpSource = __lookup_format( ClipFormats, wFormat );
616 lpTarget = lpSource;
620 /* First render the source text format */
621 if ( !lpSource || !CLIPBOARD_RenderFormat(lpSource) ) return NULL;
623 /* Convert to the desired target text format, if necessary */
624 if( lpTarget != lpSource && !lpTarget->hData16 && !lpTarget->hData32 )
626 INT src_chars, dst_chars, alloc_size;
627 LPCSTR lpstrS;
628 LPSTR lpstrT;
630 if (lpSource->hData32)
632 lpstrS = (LPSTR)GlobalLock(lpSource->hData32);
634 else
636 lpstrS = (LPSTR)GlobalLock16(lpSource->hData16);
639 if( !lpstrS ) return NULL;
641 /* Text always NULL terminated */
642 if(lpSource->wFormatID == CF_UNICODETEXT)
643 src_chars = strlenW((LPCWSTR)lpstrS)+1;
644 else
645 src_chars = strlen(lpstrS)+1;
647 /* Calculate number of characters in the destination buffer */
648 dst_chars = CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
649 lpTarget->wFormatID, NULL, 0);
650 if(!dst_chars) return NULL;
652 TRACE("\tconverting from '%s' to '%s', %i chars\n",
653 lpSource->Name, lpTarget->Name, src_chars);
655 /* Convert characters to bytes */
656 if(lpTarget->wFormatID == CF_UNICODETEXT)
657 alloc_size = dst_chars * sizeof(WCHAR);
658 else
659 alloc_size = dst_chars;
661 lpTarget->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, alloc_size);
662 lpstrT = (LPSTR)GlobalLock(lpTarget->hData32);
664 if( lpstrT )
666 CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
667 lpTarget->wFormatID, lpstrT, dst_chars);
668 GlobalUnlock(lpTarget->hData32);
670 else
671 lpTarget->hData32 = 0;
673 /* Unlock source */
674 if (lpSource->hData32)
675 GlobalUnlock(lpSource->hData32);
676 else
677 GlobalUnlock16(lpSource->hData16);
680 return (lpTarget->hData16 || lpTarget->hData32) ? lpTarget : NULL;
683 /**************************************************************************
684 * CLIPBOARD_EnumClipboardFormats (internal)
686 static UINT CLIPBOARD_EnumClipboardFormats( UINT wFormat )
688 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
689 BOOL bFormatPresent;
691 if (wFormat == 0) /* start from the beginning */
692 lpFormat = ClipFormats;
693 else
695 /* walk up to the specified format record */
697 if( !(lpFormat = __lookup_format( lpFormat, wFormat )) )
698 return 0;
699 lpFormat = lpFormat->NextFormat; /* right */
702 while(TRUE)
704 if (lpFormat == NULL) return 0;
706 if(CLIPBOARD_IsPresent(lpFormat->wFormatID))
707 break;
709 /* Query the driver if not yet in the cache */
710 if (!USER_Driver.pIsSelectionOwner())
712 if(lpFormat->wFormatID == CF_UNICODETEXT ||
713 lpFormat->wFormatID == CF_TEXT ||
714 lpFormat->wFormatID == CF_OEMTEXT)
716 if(USER_Driver.pIsClipboardFormatAvailable(CF_UNICODETEXT) ||
717 USER_Driver.pIsClipboardFormatAvailable(CF_TEXT) ||
718 USER_Driver.pIsClipboardFormatAvailable(CF_OEMTEXT))
719 bFormatPresent = TRUE;
720 else
721 bFormatPresent = FALSE;
723 else
724 bFormatPresent = USER_Driver.pIsClipboardFormatAvailable(lpFormat->wFormatID);
726 if(bFormatPresent)
727 break;
730 lpFormat = lpFormat->NextFormat;
733 TRACE("Next available format %d\n", lpFormat->wFormatID);
735 return lpFormat->wFormatID;
739 /**************************************************************************
740 * WIN32 Clipboard implementation
741 **************************************************************************/
743 /**************************************************************************
744 * OpenClipboard (USER32.@)
746 * Note: Netscape uses NULL hWnd to open the clipboard.
748 BOOL WINAPI OpenClipboard( HWND hWnd )
750 BOOL bRet;
752 TRACE("(%04x)...\n", hWnd);
754 if (!hClipLock)
756 hClipLock = GetCurrentTask();
758 /* Save current user of the clipboard */
759 hWndClipWindow = WIN_GetFullHandle( hWnd );
760 bCBHasChanged = FALSE;
761 bRet = TRUE;
763 else bRet = FALSE;
765 TRACE(" returning %i\n", bRet);
766 return bRet;
770 /**************************************************************************
771 * CloseClipboard (USER.138)
773 BOOL16 WINAPI CloseClipboard16(void)
775 return CloseClipboard();
779 /**************************************************************************
780 * CloseClipboard (USER32.@)
782 BOOL WINAPI CloseClipboard(void)
784 TRACE("()\n");
786 if (hClipLock == GetCurrentTask())
788 hWndClipWindow = 0;
790 if (bCBHasChanged && hWndViewer) SendMessageW( hWndViewer, WM_DRAWCLIPBOARD, 0, 0 );
791 hClipLock = 0;
793 return TRUE;
797 /**************************************************************************
798 * EmptyClipboard (USER.139)
800 BOOL16 WINAPI EmptyClipboard16(void)
802 return EmptyClipboard();
806 /**************************************************************************
807 * EmptyClipboard (USER32.@)
808 * Empties and acquires ownership of the clipboard
810 BOOL WINAPI EmptyClipboard(void)
812 TRACE("()\n");
814 if (hClipLock != GetCurrentTask())
816 WARN("Clipboard not opened by calling task!\n");
817 return FALSE;
820 /* destroy private objects */
822 if (hWndClipOwner) SendMessageW( hWndClipOwner, WM_DESTROYCLIPBOARD, 0, 0 );
824 /* empty the cache */
825 CLIPBOARD_EmptyCache(TRUE);
827 /* Assign ownership of the clipboard to the current client */
828 hWndClipOwner = hWndClipWindow;
830 /* Save the current task */
831 hTaskClipOwner = GetCurrentTask();
833 /* Tell the driver to acquire the selection */
834 USER_Driver.pAcquireClipboard();
836 return TRUE;
840 /**************************************************************************
841 * GetClipboardOwner (USER32.@)
842 * FIXME: Can't return the owner if the clipbard is owned by an external app
844 HWND WINAPI GetClipboardOwner(void)
846 TRACE("()\n");
847 return hWndClipOwner;
851 /**************************************************************************
852 * SetClipboardData (USER.141)
854 HANDLE16 WINAPI SetClipboardData16( UINT16 wFormat, HANDLE16 hData )
856 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
858 TRACE("(%04X, %04x) !\n", wFormat, hData);
860 /* NOTE: If the hData is zero and current owner doesn't match
861 * the window that opened the clipboard then this application
862 * is screwed because WM_RENDERFORMAT will go to the owner.
863 * (to become the owner it must call EmptyClipboard() before
864 * adding new data).
867 if( CLIPBOARD_IsLocked() || !lpFormat ||
868 (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
870 WARN("Invalid hData or clipboard not opened by calling task!\n");
871 return 0;
874 /* Pass on the request to the driver */
875 USER_Driver.pSetClipboardData(wFormat);
877 if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
879 CLIPBOARD_DeleteRecord(lpFormat, TRUE);
881 /* delete existing CF_UNICODETEXT/CF_TEXT/CF_OEMTEXT aliases */
882 if(wFormat == CF_UNICODETEXT)
884 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
885 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
887 else if(wFormat == CF_TEXT)
889 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
890 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
892 else if(wFormat == CF_OEMTEXT)
894 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
895 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
899 bCBHasChanged = TRUE;
900 lpFormat->wDataPresent = 1;
901 lpFormat->hData16 = hData; /* 0 is legal, see WM_RENDERFORMAT */
902 lpFormat->hData32 = 0;
904 return lpFormat->hData16;
908 /**************************************************************************
909 * SetClipboardData (USER32.@)
911 HANDLE WINAPI SetClipboardData( UINT wFormat, HANDLE hData )
913 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
915 TRACE("(%08X, %08x) !\n", wFormat, hData);
917 /* NOTE: If the hData is zero and current owner doesn't match
918 * the window that opened the clipboard then this application
919 * is screwed because WM_RENDERFORMAT will go to the owner.
920 * (to become the owner it must call EmptyClipboard() before
921 * adding new data).
924 if( CLIPBOARD_IsLocked() || !lpFormat ||
925 (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
927 WARN("Invalid hData or clipboard not opened by calling task!\n");
928 return 0;
931 /* Tell the driver to acquire the selection */
932 USER_Driver.pAcquireClipboard();
934 if ( lpFormat->wDataPresent &&
935 (lpFormat->hData16 || lpFormat->hData32) )
937 CLIPBOARD_DeleteRecord(lpFormat, TRUE);
939 /* delete existing CF_UNICODETEXT/CF_TEXT/CF_OEMTEXT aliases */
940 if(wFormat == CF_UNICODETEXT)
942 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
943 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
945 else if(wFormat == CF_TEXT)
947 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
948 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
950 else if(wFormat == CF_OEMTEXT)
952 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
953 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
957 bCBHasChanged = TRUE;
958 lpFormat->wDataPresent = 1;
959 lpFormat->hDataSrc32 = hData; /* Save the source handle */
962 * Make a shared duplicate if the memory is not shared
963 * TODO: What should be done for non-memory objects
965 if ( CLIPBOARD_IsMemoryObject(wFormat) && hData && !(GlobalFlags(hData) & GMEM_DDESHARE) )
966 lpFormat->hData32 = CLIPBOARD_GlobalDupMem( hData );
967 else
968 lpFormat->hData32 = hData; /* 0 is legal, see WM_RENDERFORMAT */
970 lpFormat->hData16 = 0;
972 return lpFormat->hData32; /* Should we return lpFormat->hDataSrc32 */
976 /**************************************************************************
977 * GetClipboardData (USER.142)
979 HANDLE16 WINAPI GetClipboardData16( UINT16 wFormat )
981 LPWINE_CLIPFORMAT lpRender = ClipFormats;
983 TRACE("(%04X)\n", wFormat);
985 if (CLIPBOARD_IsLocked())
987 WARN("Clipboard not opened by calling task!\n");
988 return 0;
991 if( wFormat == CF_UNICODETEXT || wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
993 lpRender = CLIPBOARD_RenderText(wFormat);
994 if ( !lpRender ) return 0;
996 else
998 lpRender = __lookup_format( ClipFormats, wFormat );
999 if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
1002 /* Convert between 32 -> 16 bit data, if necessary */
1003 if( lpRender->hData32 && !lpRender->hData16
1004 && CLIPBOARD_IsMemoryObject(wFormat) )
1006 int size;
1007 if( lpRender->wFormatID == CF_METAFILEPICT )
1008 size = sizeof( METAFILEPICT16 );
1009 else
1010 size = GlobalSize(lpRender->hData32);
1012 lpRender->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);
1013 if( !lpRender->hData16 )
1014 ERR("(%04X) -- not enough memory in 16b heap\n", wFormat);
1015 else
1017 if( lpRender->wFormatID == CF_METAFILEPICT )
1019 FIXME("\timplement function CopyMetaFilePict32to16\n");
1020 FIXME("\tin the appropriate file.\n");
1021 #ifdef SOMEONE_IMPLEMENTED_ME
1022 CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16),
1023 GlobalLock(lpRender->hData32) );
1024 #endif
1026 else
1028 memcpy( GlobalLock16(lpRender->hData16),
1029 GlobalLock(lpRender->hData32),
1030 size );
1032 GlobalUnlock16(lpRender->hData16);
1033 GlobalUnlock(lpRender->hData32);
1037 TRACE("\treturning %04x (type %i)\n",
1038 lpRender->hData16, lpRender->wFormatID);
1039 return lpRender->hData16;
1043 /**************************************************************************
1044 * GetClipboardData (USER32.@)
1046 HANDLE WINAPI GetClipboardData( UINT wFormat )
1048 LPWINE_CLIPFORMAT lpRender = ClipFormats;
1050 TRACE("(%08X)\n", wFormat);
1052 if (CLIPBOARD_IsLocked())
1054 WARN("Clipboard not opened by calling task!\n");
1055 return 0;
1058 if( wFormat == CF_UNICODETEXT || wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
1060 lpRender = CLIPBOARD_RenderText(wFormat);
1061 if ( !lpRender ) return 0;
1063 else
1065 lpRender = __lookup_format( ClipFormats, wFormat );
1066 if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
1069 /* Convert between 16 -> 32 bit data, if necessary */
1070 if( lpRender->hData16 && !lpRender->hData32
1071 && CLIPBOARD_IsMemoryObject(wFormat) )
1073 int size;
1074 if( lpRender->wFormatID == CF_METAFILEPICT )
1075 size = sizeof( METAFILEPICT );
1076 else
1077 size = GlobalSize16(lpRender->hData16);
1078 lpRender->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE,
1079 size);
1080 if( lpRender->wFormatID == CF_METAFILEPICT )
1082 FIXME("\timplement function CopyMetaFilePict16to32\n");
1083 FIXME("\tin the appropriate file.\n");
1084 #ifdef SOMEONE_IMPLEMENTED_ME
1085 CopyMetaFilePict16to32( GlobalLock16(lpRender->hData32),
1086 GlobalLock(lpRender->hData16) );
1087 #endif
1089 else
1091 memcpy( GlobalLock(lpRender->hData32),
1092 GlobalLock16(lpRender->hData16),
1093 size );
1095 GlobalUnlock(lpRender->hData32);
1096 GlobalUnlock16(lpRender->hData16);
1099 TRACE("\treturning %04x (type %i)\n",
1100 lpRender->hData32, lpRender->wFormatID);
1101 return lpRender->hData32;
1105 /**************************************************************************
1106 * CountClipboardFormats (USER.143)
1108 INT16 WINAPI CountClipboardFormats16(void)
1110 return CountClipboardFormats();
1114 /**************************************************************************
1115 * CountClipboardFormats (USER32.@)
1117 INT WINAPI CountClipboardFormats(void)
1119 INT FormatCount = 0;
1120 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
1122 TRACE("()\n");
1124 while(TRUE)
1126 if (lpFormat == NULL) break;
1128 if( lpFormat->wFormatID != CF_TEXT ) /* Don't count CF_TEXT */
1131 * The format is available if either:
1132 * 1. The data is already in the cache.
1133 * 2. The selection is not owned by us(WINE) and the data is
1134 * available to the clipboard driver.
1136 if ( lpFormat->wDataPresent ||
1137 ( !USER_Driver.pIsSelectionOwner()
1138 && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) ) )
1140 TRACE("\tdata found for format 0x%04x(%s)\n",
1141 lpFormat->wFormatID, CLIPBOARD_GetFormatName(lpFormat->wFormatID, NULL, 0));
1142 FormatCount++;
1146 lpFormat = lpFormat->NextFormat;
1149 /* these are equivalent, adjust the total */
1150 FormatCount += (ClipFormats[CF_UNICODETEXT-1].wDataPresent ||
1151 ClipFormats[CF_TEXT-1].wDataPresent ||
1152 ClipFormats[CF_OEMTEXT-1].wDataPresent) ? 1 : 0;
1154 TRACE("\ttotal %d\n", FormatCount);
1155 return FormatCount;
1158 /**************************************************************************
1159 * EnumClipboardFormats (USER.144)
1161 UINT16 WINAPI EnumClipboardFormats16( UINT16 wFormat )
1163 return EnumClipboardFormats( wFormat );
1167 /**************************************************************************
1168 * EnumClipboardFormats (USER32.@)
1170 UINT WINAPI EnumClipboardFormats( UINT wFormat )
1172 TRACE("(%04X)\n", wFormat);
1174 if (CLIPBOARD_IsLocked())
1176 WARN("Clipboard not opened by calling task!\n");
1177 return 0;
1180 return CLIPBOARD_EnumClipboardFormats(wFormat);
1184 /**************************************************************************
1185 * RegisterClipboardFormatA (USER32.@)
1187 UINT WINAPI RegisterClipboardFormatA( LPCSTR FormatName )
1189 LPWINE_CLIPFORMAT lpNewFormat;
1190 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
1192 if (FormatName == NULL) return 0;
1194 TRACE("('%s') !\n", FormatName);
1196 /* walk format chain to see if it's already registered */
1198 while(TRUE)
1200 if ( !strcasecmp(lpFormat->Name,FormatName) )
1202 lpFormat->wRefCount++;
1203 return lpFormat->wFormatID;
1206 if ( lpFormat->NextFormat == NULL ) break;
1208 lpFormat = lpFormat->NextFormat;
1211 /* allocate storage for new format entry */
1213 lpNewFormat = (LPWINE_CLIPFORMAT)HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPFORMAT));
1214 if(lpNewFormat == NULL) {
1215 WARN("No more memory for a new format!\n");
1216 return 0;
1218 lpFormat->NextFormat = lpNewFormat;
1219 lpNewFormat->wRefCount = 1;
1221 if (!(lpNewFormat->Name = HeapAlloc(GetProcessHeap(), 0, strlen(FormatName)+1 )))
1223 WARN("No more memory for the new format name!\n");
1224 HeapFree(GetProcessHeap(), 0, lpNewFormat);
1225 return 0;
1227 strcpy( lpNewFormat->Name, FormatName );
1228 CharLowerA(lpNewFormat->Name);
1230 lpNewFormat->wDataPresent = 0;
1231 lpNewFormat->hData16 = 0;
1232 lpNewFormat->hDataSrc32 = 0;
1233 lpNewFormat->hData32 = 0;
1234 lpNewFormat->drvData = 0;
1235 lpNewFormat->PrevFormat = lpFormat;
1236 lpNewFormat->NextFormat = NULL;
1238 /* Pass on the registration request to the driver */
1239 lpNewFormat->wFormatID = USER_Driver.pRegisterClipboardFormat(lpNewFormat->Name);
1241 TRACE("Registering format(%d): %s\n", lpNewFormat->wFormatID, FormatName);
1242 return lpNewFormat->wFormatID;
1246 /**************************************************************************
1247 * RegisterClipboardFormat (USER.145)
1249 UINT16 WINAPI RegisterClipboardFormat16( LPCSTR FormatName )
1251 return RegisterClipboardFormatA( FormatName );
1255 /**************************************************************************
1256 * RegisterClipboardFormatW (USER32.@)
1258 UINT WINAPI RegisterClipboardFormatW( LPCWSTR formatName )
1260 LPSTR aFormat = HEAP_strdupWtoA( GetProcessHeap(), 0, formatName );
1261 UINT ret = RegisterClipboardFormatA( aFormat );
1262 HeapFree( GetProcessHeap(), 0, aFormat );
1263 return ret;
1267 /**************************************************************************
1268 * GetClipboardFormatName (USER.146)
1270 INT16 WINAPI GetClipboardFormatName16( UINT16 wFormat, LPSTR retStr, INT16 maxlen )
1272 return GetClipboardFormatNameA( wFormat, retStr, maxlen );
1276 /**************************************************************************
1277 * GetClipboardFormatNameA (USER32.@)
1279 INT WINAPI GetClipboardFormatNameA( UINT wFormat, LPSTR retStr, INT maxlen )
1281 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
1283 TRACE("(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
1285 if (lpFormat == NULL || lpFormat->Name == NULL)
1287 /* Check if another wine process already registered the format */
1288 if (wFormat && !USER_Driver.pGetClipboardFormatName(wFormat, retStr, maxlen))
1290 RegisterClipboardFormatA(retStr); /* Make a cache entry */
1291 return strlen(retStr);
1293 else
1295 TRACE("wFormat=%d not found\n", wFormat);
1296 return 0;
1300 TRACE("Name='%s' !\n", lpFormat->Name);
1302 lstrcpynA( retStr, lpFormat->Name, maxlen );
1303 return strlen(retStr);
1307 /**************************************************************************
1308 * GetClipboardFormatNameW (USER32.@)
1310 INT WINAPI GetClipboardFormatNameW( UINT wFormat, LPWSTR retStr, INT maxlen )
1312 INT ret;
1313 LPSTR p = HeapAlloc( GetProcessHeap(), 0, maxlen );
1314 if(p == NULL) return 0; /* FIXME: is this the correct failure value? */
1316 ret = GetClipboardFormatNameA( wFormat, p, maxlen );
1318 if (maxlen > 0 && !MultiByteToWideChar( CP_ACP, 0, p, -1, retStr, maxlen ))
1319 retStr[maxlen-1] = 0;
1320 HeapFree( GetProcessHeap(), 0, p );
1321 return ret;
1325 /**************************************************************************
1326 * SetClipboardViewer (USER32.@)
1328 HWND WINAPI SetClipboardViewer( HWND hWnd )
1330 HWND hwndPrev = hWndViewer;
1332 TRACE("(%04x): returning %04x\n", hWnd, hwndPrev);
1334 hWndViewer = WIN_GetFullHandle( hWnd );
1335 return hwndPrev;
1339 /**************************************************************************
1340 * GetClipboardViewer (USER32.@)
1342 HWND WINAPI GetClipboardViewer(void)
1344 TRACE("()\n");
1345 return hWndViewer;
1349 /**************************************************************************
1350 * ChangeClipboardChain (USER32.@)
1352 BOOL WINAPI ChangeClipboardChain(HWND hWnd, HWND hWndNext)
1354 BOOL bRet = 0;
1356 FIXME("(0x%04x, 0x%04x): stub?\n", hWnd, hWndNext);
1358 if( hWndViewer )
1359 bRet = !SendMessageW( hWndViewer, WM_CHANGECBCHAIN, (WPARAM)hWnd, (LPARAM)hWndNext );
1360 else
1361 WARN("hWndViewer is lost\n");
1363 if( WIN_GetFullHandle(hWnd) == hWndViewer ) hWndViewer = WIN_GetFullHandle( hWndNext );
1365 return bRet;
1369 /**************************************************************************
1370 * IsClipboardFormatAvailable (USER.193)
1372 BOOL16 WINAPI IsClipboardFormatAvailable16( UINT16 wFormat )
1374 return IsClipboardFormatAvailable( wFormat );
1378 /**************************************************************************
1379 * IsClipboardFormatAvailable (USER32.@)
1381 BOOL WINAPI IsClipboardFormatAvailable( UINT wFormat )
1383 BOOL bRet;
1385 if (wFormat == 0) /* Reject this case quickly */
1386 bRet = FALSE;
1387 else
1389 UINT iret = CLIPBOARD_EnumClipboardFormats(wFormat - 1);
1390 if ((wFormat == CF_TEXT) || (wFormat == CF_OEMTEXT) || (wFormat == CF_UNICODETEXT))
1391 bRet = ((iret == CF_TEXT) || (iret == CF_OEMTEXT) || (iret == CF_UNICODETEXT));
1392 else
1393 bRet = iret == wFormat;
1395 TRACE("(%04X)- ret(%d)\n", wFormat, bRet);
1396 return bRet;
1400 /**************************************************************************
1401 * GetOpenClipboardWindow (USER32.@)
1402 * FIXME: This wont work if an external app owns the selection
1404 HWND WINAPI GetOpenClipboardWindow(void)
1406 TRACE("()\n");
1407 return hWndClipWindow;
1411 /**************************************************************************
1412 * GetPriorityClipboardFormat (USER32.@)
1414 INT WINAPI GetPriorityClipboardFormat( UINT *list, INT nCount )
1416 int i;
1417 TRACE("()\n");
1419 if(CountClipboardFormats() == 0) return 0;
1421 for (i = 0; i < nCount; i++)
1422 if (IsClipboardFormatAvailable( list[i] )) return list[i];
1423 return -1;
1427 /**************************************************************************
1428 * GetClipboardSequenceNumber (USER32.@)
1429 * Supported on Win2k/Win98
1430 * MSDN: Windows clipboard code keeps a serial number for the clipboard
1431 * for each window station. The number is incremented whenever the
1432 * contents change or are emptied.
1433 * If you do not have WINSTA_ACCESSCLIPBOARD then the function returns 0
1435 DWORD WINAPI GetClipboardSequenceNumber(VOID)
1437 FIXME("Returning 0, see windows/clipboard.c\n");
1438 /* FIXME: Use serial numbers */
1439 return 0;