/*    
	Clipboard.c	2.23
    	Copyright 1997 Willows Software, Inc. 

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.


For more information about the Willows Twin Libraries.

	http://www.willows.com	

To send email to the maintainer of the Willows Twin Libraries.

	mailto:twin@willows.com 

 */

#include <string.h>
#include "windows.h"
#include "GdiObjects.h"
#include "Clipboard.h"
#include "WinDefs.h"
#include "Driver.h"
#include "Log.h"

BOOL TWIN_InternalClipboard(DWORD, DWORD);

/* all clipboard data is contained here */
static DRVCLIPINFO drvci;
static CLIPTABLE   cb = { 0, 0, 0, 0, 0, &drvci };

/***************************************************************************/
BOOL TWIN_InternalClipboard(DWORD clipchange, DWORD cliptime)
{
    register  i;
    HWND      hWnd;

    switch(clipchange)
    {
    case 0L:
       hWnd = GetClipboardOwner();
       if (IsWindow(hWnd))
          SendMessage(hWnd, WM_DESTROYCLIPBOARD, 0, 0L);
       cb.lpDrvData->ClipboardTime = cliptime;
       break;

    case 1L:
       cb.lpDrvData->CutBufferTime = cb.hwndOpen ? 0 : cliptime;
       break;
 
    case 2L:
       for (i = 0;   i < cb.ViewerCount;   i++)
           {
           if (cb.ViewerList[i])
              SendMessage(cb.ViewerList[i], WM_DRAWCLIPBOARD, 0, 0L);
           }
       break;
    } 
    return 1;
}


/***************************************************************************/
BOOL WINAPI
OpenClipboard(HWND hWnd)
{
    BOOL  ynSuccess; 
    DWORD win = WIN_GETDRVDATA(TWIN_GetTopLevelFrame(hWnd));

    APISTR((LF_API,"OpenClipboard: hWnd %x\n", hWnd));

    if (cb.hwndOwner) 
       {
       LOGSTR((LF_LOG,"OpenClipboard ERROR: already open, returning FALSE\n"));
       return FALSE;
       }

    if (!win || !hWnd || !IsWindow(hWnd)) 
        {
	LOGSTR((LF_LOG,"OpenClipboard ERROR: bogus hWnd, returning FALSE\n"));
	return FALSE;
        }

    cb.hwndOwner = cb.hwndOpen = hWnd;
    ynSuccess = (BOOL)DRVCALL_IPC(IPCH_OPENCLIPBRD, 0L, win, cb.lpDrvData);

    if (!ynSuccess)
       cb.hwndOwner = cb.hwndOpen = 0;
    return ynSuccess;   
}

/****************************************************************************/
BOOL WINAPI
CloseClipboard(void)
{
    APISTR((LF_API,"CloseClipboard\n"));
    /*
    **   Release all X related stuff first...
    */
    DRVCALL_IPC(IPCH_CLOSECLIPBRD, 0L, 0L, cb.lpDrvData);
    cb.hwndOwner = 0;
    cb.hwndOpen  = 0;
    LOGSTR((LF_API,"CloseClipboard: complete.\n"));
    return TRUE;
 
    /* we did not have it open */
    /* return FALSE;*/
}

/****************************************************************************/
BOOL WINAPI
EmptyClipboard(void)
{
    HWND   hWnd;

    APISTR((LF_API,"EmptyClipboard\n"));
    /*
    **  Do we have it open? 
    **  we could read the format to verify it is us...      
    */
    if (cb.hwndOpen) 
       {
       hWnd = GetClipboardOwner();
       if (IsWindow(hWnd))
          SendMessage(hWnd, WM_DESTROYCLIPBOARD, 0, 0L);
       return (BOOL)DRVCALL_IPC(IPCH_EMPTYCLIPBRD, 0L, 0L, cb.lpDrvData);
       }
    return 0;
}

/****************************************************************************/
HWND WINAPI
GetOpenClipboardWindow(void)
{
    APISTR((LF_API,"GetOpenClipboardWindow: returning %x\n",
			cb.hwndOpen));
    return cb.hwndOpen;
}

/****************************************************************************/
HWND WINAPI
GetClipboardOwner(void)
{
    APISTR((LF_API,"GetOpenClipboardWindow: returning %x\n",
			cb.hwndOwner));
    return cb.hwndOwner;
}

