327 lines
8.6 KiB
C
327 lines
8.6 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 "wine/winuser16.h"
|
|
#include "clipboard.h"
|
|
#include "debug.h"
|
|
#include "message.h"
|
|
#include "win.h"
|
|
#include "windef.h"
|
|
#include "x11drv.h"
|
|
|
|
DEFAULT_DEBUG_CHANNEL(clipboard)
|
|
|
|
extern HWND hWndClipOwner;
|
|
extern HWND hWndClipWindow;
|
|
extern WINE_CLIPFORMAT ClipFormats[];
|
|
|
|
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
|
|
*/
|
|
static void X11DRV_CLIPBOARD_ReadSelection(Window w, Atom prop)
|
|
{
|
|
HANDLE hText = 0;
|
|
LPWINE_CLIPFORMAT lpFormat = ClipFormats;
|
|
|
|
TRACE(clipboard,"Reading X selection...\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;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
* 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_Empty
|
|
*/
|
|
void X11DRV_CLIPBOARD_Empty()
|
|
{
|
|
if( selectionAcquired )
|
|
{
|
|
XEvent xe;
|
|
|
|
selectionAcquired = False;
|
|
selectionPrevWindow = selectionWindow;
|
|
selectionWindow = None;
|
|
|
|
TRACE(clipboard, "\tgiving up selection (spw = %08x)\n",
|
|
(unsigned)selectionPrevWindow);
|
|
|
|
EnterCriticalSection(&X11DRV_CritSection);
|
|
XSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
|
|
|
|
if( selectionPrevWindow )
|
|
while( !XCheckTypedWindowEvent( display, selectionPrevWindow,
|
|
SelectionClear, &xe ) );
|
|
LeaveCriticalSection(&X11DRV_CritSection);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
* X11DRV_CLIPBOARD_SetData
|
|
*/
|
|
void X11DRV_CLIPBOARD_SetData(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_GetData
|
|
*
|
|
* NOTE: Clipboard driver doesn't get requests for CF_TEXT data, only
|
|
* for CF_OEMTEXT.
|
|
*/
|
|
BOOL X11DRV_CLIPBOARD_GetData(UINT wFormat)
|
|
{
|
|
BOOL bRet = selectionAcquired;
|
|
HWND hWnd = (hWndClipWindow) ? hWndClipWindow : GetActiveWindow();
|
|
WND* wnd = NULL;
|
|
|
|
if( wFormat != CF_OEMTEXT ) return FALSE;
|
|
|
|
if( !bRet && (wnd = WIN_FindWndPtr(hWnd)) )
|
|
{
|
|
XEvent xe;
|
|
Window w = X11DRV_WND_FindXWindow(wnd);
|
|
|
|
TRACE(clipboard, "Requesting XA_STRING selection...\n");
|
|
|
|
EnterCriticalSection( &X11DRV_CritSection );
|
|
XConvertSelection(display, XA_PRIMARY, XA_STRING,
|
|
XInternAtom(display, "PRIMARY_TEXT", False),
|
|
w, CurrentTime);
|
|
|
|
/* wait until SelectionNotify is received */
|
|
|
|
while( TRUE )
|
|
{
|
|
if( XCheckTypedWindowEvent(display, w, SelectionNotify, &xe) )
|
|
if( xe.xselection.selection == XA_PRIMARY )
|
|
break;
|
|
}
|
|
LeaveCriticalSection( &X11DRV_CritSection );
|
|
|
|
if (xe.xselection.target != XA_STRING)
|
|
X11DRV_CLIPBOARD_ReadSelection( 0, None );
|
|
else
|
|
X11DRV_CLIPBOARD_ReadSelection( xe.xselection.requestor,
|
|
xe.xselection.property );
|
|
|
|
/* treat Unix text as CF_OEMTEXT */
|
|
|
|
bRet = (BOOL)ClipFormats[CF_OEMTEXT-1].wDataPresent;
|
|
|
|
TRACE(clipboard,"\tpresent CF_OEMTEXT = %i\n", bRet );
|
|
WIN_ReleaseWndPtr(wnd);
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* 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) */
|