| /* |
| * 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" |
| |
| 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) */ |