/****************************************************************************/
HWND WINAPI
GetClipboardViewer(void)
{
        register  i;

        LOGSTR((LF_SHARED,"GetClipboardViewer:\n"));
        if (cb.ViewerList) 
           {
           for (i = 0;   i < cb.ViewerCount;   i++)
               if (cb.ViewerList[i])
                  return cb.ViewerList[i];
           }
        return (HWND)NULL;
}

/****************************************************************************/
HWND WINAPI
SetClipboardViewer(HWND hWnd)
{
        register  i;
        LOGSTR((LF_SHARED,"SetClipboardViewer: %x\n",hWnd));
 
        /* try to insert into a list if we have one */
        if (cb.ViewerList) 
           {
           for (i = 0;   i < cb.ViewerCount;   i++) 
               {
               if (cb.ViewerList[i])
                  continue;
               /* we have a slot */
               cb.ViewerList[i] = hWnd;
               return 0;
               }
           }
        /* the remainder of these are guaranteed to be at end of list */
        if (cb.ViewerList == 0) 
           {
           /* no list so allocate one */
           cb.ViewerList = (HWND *) WinMalloc(sizeof(HWND));
           } 
        else {
             /* expand the current list */
             cb.ViewerList = (HWND *) WinRealloc((char *)cb.ViewerList,
                                                 (cb.ViewerCount+1)*sizeof(HWND));
             }
        /* fill in the new slot */
        cb.ViewerList[cb.ViewerCount++] = hWnd;
        return (HWND)NULL;
}

/****************************************************************************/
HANDLE WINAPI
GetClipboardData(UINT uiFormat)
{
    GETSETDATA gd;
    HANDLE     hMem   = (HANDLE)0;
    LPSTR      lpData = NULL;

    APISTR((LF_API,"GetClipboardData(format=%x)\n", uiFormat ));

    gd.uiFormat = uiFormat;
    gd.dwSize   = 0L;
    gd.lpMem    = NULL;

    if (DRVCALL_IPC(IPCH_GETCLIPBRDDATA, 0, &gd, cb.lpDrvData) == 0L)
       return 0;

    if (uiFormat == CF_BITMAP)
       {
       HBITMAP hbmp;
       LPIMAGEINFO lpii;
 
       if (cb.hbmpClip)
          DeleteObject(cb.hbmpClip);

       lpii = CREATEHBITMAP(hbmp);
       hMem = cb.hbmpClip = hbmp;
       memcpy(gd.lpMem, (LPSTR)lpii, sizeof(OBJHEAD));
       memcpy((LPSTR)lpii, gd.lpMem, sizeof(IMAGEINFO));
       RELEASEBITMAPINFO(lpii);
       }
    else {           
         hMem = GlobalAlloc(GHND, gd.dwSize);
         if (!hMem)
            APISTR((LF_API, "GetClipboardData: GlobalAlloc failed...\n"));
         else {
              lpData = GlobalLock(hMem); 
              memcpy(lpData, gd.lpMem, gd.dwSize);
              GlobalUnlock(hMem);
              }
         }
    WinFree(gd.lpMem);
    return hMem;
}

/****************************************************************************/
HANDLE WINAPI
SetClipboardData(UINT uiFormat, HANDLE hData)
{
    register     i;
    GETSETDATA   sd;

    APISTR((LF_API,"SetClipboardData: format '%d', handle '%x'\n", uiFormat, hData));
    if (cb.hwndOpen)
       {
       /*   If hData is NULL, we send WM_RENDERFORMAT to clipboard owner...
       */
       if (!hData)
          SendMessage(cb.hwndOwner, WM_RENDERFORMAT, uiFormat, 0L);
       else {
            sd.uiFormat = uiFormat;
            if (sd.uiFormat != CF_BITMAP)
               {
               sd.dwSize = GlobalSize(hData);
               sd.lpMem = GlobalLock(hData);
		
 	       /* for text, cut the length to the ascii string length */	
	       if(sd.uiFormat == CF_TEXT) 
	           sd.dwSize = strlen(sd.lpMem);

               DRVCALL_IPC(IPCH_SETCLIPBRDDATA, 0, &sd, cb.lpDrvData);
               GlobalUnlock(hData);
               }
            else {
                 LPIMAGEINFO lpim;

                 lpim = GETBITMAPINFO(hData);
                 if (!lpim)
                     return 0;
                 sd.lpMem = (LPSTR)lpim->lpDrvData;
                 DRVCALL_IPC(IPCH_SETCLIPBRDDATA, 0, &sd, cb.lpDrvData);
		 RELEASEBITMAPINFO(lpim);
                 }
            /*
            **   Force a reload of formats and data...
            */
            for (i = 0;   i < cb.ViewerCount;   i++)
                {
                if (cb.ViewerList[i])
                   SendMessage(cb.ViewerList[i], WM_DRAWCLIPBOARD, 0, 0L);
                }
            return hData;
            }
      }
    return 0;
}

