Sweden-Number/windows/x11drv/clipboard.c

312 lines
8.2 KiB
C

/*
* X11 windows driver
*
* Copyright 1994 Martin Ayotte
* 1996 Alex Korobka
*/
#include "config.h"
#ifndef X_DISPLAY_MISSING
#include <X11/Xatom.h>
#include "ts_xlib.h"
#include "clipboard.h"
#include "debug.h"
#include "message.h"
#include "win.h"
#include "windef.h"
#include "x11drv.h"
extern HWND hWndClipOwner;
extern HWND hWndClipWindow;
extern WINE_CLIPFORMAT ClipFormats[];
static Bool selectionWait = False;
static Bool selectionAcquired = False;
static Window selectionWindow = None;
static Window selectionPrevWindow = None;
/**************************************************************************
* X11DRV_CLIPBOARD_CheckSelection [Internal]
*
* Prevent X selection from being lost when a top level window is
* destroyed.
*/
static void X11DRV_CLIPBOARD_CheckSelection(WND* pWnd)
{
TRACE(clipboard,"\tchecking %08x\n",
(unsigned) X11DRV_WND_GetXWindow(pWnd)
);
if( selectionAcquired && selectionWindow != None &&
X11DRV_WND_GetXWindow(pWnd) == selectionWindow )
{
selectionPrevWindow = selectionWindow;
selectionWindow = None;
if( pWnd->next )
selectionWindow = X11DRV_WND_GetXWindow(pWnd->next);
else if( pWnd->parent )
if( pWnd->parent->child != pWnd )
selectionWindow = X11DRV_WND_GetXWindow(pWnd->parent->child);
TRACE(clipboard,"\tswitching selection from %08x to %08x\n",
(unsigned)selectionPrevWindow, (unsigned)selectionWindow);
if( selectionWindow != None )
{
TSXSetSelectionOwner(display, XA_PRIMARY, selectionWindow, CurrentTime);
if( TSXGetSelectionOwner(display, XA_PRIMARY) != selectionWindow )
selectionWindow = None;
}
}
}
/**************************************************************************
* X11DRV_CLIPBOARD_ReadSelection
*
* Called from the SelectionNotify event handler.
*/
void X11DRV_CLIPBOARD_ReadSelection(Window w,Atom prop)
{
HANDLE hText = 0;
LPWINE_CLIPFORMAT lpFormat = ClipFormats;
TRACE(clipboard,"ReadSelection callback\n");
if(prop != None)
{
Atom atype=AnyPropertyType;
int aformat;
unsigned long nitems,remain;
unsigned char* val=NULL;
TRACE(clipboard,"\tgot property %s\n",TSXGetAtomName(display,prop));
/* TODO: Properties longer than 64K */
if(TSXGetWindowProperty(display,w,prop,0,0x3FFF,True,XA_STRING,
&atype, &aformat, &nitems, &remain, &val) != Success)
WARN(clipboard, "\tcouldn't read property\n");
else
{
TRACE(clipboard,"\tType %s,Format %d,nitems %ld,value %s\n",
TSXGetAtomName(display,atype),aformat,nitems,val);
if(atype == XA_STRING && aformat == 8)
{
int i,inlcount = 0;
char* lpstr;
TRACE(clipboard,"\tselection is '%s'\n",val);
for(i=0; i <= nitems; i++)
if( val[i] == '\n' ) inlcount++;
if( nitems )
{
hText=GlobalAlloc(GMEM_MOVEABLE, nitems + inlcount + 1);
if( (lpstr = (char*)GlobalLock(hText)) )
for(i=0,inlcount=0; i <= nitems; i++)
{
if( val[i] == '\n' ) lpstr[inlcount++]='\r';
lpstr[inlcount++]=val[i];
}
else hText = 0;
}
}
TSXFree(val);
}
}
/* delete previous CF_TEXT and CF_OEMTEXT data */
if( hText )
{
lpFormat = &ClipFormats[CF_TEXT-1];
if (lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32)
CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
lpFormat = &ClipFormats[CF_OEMTEXT-1];
if (lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32)
CLIPBOARD_DeleteRecord(lpFormat, !(hWndClipWindow));
lpFormat->wDataPresent = 1;
lpFormat->hData32 = hText;
lpFormat->hData16 = 0;
}
selectionWait=False;
}
/**************************************************************************
* X11DRV_CLIPBOARD_ReleaseSelection
*
* Wine might have lost XA_PRIMARY selection because of
* EmptyClipboard() or other client.
*/
void X11DRV_CLIPBOARD_ReleaseSelection(Window w, HWND hwnd)
{
/* w is the window that lost selection,
*
* selectionPrevWindow is nonzero if CheckSelection() was called.
*/
TRACE(clipboard,"\tevent->window = %08x (sw = %08x, spw=%08x)\n",
(unsigned)w, (unsigned)selectionWindow, (unsigned)selectionPrevWindow );
if( selectionAcquired )
{
if( w == selectionWindow || selectionPrevWindow == None)
{
/* alright, we really lost it */
selectionAcquired = False;
selectionWindow = None;
/* but we'll keep existing data for internal use */
}
else if( w == selectionPrevWindow )
{
w = TSXGetSelectionOwner(display, XA_PRIMARY);
if( w == None )
TSXSetSelectionOwner(display, XA_PRIMARY, selectionWindow, CurrentTime);
}
}
selectionPrevWindow = None;
}
/**************************************************************************
* X11DRV_CLIPBOARD_EmptyClipboard
*/
void X11DRV_CLIPBOARD_EmptyClipboard()
{
if(selectionAcquired)
{
selectionAcquired = False;
selectionPrevWindow = selectionWindow;
selectionWindow = None;
TRACE(clipboard, "\tgiving up selection (spw = %08x)\n",
(unsigned)selectionPrevWindow);
TSXSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
}
}
/**************************************************************************
* X11DRV_CLIPBOARD_SetClipboardData
*/
void X11DRV_CLIPBOARD_SetClipboardData(UINT wFormat)
{
Window owner;
/* Acquire X selection if text format */
if( !selectionAcquired &&
(wFormat == CF_TEXT || wFormat == CF_OEMTEXT) )
{
WND *tmpWnd = WIN_FindWndPtr( hWndClipWindow ? hWndClipWindow : AnyPopup() );
owner = X11DRV_WND_FindXWindow(tmpWnd );
TSXSetSelectionOwner(display,XA_PRIMARY, owner, CurrentTime);
if( TSXGetSelectionOwner(display,XA_PRIMARY) == owner )
{
selectionAcquired = True;
selectionWindow = owner;
TRACE(clipboard,"Grabbed X selection, owner=(%08x)\n",
(unsigned) owner);
}
WIN_ReleaseWndPtr(tmpWnd);
}
}
/**************************************************************************
* X11DRV_CLIPBOARD_RequestSelection
*/
BOOL X11DRV_CLIPBOARD_RequestSelection()
{
HWND hWnd = (hWndClipWindow) ? hWndClipWindow : GetActiveWindow();
WND *tmpWnd = WIN_FindWndPtr(hWnd);
if( selectionAcquired )
return TRUE;
if( !hWnd ) return FALSE;
TRACE(clipboard,"Requesting selection...\n");
/* request data type XA_STRING, later
* CLIPBOARD_ReadSelection() will be invoked
* from the SelectionNotify event handler */
TSXConvertSelection(display, XA_PRIMARY, XA_STRING,
TSXInternAtom(display, "PRIMARY_TEXT", False),
X11DRV_WND_FindXWindow(tmpWnd ),
CurrentTime);
WIN_ReleaseWndPtr(tmpWnd);
/* wait until SelectionNotify is processed
*
* FIXME: Use TSXCheckTypedWindowEvent() instead ( same in the
* CLIPBOARD_CheckSelection() ).
*/
selectionWait=True;
while(selectionWait) EVENT_WaitNetEvent( TRUE, FALSE );
/* we treat Unix text as CF_OEMTEXT */
TRACE(clipboard,"\tgot CF_OEMTEXT = %i\n",
ClipFormats[CF_OEMTEXT-1].wDataPresent);
return (BOOL)ClipFormats[CF_OEMTEXT-1].wDataPresent;
}
/**************************************************************************
* X11DRV_CLIPBOARD_ResetOwner
*
* Called from DestroyWindow().
*/
void X11DRV_CLIPBOARD_ResetOwner(WND *pWnd, BOOL bFooBar)
{
LPWINE_CLIPFORMAT lpFormat = ClipFormats;
if(bFooBar && X11DRV_WND_GetXWindow(pWnd))
return;
if(!bFooBar && !X11DRV_WND_GetXWindow(pWnd))
return;
TRACE(clipboard,"clipboard owner = %04x, selection = %08x\n",
hWndClipOwner, (unsigned)selectionWindow);
if( pWnd->hwndSelf == hWndClipOwner)
{
SendMessage16(hWndClipOwner,WM_RENDERALLFORMATS,0,0L);
/* check if all formats were rendered */
while(lpFormat)
{
if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
{
TRACE(clipboard,"\tdata missing for clipboard format %i\n",
lpFormat->wFormatID);
lpFormat->wDataPresent = 0;
}
lpFormat = lpFormat->NextFormat;
}
hWndClipOwner = 0;
}
/* now try to salvage current selection from being destroyed by X */
if( X11DRV_WND_GetXWindow(pWnd) ) X11DRV_CLIPBOARD_CheckSelection(pWnd);
}
#endif /* !defined(X_DISPLAY_MISSING) */