winex11: Run a single clipboard manager thread per window station, inside the explorer process.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
a46d736012
commit
a52d09198d
|
@ -87,7 +87,6 @@
|
|||
#include "wine/list.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "wine/server.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
|
||||
|
||||
|
@ -97,25 +96,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
|
|||
|
||||
#define SELECTION_UPDATE_DELAY 2000 /* delay between checks of the X11 selection */
|
||||
|
||||
/* Selection masks */
|
||||
#define S_NOSELECTION 0
|
||||
#define S_PRIMARY 1
|
||||
#define S_CLIPBOARD 2
|
||||
|
||||
typedef BOOL (*EXPORTFUNC)( Display *display, Window win, Atom prop, Atom target, HANDLE handle );
|
||||
typedef HANDLE (*IMPORTFUNC)( Atom type, const void *data, size_t size );
|
||||
|
||||
typedef struct clipboard_format
|
||||
struct clipboard_format
|
||||
{
|
||||
struct list entry;
|
||||
UINT id;
|
||||
Atom atom;
|
||||
IMPORTFUNC import;
|
||||
EXPORTFUNC export;
|
||||
} WINE_CLIPFORMAT, *LPWINE_CLIPFORMAT;
|
||||
|
||||
static int selectionAcquired = 0; /* Contains the current selection masks */
|
||||
static Window selectionWindow = None; /* The top level X window which owns the selection */
|
||||
};
|
||||
|
||||
static HANDLE import_data( Atom type, const void *data, size_t size );
|
||||
static HANDLE import_enhmetafile( Atom type, const void *data, size_t size );
|
||||
|
@ -202,36 +193,16 @@ static struct list format_list = LIST_INIT( format_list );
|
|||
#define NB_BUILTIN_FORMATS (sizeof(builtin_formats) / sizeof(builtin_formats[0]))
|
||||
#define GET_ATOM(prop) (((prop) < FIRST_XATOM) ? (Atom)(prop) : X11DRV_Atoms[(prop) - FIRST_XATOM])
|
||||
|
||||
static DWORD clipboard_thread_id;
|
||||
static HWND clipboard_hwnd;
|
||||
static BOOL is_clipboard_owner;
|
||||
static Window selection_window;
|
||||
static Window import_window;
|
||||
static Atom current_selection;
|
||||
static ULONG64 last_clipboard_update;
|
||||
static struct clipboard_format **current_x11_formats;
|
||||
static unsigned int nb_current_x11_formats;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Internal Clipboard implementation methods
|
||||
**************************************************************************/
|
||||
|
||||
static Window thread_selection_wnd(void)
|
||||
{
|
||||
struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
|
||||
Window w = thread_data->selection_wnd;
|
||||
|
||||
if (!w)
|
||||
{
|
||||
w = XCreateWindow(thread_data->display, root_window, 0, 0, 1, 1, 0, CopyFromParent,
|
||||
InputOnly, CopyFromParent, 0, NULL);
|
||||
if (w)
|
||||
{
|
||||
thread_data->selection_wnd = w;
|
||||
|
||||
XSelectInput(thread_data->display, w, PropertyChangeMask);
|
||||
}
|
||||
else
|
||||
FIXME("Failed to create window. Fetching selection data will fail.\n");
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static const char *debugstr_format( UINT id )
|
||||
{
|
||||
WCHAR buffer[256];
|
||||
|
@ -445,15 +416,6 @@ static void register_x11_formats( const Atom *atoms, UINT size )
|
|||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* X11DRV_InitClipboard
|
||||
*/
|
||||
void X11DRV_InitClipboard(void)
|
||||
{
|
||||
register_builtin_formats();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* put_property
|
||||
*
|
||||
|
@ -1135,19 +1097,21 @@ void X11DRV_CLIPBOARD_ImportSelection( Display *display, Window win, Atom select
|
|||
/**************************************************************************
|
||||
* render_format
|
||||
*/
|
||||
BOOL render_format( Display *display, Window win, Atom selection, UINT id )
|
||||
static void render_format( UINT id )
|
||||
{
|
||||
Display *display = thread_display();
|
||||
unsigned int i;
|
||||
HANDLE handle = 0;
|
||||
|
||||
if (!current_selection) return;
|
||||
|
||||
for (i = 0; i < nb_current_x11_formats; i++)
|
||||
{
|
||||
if (current_x11_formats[i]->id != id) continue;
|
||||
handle = import_selection( display, win, selection, current_x11_formats[i] );
|
||||
handle = import_selection( display, import_window, current_selection, current_x11_formats[i] );
|
||||
if (handle) SetClipboardData( id, handle );
|
||||
break;
|
||||
}
|
||||
return handle != 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1630,7 +1594,7 @@ static BOOL export_selection( Display *display, Window win, Atom prop, Atom targ
|
|||
ret = format->export( display, win, prop, target, 0 );
|
||||
break;
|
||||
}
|
||||
if (!open && !(open = OpenClipboard( 0 )))
|
||||
if (!open && !(open = OpenClipboard( clipboard_hwnd )))
|
||||
{
|
||||
ERR( "failed to open clipboard for %s\n", debugstr_xatom( target ));
|
||||
return FALSE;
|
||||
|
@ -1875,159 +1839,211 @@ static BOOL X11DRV_CLIPBOARD_ReadProperty( Display *display, Window w, Atom prop
|
|||
|
||||
|
||||
/**************************************************************************
|
||||
* X11DRV_CLIPBOARD_ReleaseSelection
|
||||
* acquire_selection
|
||||
*
|
||||
* Release XA_CLIPBOARD and XA_PRIMARY in response to a SelectionClear event.
|
||||
* Acquire the X11 selection when the Win32 clipboard has changed.
|
||||
*/
|
||||
static void X11DRV_CLIPBOARD_ReleaseSelection(Display *display, Atom selType, Window w, HWND hwnd, Time time)
|
||||
static void acquire_selection( Display *display )
|
||||
{
|
||||
/* w is the window that lost the selection
|
||||
*/
|
||||
TRACE("event->window = %08x (selectionWindow = %08x) selectionAcquired=0x%08x\n",
|
||||
(unsigned)w, (unsigned)selectionWindow, (unsigned)selectionAcquired);
|
||||
if (selection_window) XDestroyWindow( display, selection_window );
|
||||
|
||||
if (selectionAcquired && (w == selectionWindow))
|
||||
{
|
||||
/* completely give up the selection */
|
||||
TRACE("Lost CLIPBOARD (+PRIMARY) selection\n");
|
||||
selection_window = XCreateWindow( display, root_window, 0, 0, 1, 1, 0, CopyFromParent,
|
||||
InputOutput, CopyFromParent, 0, NULL );
|
||||
if (!selection_window) return;
|
||||
|
||||
if ((selType == x11drv_atom(CLIPBOARD)) && (selectionAcquired & S_PRIMARY))
|
||||
{
|
||||
TRACE("Lost clipboard. Check if we need to release PRIMARY\n");
|
||||
|
||||
if (selectionWindow == XGetSelectionOwner(display, XA_PRIMARY))
|
||||
{
|
||||
TRACE("We still own PRIMARY. Releasing PRIMARY.\n");
|
||||
XSetSelectionOwner(display, XA_PRIMARY, None, time);
|
||||
}
|
||||
else
|
||||
TRACE("We no longer own PRIMARY\n");
|
||||
}
|
||||
else if ((selType == XA_PRIMARY) && (selectionAcquired & S_CLIPBOARD))
|
||||
{
|
||||
TRACE("Lost PRIMARY. Check if we need to release CLIPBOARD\n");
|
||||
|
||||
if (selectionWindow == XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)))
|
||||
{
|
||||
TRACE("We still own CLIPBOARD. Releasing CLIPBOARD.\n");
|
||||
XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), None, time);
|
||||
}
|
||||
else
|
||||
TRACE("We no longer own CLIPBOARD\n");
|
||||
}
|
||||
|
||||
selectionWindow = None;
|
||||
|
||||
/* Reset the selection flags now that we are done */
|
||||
selectionAcquired = S_NOSELECTION;
|
||||
}
|
||||
XSetSelectionOwner( display, x11drv_atom(CLIPBOARD), selection_window, CurrentTime );
|
||||
if (use_primary_selection) XSetSelectionOwner( display, XA_PRIMARY, selection_window, CurrentTime );
|
||||
TRACE( "win %lx\n", selection_window );
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* X11DRV Clipboard Exports
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
static void selection_acquire(void)
|
||||
* release_selection
|
||||
*
|
||||
* Release the X11 selection when some other X11 app has grabbed it.
|
||||
*/
|
||||
static void release_selection( Display *display, Time time )
|
||||
{
|
||||
Window owner;
|
||||
Display *display;
|
||||
assert( selection_window );
|
||||
|
||||
owner = thread_selection_wnd();
|
||||
display = thread_display();
|
||||
TRACE( "win %lx\n", selection_window );
|
||||
|
||||
selectionAcquired = 0;
|
||||
selectionWindow = 0;
|
||||
/* release PRIMARY if we still own it */
|
||||
if (use_primary_selection && XGetSelectionOwner( display, XA_PRIMARY ) == selection_window)
|
||||
XSetSelectionOwner( display, XA_PRIMARY, None, time );
|
||||
|
||||
/* Grab PRIMARY selection if not owned */
|
||||
if (use_primary_selection)
|
||||
XSetSelectionOwner(display, XA_PRIMARY, owner, CurrentTime);
|
||||
|
||||
/* Grab CLIPBOARD selection if not owned */
|
||||
XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), owner, CurrentTime);
|
||||
|
||||
if (use_primary_selection && XGetSelectionOwner(display, XA_PRIMARY) == owner)
|
||||
selectionAcquired |= S_PRIMARY;
|
||||
|
||||
if (XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)) == owner)
|
||||
selectionAcquired |= S_CLIPBOARD;
|
||||
|
||||
if (selectionAcquired)
|
||||
{
|
||||
selectionWindow = owner;
|
||||
TRACE("Grabbed X selection, owner=(%08x)\n", (unsigned) owner);
|
||||
}
|
||||
XDestroyWindow( display, selection_window );
|
||||
selection_window = 0;
|
||||
}
|
||||
|
||||
static DWORD WINAPI selection_thread_proc(LPVOID p)
|
||||
{
|
||||
HANDLE event = p;
|
||||
|
||||
TRACE("\n");
|
||||
|
||||
selection_acquire();
|
||||
SetEvent(event);
|
||||
|
||||
while (selectionAcquired)
|
||||
{
|
||||
MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_SENDMESSAGE, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* X11DRV_AcquireClipboard
|
||||
* request_selection_contents
|
||||
*
|
||||
* Retrieve the contents of the X11 selection when it's owned by an X11 app.
|
||||
*/
|
||||
void X11DRV_AcquireClipboard(HWND hWndClipWindow)
|
||||
static void request_selection_contents( Display *display )
|
||||
{
|
||||
DWORD procid;
|
||||
HANDLE selectionThread;
|
||||
struct clipboard_format *targets = find_x11_format( x11drv_atom(TARGETS) );
|
||||
struct clipboard_format *string = find_x11_format( XA_STRING );
|
||||
|
||||
TRACE(" %p\n", hWndClipWindow);
|
||||
assert( targets );
|
||||
assert( string );
|
||||
|
||||
/*
|
||||
* It's important that the selection get acquired from the thread
|
||||
* that owns the clipboard window. The primary reason is that we know
|
||||
* it is running a message loop and therefore can process the
|
||||
* X selection events.
|
||||
*/
|
||||
if (hWndClipWindow &&
|
||||
GetCurrentThreadId() != GetWindowThreadProcessId(hWndClipWindow, &procid))
|
||||
current_selection = 0;
|
||||
if (use_primary_selection && XGetSelectionOwner( display, XA_PRIMARY ))
|
||||
{
|
||||
if (procid != GetCurrentProcessId())
|
||||
{
|
||||
WARN("Setting clipboard owner to other process is not supported\n");
|
||||
hWndClipWindow = NULL;
|
||||
}
|
||||
if (import_selection( display, import_window, XA_PRIMARY, targets ))
|
||||
current_selection = XA_PRIMARY;
|
||||
else
|
||||
{
|
||||
TRACE("Thread %x is acquiring selection with thread %x's window %p\n",
|
||||
GetCurrentThreadId(),
|
||||
GetWindowThreadProcessId(hWndClipWindow, NULL), hWndClipWindow);
|
||||
|
||||
SendMessageW(hWndClipWindow, WM_X11DRV_ACQUIRE_SELECTION, 0, 0);
|
||||
return;
|
||||
}
|
||||
import_selection( display, import_window, XA_PRIMARY, string );
|
||||
}
|
||||
|
||||
if (hWndClipWindow)
|
||||
else if (XGetSelectionOwner( display, x11drv_atom(CLIPBOARD) ))
|
||||
{
|
||||
selection_acquire();
|
||||
if (import_selection( display, import_window, x11drv_atom(CLIPBOARD), targets ))
|
||||
current_selection = x11drv_atom(CLIPBOARD);
|
||||
else
|
||||
import_selection( display, import_window, x11drv_atom(CLIPBOARD), string );
|
||||
}
|
||||
else
|
||||
{
|
||||
HANDLE event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
selectionThread = CreateThread(NULL, 0, selection_thread_proc, event, 0, NULL);
|
||||
}
|
||||
|
||||
if (selectionThread)
|
||||
{
|
||||
WaitForSingleObject(event, INFINITE);
|
||||
CloseHandle(selectionThread);
|
||||
}
|
||||
CloseHandle(event);
|
||||
|
||||
/**************************************************************************
|
||||
* grab_win32_clipboard
|
||||
*
|
||||
* Grab the Win32 clipboard when an X11 app has grabbed the X11 selection,
|
||||
* and fill it with the selection contents.
|
||||
*/
|
||||
static BOOL grab_win32_clipboard( Display *display )
|
||||
{
|
||||
if (!OpenClipboard( clipboard_hwnd )) return FALSE;
|
||||
EmptyClipboard();
|
||||
is_clipboard_owner = TRUE;
|
||||
last_clipboard_update = GetTickCount64();
|
||||
request_selection_contents( display );
|
||||
CloseClipboard();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* update_clipboard
|
||||
*
|
||||
* Periodically update the clipboard while the selection is owned by an X11 app.
|
||||
*/
|
||||
BOOL update_clipboard( HWND hwnd )
|
||||
{
|
||||
if (hwnd != clipboard_hwnd) return TRUE;
|
||||
if (!is_clipboard_owner) return TRUE;
|
||||
if (GetTickCount64() - last_clipboard_update <= SELECTION_UPDATE_DELAY) return TRUE;
|
||||
return grab_win32_clipboard( thread_display() );
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* clipboard_wndproc
|
||||
*
|
||||
* Window procedure for the clipboard manager.
|
||||
*/
|
||||
static LRESULT CALLBACK clipboard_wndproc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case WM_NCCREATE:
|
||||
return TRUE;
|
||||
case WM_CLIPBOARDUPDATE:
|
||||
if (is_clipboard_owner) break; /* ignore our own changes */
|
||||
acquire_selection( thread_init_display() );
|
||||
break;
|
||||
case WM_RENDERFORMAT:
|
||||
render_format( wp );
|
||||
break;
|
||||
case WM_DESTROYCLIPBOARD:
|
||||
TRACE( "WM_DESTROYCLIPBOARD: lost ownership\n" );
|
||||
is_clipboard_owner = FALSE;
|
||||
break;
|
||||
}
|
||||
return DefWindowProcW( hwnd, msg, wp, lp );
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* wait_clipboard_mutex
|
||||
*
|
||||
* Make sure that there's only one clipboard thread per window station.
|
||||
*/
|
||||
static BOOL wait_clipboard_mutex(void)
|
||||
{
|
||||
static const WCHAR prefix[] = {'_','_','w','i','n','e','_','c','l','i','p','b','o','a','r','d','_'};
|
||||
WCHAR buffer[MAX_PATH + sizeof(prefix) / sizeof(WCHAR)];
|
||||
HANDLE mutex;
|
||||
|
||||
memcpy( buffer, prefix, sizeof(prefix) );
|
||||
if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_NAME,
|
||||
buffer + sizeof(prefix) / sizeof(WCHAR),
|
||||
sizeof(buffer) - sizeof(prefix), NULL ))
|
||||
{
|
||||
ERR( "failed to get winstation name\n" );
|
||||
return FALSE;
|
||||
}
|
||||
mutex = CreateMutexW( NULL, TRUE, buffer );
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
TRACE( "waiting for mutex %s\n", debugstr_w( buffer ));
|
||||
WaitForSingleObject( mutex, INFINITE );
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* clipboard_thread
|
||||
*
|
||||
* Thread running inside the desktop process to manage the clipboard
|
||||
*/
|
||||
static DWORD WINAPI clipboard_thread( void *arg )
|
||||
{
|
||||
static const WCHAR clipboard_classname[] = {'_','_','w','i','n','e','_','c','l','i','p','b','o','a','r','d','_','m','a','n','a','g','e','r',0};
|
||||
XSetWindowAttributes attr;
|
||||
WNDCLASSW class;
|
||||
MSG msg;
|
||||
Display *display = thread_init_display();
|
||||
|
||||
if (!wait_clipboard_mutex()) return 0;
|
||||
|
||||
attr.event_mask = PropertyChangeMask;
|
||||
import_window = XCreateWindow( display, root_window, 0, 0, 1, 1, 0, CopyFromParent,
|
||||
InputOutput, CopyFromParent, CWEventMask, &attr );
|
||||
if (!import_window)
|
||||
{
|
||||
ERR( "failed to create import window\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset( &class, 0, sizeof(class) );
|
||||
class.lpfnWndProc = clipboard_wndproc;
|
||||
class.lpszClassName = clipboard_classname;
|
||||
|
||||
if (!RegisterClassW( &class ) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
|
||||
{
|
||||
ERR( "could not register clipboard window class err %u\n", GetLastError() );
|
||||
return 0;
|
||||
}
|
||||
if (!(clipboard_hwnd = CreateWindowW( clipboard_classname, NULL, 0, 0, 0, 0, 0,
|
||||
HWND_MESSAGE, 0, 0, NULL )))
|
||||
{
|
||||
ERR( "failed to create clipboard window err %u\n", GetLastError() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
clipboard_thread_id = GetCurrentThreadId();
|
||||
AddClipboardFormatListener( clipboard_hwnd );
|
||||
register_builtin_formats();
|
||||
grab_win32_clipboard( display );
|
||||
|
||||
TRACE( "clipboard thread %04x running\n", GetCurrentThreadId() );
|
||||
while (GetMessageW( &msg, 0, 0, 0 )) DispatchMessageW( &msg );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2038,48 +2054,14 @@ void CDECL X11DRV_UpdateClipboard(void)
|
|||
{
|
||||
static ULONG last_update;
|
||||
ULONG now;
|
||||
DWORD_PTR ret;
|
||||
|
||||
if (selectionAcquired) return;
|
||||
if (GetCurrentThreadId() == clipboard_thread_id) return;
|
||||
now = GetTickCount();
|
||||
if ((int)(now - last_update) <= SELECTION_UPDATE_DELAY) return;
|
||||
last_update = now;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* ResetSelectionOwner
|
||||
*
|
||||
* Called when the thread owning the selection is destroyed and we need to
|
||||
* preserve the selection ownership. We look for another top level window
|
||||
* in this process and send it a message to acquire the selection.
|
||||
*/
|
||||
void X11DRV_ResetSelectionOwner(void)
|
||||
{
|
||||
HWND hwnd;
|
||||
DWORD procid;
|
||||
|
||||
TRACE("\n");
|
||||
|
||||
if (!selectionAcquired || thread_selection_wnd() != selectionWindow)
|
||||
return;
|
||||
|
||||
selectionAcquired = S_NOSELECTION;
|
||||
selectionWindow = 0;
|
||||
|
||||
hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
|
||||
do
|
||||
{
|
||||
if (GetCurrentThreadId() != GetWindowThreadProcessId(hwnd, &procid))
|
||||
{
|
||||
if (GetCurrentProcessId() == procid)
|
||||
{
|
||||
if (SendMessageW(hwnd, WM_X11DRV_ACQUIRE_SELECTION, 0, 0))
|
||||
return;
|
||||
}
|
||||
}
|
||||
} while ((hwnd = GetWindow(hwnd, GW_HWNDNEXT)) != NULL);
|
||||
|
||||
WARN("Failed to find another thread to take selection ownership. Clipboard data will be lost.\n");
|
||||
if (SendMessageTimeoutW( GetClipboardOwner(), WM_X11DRV_UPDATE_CLIPBOARD, 0, 0,
|
||||
SMTO_ABORTIFHUNG, 5000, &ret ) && ret)
|
||||
last_update = now;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2095,12 +2077,13 @@ BOOL X11DRV_SelectionRequest( HWND hwnd, XEvent *xev )
|
|||
|
||||
X11DRV_expect_error( display, is_window_error, NULL );
|
||||
|
||||
/*
|
||||
* We can only handle the selection request if :
|
||||
* The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
|
||||
*/
|
||||
if (((event->selection != XA_PRIMARY) && (event->selection != x11drv_atom(CLIPBOARD))))
|
||||
goto done;
|
||||
TRACE( "got request on %lx for selection %s target %s win %lx prop %s\n",
|
||||
event->owner, debugstr_xatom( event->selection ), debugstr_xatom( event->target ),
|
||||
event->requestor, debugstr_xatom( event->property ));
|
||||
|
||||
if (event->owner != selection_window) goto done;
|
||||
if ((event->selection != x11drv_atom(CLIPBOARD)) &&
|
||||
(!use_primary_selection || event->selection != XA_PRIMARY)) goto done;
|
||||
|
||||
/* If the specified property is None the requestor is an obsolete client.
|
||||
* We support these by using the specified target atom as the reply property.
|
||||
|
@ -2131,11 +2114,27 @@ done:
|
|||
/***********************************************************************
|
||||
* X11DRV_SelectionClear
|
||||
*/
|
||||
BOOL X11DRV_SelectionClear( HWND hWnd, XEvent *xev )
|
||||
BOOL X11DRV_SelectionClear( HWND hwnd, XEvent *xev )
|
||||
{
|
||||
XSelectionClearEvent *event = &xev->xselectionclear;
|
||||
if (event->selection == XA_PRIMARY || event->selection == x11drv_atom(CLIPBOARD))
|
||||
X11DRV_CLIPBOARD_ReleaseSelection( event->display, event->selection,
|
||||
event->window, hWnd, event->time );
|
||||
|
||||
if (event->window != selection_window) return FALSE;
|
||||
if (event->selection != x11drv_atom(CLIPBOARD)) return FALSE;
|
||||
|
||||
release_selection( event->display, event->time );
|
||||
grab_win32_clipboard( event->display );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* X11DRV_InitClipboard
|
||||
*/
|
||||
void X11DRV_InitClipboard(void)
|
||||
{
|
||||
DWORD id;
|
||||
HANDLE handle = CreateThread( NULL, 0, clipboard_thread, NULL, 0, &id );
|
||||
|
||||
if (handle) CloseHandle( handle );
|
||||
else ERR( "failed to create clipboard thread\n" );
|
||||
}
|
||||
|
|
|
@ -1794,6 +1794,7 @@ BOOL CDECL X11DRV_CreateWindow( HWND hwnd )
|
|||
CWOverrideRedirect | CWEventMask, &attr );
|
||||
XFlush( data->display );
|
||||
SetPropA( hwnd, clip_window_prop, (HANDLE)data->clip_window );
|
||||
X11DRV_InitClipboard();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -2660,9 +2661,8 @@ LRESULT CDECL X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
|
|||
|
||||
switch(msg)
|
||||
{
|
||||
case WM_X11DRV_ACQUIRE_SELECTION:
|
||||
X11DRV_AcquireClipboard( hwnd );
|
||||
return 0;
|
||||
case WM_X11DRV_UPDATE_CLIPBOARD:
|
||||
return update_clipboard( hwnd );
|
||||
case WM_X11DRV_SET_WIN_REGION:
|
||||
if ((data = get_win_data( hwnd )))
|
||||
{
|
||||
|
|
|
@ -521,7 +521,7 @@ extern DWORD EVENT_x11_time_to_win32_time(Time time) DECLSPEC_HIDDEN;
|
|||
/* X11 driver private messages, must be in the range 0x80001000..0x80001fff */
|
||||
enum x11drv_window_messages
|
||||
{
|
||||
WM_X11DRV_ACQUIRE_SELECTION = 0x80001000,
|
||||
WM_X11DRV_UPDATE_CLIPBOARD = 0x80001000,
|
||||
WM_X11DRV_SET_WIN_REGION,
|
||||
WM_X11DRV_RESIZE_DESKTOP,
|
||||
WM_X11DRV_SET_CURSOR,
|
||||
|
@ -589,6 +589,7 @@ extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *
|
|||
extern void change_systray_owner( Display *display, Window systray_window ) DECLSPEC_HIDDEN;
|
||||
extern void update_systray_balloon_position(void) DECLSPEC_HIDDEN;
|
||||
extern HWND create_foreign_window( Display *display, Window window ) DECLSPEC_HIDDEN;
|
||||
extern BOOL update_clipboard( HWND hwnd ) DECLSPEC_HIDDEN;
|
||||
|
||||
static inline void mirror_rect( const RECT *window_rect, RECT *rect )
|
||||
{
|
||||
|
@ -606,8 +607,6 @@ extern XContext win_data_context DECLSPEC_HIDDEN;
|
|||
extern XContext cursor_context DECLSPEC_HIDDEN;
|
||||
|
||||
extern void X11DRV_InitClipboard(void) DECLSPEC_HIDDEN;
|
||||
extern void X11DRV_AcquireClipboard(HWND hWndClipWindow) DECLSPEC_HIDDEN;
|
||||
extern void X11DRV_ResetSelectionOwner(void) DECLSPEC_HIDDEN;
|
||||
extern void CDECL X11DRV_SetFocus( HWND hwnd ) DECLSPEC_HIDDEN;
|
||||
extern void set_window_cursor( Window window, HCURSOR handle ) DECLSPEC_HIDDEN;
|
||||
extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -588,7 +588,6 @@ static BOOL process_attach(void)
|
|||
if (use_xkb) use_xkb = XkbUseExtension( gdi_display, NULL, NULL );
|
||||
#endif
|
||||
X11DRV_InitKeyboard( gdi_display );
|
||||
X11DRV_InitClipboard();
|
||||
if (use_xim) use_xim = X11DRV_InitXIM( input_style );
|
||||
|
||||
return TRUE;
|
||||
|
@ -604,7 +603,6 @@ void CDECL X11DRV_ThreadDetach(void)
|
|||
|
||||
if (data)
|
||||
{
|
||||
X11DRV_ResetSelectionOwner();
|
||||
if (data->xim) XCloseIM( data->xim );
|
||||
if (data->font_set) XFreeFontSet( data->display, data->font_set );
|
||||
XCloseDisplay( data->display );
|
||||
|
|
Loading…
Reference in New Issue