/****************************************************************************/
BOOL WINAPI
IsClipboardFormatAvailable(UINT uiFormat)
{
        BOOL ynIs = DRVCALL_IPC(IPCH_ISFORMATAVAIL, uiFormat, 0L, 0L);

        LOGSTR((LF_SHARED,"IsClipboardFormatAvailable: %x, %s\n",uiFormat, ynIs ? "Yes":"No"));

        return ynIs;
}

/****************************************************************************/
int WINAPI
GetPriorityClipboardFormat(UINT *lpuiPriorityList, int cEntries)
{
        int nitems;
 
        LOGSTR((LF_SHARED,"GetPriorityClipboardFormat:\n"));
 
        nitems = CountClipboardFormats();
        if (nitems == 0)
           return 0;

#ifdef LATER 
        LOGSTR((LF_SHARED,"#formats=%x\n",nitems));
        for (n = 0;  n < cEntries;  n++) 
            {
	    CLIPENTRY *lpce;
	    int i;

            LOGSTR((LF_SHARED,"%d check format=%x\n",n,lpuiPriorityList[n]));

            lpce = cb.lpDrvData->FormatData;
            for (i = 0;  i < nitems;  i++) 
                {
                if (lpce->wFormat == lpuiPriorityList[n])
                   return (int) lpce->wFormat;
                lpce++;
                }
            }
#endif

        LOGSTR((LF_SHARED,"format not available but data is\n"));
        return -1;
}


/****************************************************************************/
int WINAPI
CountClipboardFormats(void)
{
        LOGSTR((LF_SHARED,"CountClipboardFormats\n"));
        return (int)DRVCALL_IPC(IPCH_LOADFORMATS, 0L, 0L, cb.lpDrvData);
}

/****************************************************************************/
UINT WINAPI
EnumClipboardFormats(UINT uiFormat)
{
        LOGSTR((LF_SHARED,"EnumClipboardFormats: %x\n", uiFormat));
        return cb.hwndOpen ? (UINT)DRVCALL_IPC(IPCH_ENUMFORMATS, uiFormat, 0L, 0L) : 0;
}

/****************************************************************************/
int WINAPI
GetClipboardFormatName(UINT uFormat, LPSTR lpszFormatName, int cbMax)
{
    int len;

    LOGSTR((LF_SHARED,"GetClipboardFormatName %x\n",uFormat));
    if (uFormat < 0xCC00)
       return 0; /* predefined formats don't have names */
    len = GlobalGetAtomName(uFormat,lpszFormatName,cbMax);
    LOGSTR((LF_SHARED,"GetClipboardFormatName: format '%x', '%s', length '%d'\n",uFormat, lpszFormatName, len));
    return len;
}

/****************************************************************************/
BOOL WINAPI
ChangeClipboardChain(HWND hWnd, HWND hWndNext)
{
	register  i;
        LOGSTR((LF_SHARED,"SetClipboardViewer: %x %x\n",hWnd,hWndNext));
 
        if (cb.ViewerList) 
           {
           for (i = 0;   i < cb.ViewerCount;   i++) 
               {
               if (cb.ViewerList[i] == hWnd) 
                  {
                  cb.ViewerList[i] = 0;
                  return TRUE;
                  }
               }
           }
        return FALSE;
}

/****************************************************************************/
UINT WINAPI
RegisterClipboardFormat(LPCSTR lpszFormat)
{
    UINT uiAtom;

    uiAtom = GlobalAddAtom(lpszFormat);
    /*call driver to add new format to FormatData property under unique ID */

    DRVCALL_IPC(IPCH_REGISTERFORMAT, 0L, uiAtom, lpszFormat);
    return uiAtom;
}

