/* * X11 windows driver * * Copyright 1994 Martin Ayotte * 1996 Alex Korobka */ #include "config.h" #ifndef X_DISPLAY_MISSING #include #include "ts_xlib.h" #include "clipboard.h" #include "debug.h" #include "message.h" #include "win.h" #include "wintypes.h" #include "x11drv.h" extern HWND32 hWndClipOwner; extern HWND32 hWndClipWindow; extern 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) { HANDLE32 hText = 0; LPCLIPFORMAT 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=GlobalAlloc32(GMEM_MOVEABLE, nitems + inlcount + 1); if( (lpstr = (char*)GlobalLock32(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, HWND32 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(UINT32 wFormat) { Window owner; /* Acquire X selection if text format */ if( !selectionAcquired && (wFormat == CF_TEXT || wFormat == CF_OEMTEXT) ) { owner = X11DRV_WND_FindXWindow( WIN_FindWndPtr( hWndClipWindow ? hWndClipWindow : AnyPopup32() ) ); 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); } } } /************************************************************************** * X11DRV_CLIPBOARD_RequestSelection */ BOOL32 X11DRV_CLIPBOARD_RequestSelection() { HWND32 hWnd = (hWndClipWindow) ? hWndClipWindow : GetActiveWindow32(); 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( WIN_FindWndPtr( hWnd ) ), CurrentTime); /* 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 (BOOL32)ClipFormats[CF_OEMTEXT-1].wDataPresent; } /************************************************************************** * X11DRV_CLIPBOARD_ResetOwner * * Called from DestroyWindow(). */ void X11DRV_CLIPBOARD_ResetOwner(WND *pWnd, BOOL32 bFooBar) { LPCLIPFORMAT 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) */