Merge remote-tracking branch 'jturney/xwin-clipboard-refactoring'

This commit is contained in:
Keith Packard 2014-09-29 13:04:49 -07:00
commit 78c27d12e1
21 changed files with 852 additions and 643 deletions

View File

@ -2142,7 +2142,7 @@ if test "x$XWIN" = xyes; then
AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support]) AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support])
AC_CHECK_TOOL(WINDRES, windres) AC_CHECK_TOOL(WINDRES, windres)
PKG_CHECK_MODULES([XWINMODULES],[x11 xdmcp xau]) PKG_CHECK_MODULES([XWINMODULES],[x11 xdmcp xau xfixes])
if test "x$WINDOWSWM" = xauto; then if test "x$WINDOWSWM" = xauto; then
PKG_CHECK_EXISTS($WINDOWSWMPROTO, [WINDOWSWM=yes], [WINDOWSWM=no]) PKG_CHECK_EXISTS($WINDOWSWMPROTO, [WINDOWSWM=yes], [WINDOWSWM=no])
@ -2600,6 +2600,7 @@ hw/xnest/man/Makefile
hw/xwin/Makefile hw/xwin/Makefile
hw/xwin/glx/Makefile hw/xwin/glx/Makefile
hw/xwin/man/Makefile hw/xwin/man/Makefile
hw/xwin/winclipboard/Makefile
hw/xquartz/Makefile hw/xquartz/Makefile
hw/xquartz/GL/Makefile hw/xquartz/GL/Makefile
hw/xquartz/bundle/Makefile hw/xquartz/bundle/Makefile

View File

@ -39,7 +39,6 @@
#ifdef XWIN_CLIPBOARD #ifdef XWIN_CLIPBOARD
int winProcEstablishConnection(ClientPtr /* client */ ); int winProcEstablishConnection(ClientPtr /* client */ );
int winProcSetSelectionOwner(ClientPtr /* client */ );
#endif #endif
/* /*

View File

@ -66,24 +66,11 @@ typedef WINAPI HRESULT(*SHGETFOLDERPATHPROC) (HWND hwndOwner,
/* /*
* References to external symbols * References to external symbols
*/ */
#ifdef XWIN_CLIPBOARD
extern Bool g_fUnicodeClipboard;
extern Bool g_fClipboardLaunched;
extern Bool g_fClipboardStarted;
extern pthread_t g_ptClipboardProc;
extern HWND g_hwndClipboard;
extern Bool g_fClipboard;
#endif
/* /*
* Function prototypes * Function prototypes
*/ */
#ifdef XWIN_CLIPBOARD
static void
winClipboardShutdown(void);
#endif
static Bool static Bool
winCheckDisplayNumber(void); winCheckDisplayNumber(void);
@ -125,31 +112,6 @@ static PixmapFormatRec g_PixmapFormats[] = {
const int NUMFORMATS = sizeof(g_PixmapFormats) / sizeof(g_PixmapFormats[0]); const int NUMFORMATS = sizeof(g_PixmapFormats) / sizeof(g_PixmapFormats[0]);
#ifdef XWIN_CLIPBOARD
static void
winClipboardShutdown(void)
{
/* Close down clipboard resources */
if (g_fClipboard && g_fClipboardLaunched && g_fClipboardStarted) {
/* Synchronously destroy the clipboard window */
if (g_hwndClipboard != NULL) {
SendMessage(g_hwndClipboard, WM_DESTROY, 0, 0);
/* NOTE: g_hwndClipboard is set to NULL in winclipboardthread.c */
}
else
return;
/* Wait for the clipboard thread to exit */
pthread_join(g_ptClipboardProc, NULL);
g_fClipboardLaunched = FALSE;
g_fClipboardStarted = FALSE;
winDebug("winClipboardShutdown - Clipboard thread has exited.\n");
}
}
#endif
static const ExtensionModule xwinExtensions[] = { static const ExtensionModule xwinExtensions[] = {
#ifdef GLXEXT #ifdef GLXEXT
{ GlxExtensionInit, "GLX", &noGlxExtension }, { GlxExtensionInit, "GLX", &noGlxExtension },

View File

@ -3,12 +3,9 @@ bin_PROGRAMS = XWin
if XWIN_CLIPBOARD if XWIN_CLIPBOARD
SRCS_CLIPBOARD = \ SRCS_CLIPBOARD = \
winclipboardinit.c \ winclipboardinit.c \
winclipboardtextconv.c \ winclipboardwrappers.c
winclipboardthread.c \
winclipboardwndproc.c \
winclipboardwrappers.c \
winclipboardxevents.c
DEFS_CLIPBOARD = -DXWIN_CLIPBOARD DEFS_CLIPBOARD = -DXWIN_CLIPBOARD
CLIPBOARD_LIBS = $(top_builddir)/hw/xwin/winclipboard/libXWinclipboard.la
endif endif
if XWIN_GLX_WINDOWS if XWIN_GLX_WINDOWS
@ -110,7 +107,6 @@ SRCS = InitInput.c \
winwindow.c \ winwindow.c \
winwndproc.c \ winwndproc.c \
ddraw.h \ ddraw.h \
winclipboard.h \
winconfig.h \ winconfig.h \
win.h \ win.h \
winglobals.h \ winglobals.h \
@ -162,12 +158,15 @@ XWin_DEPENDENCIES = \
$(MULTIWINDOWEXTWM_LIBS) \ $(MULTIWINDOWEXTWM_LIBS) \
$(XWIN_GLX_LIBS) \ $(XWIN_GLX_LIBS) \
$(XWIN_LIBS) \ $(XWIN_LIBS) \
$(CLIPBOARD_LIBS) \
$(XSERVER_LIBS) $(XSERVER_LIBS)
XWin_LDADD = \ XWin_LDADD = \
$(MULTIWINDOWEXTWM_LIBS) \ $(MULTIWINDOWEXTWM_LIBS) \
$(XWIN_GLX_LIBS) \ $(XWIN_GLX_LIBS) \
$(XWIN_LIBS) \ $(XWIN_LIBS) \
$(CLIPBOARD_LIBS) \
$(XSERVER_LIBS) \ $(XSERVER_LIBS) \
$(XWIN_GLX_SYS_LIBS) \ $(XWIN_GLX_SYS_LIBS) \
$(XSERVER_SYS_LIBS) \ $(XSERVER_SYS_LIBS) \
@ -210,5 +209,5 @@ EXTRA_DIST = \
relink: relink:
$(AM_V_at)rm -f XWin$(EXEEXT) && $(MAKE) XWin$(EXEEXT) $(AM_V_at)rm -f XWin$(EXEEXT) && $(MAKE) XWin$(EXEEXT)
SUBDIRS = man $(GLX_DIR) . SUBDIRS = man $(GLX_DIR) winclipboard .
DIST_SUBDIRS = man glx . DIST_SUBDIRS = man glx winclipboard .

View File

@ -793,7 +793,7 @@ Bool
winInitClipboard(void); winInitClipboard(void);
void void
winFixClipboardChain(void); winClipboardShutdown(void);
#endif #endif
/* /*

View File

@ -0,0 +1,25 @@
noinst_LTLIBRARIES = libXWinclipboard.la
libXWinclipboard_la_SOURCES = \
winclipboard.h \
textconv.c \
thread.c \
wndproc.c \
xevents.c
libXWinclipboard_la_CFLAGS = -DHAVE_XWIN_CONFIG_H \
$(DIX_CFLAGS) \
$(XWINMODULES_CFLAGS)
libXWinclipboard_la_LDFLAGS = -static -no-undefined
bin_PROGRAMS = xwinclip
xwinclip_SOURCES = xwinclip.c debug.c
xwinclip_CFLAGS = $(XWINMODULES_CFLAGS)
xwinclip_LDADD = libXWinclipboard.la $(XWINMODULES_LIBS) -lgdi32
include $(top_srcdir)/manpages.am
appman_PRE = xwinclip.man

View File

@ -0,0 +1,52 @@
//
// Copyright © Jon TURNEY 2013
//
// This file is part of xwinclip.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include <stdarg.h>
#include <stdio.h>
#if 1
int
winDebug(const char *format, ...)
{
int count;
va_list ap;
va_start(ap, format);
count = fprintf(stderr, "xwinclip: ");
count += vfprintf(stderr, format, ap);
va_end(ap);
return count;
}
#endif
int
ErrorF(const char *format, ...)
{
int count;
va_list ap;
va_start(ap, format);
count = vfprintf(stderr, format, ap);
va_end(ap);
return count;
}

View File

@ -1,5 +1,4 @@
#ifndef _WINCLIPBOARD_H_
#define _WINCLIPBOARD_H_
/* /*
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved. *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
* *
@ -30,46 +29,18 @@
* Authors: Harold L Hunt II * Authors: Harold L Hunt II
*/ */
/* Standard library headers */ #ifndef WINCLIPBOARD_INTERNAL_H
#include <assert.h> #define WINCLIPBOARD_INTERNAL_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef __CYGWIN__
#include <sys/select.h>
#else
#include <X11/Xwinsock.h>
#endif
#include <fcntl.h>
#include <setjmp.h>
#include <pthread.h>
/* X headers */ /* X headers */
#include <X11/X.h> #include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#include <X11/Xlocale.h>
/* Windows headers */ /* Windows headers */
#include <X11/Xwindows.h> #include <X11/Xwindows.h>
/* Clipboard module constants */
#define WIN_CLIPBOARD_WINDOW_CLASS "xwinclip"
#define WIN_CLIPBOARD_WINDOW_TITLE "xwinclip"
#ifdef HAS_DEVWINDOWS
#define WIN_MSG_QUEUE_FNAME "/dev/windows"
#endif
#define WIN_CONNECT_RETRIES 40
#define WIN_CONNECT_DELAY 4
#define WIN_JMP_OKAY 0
#define WIN_JMP_ERROR_IO 2
#define WIN_LOCAL_PROPERTY "CYGX_CUT_BUFFER"
#define WIN_XEVENTS_SUCCESS 0 #define WIN_XEVENTS_SUCCESS 0
#define WIN_XEVENTS_CONVERT 2 #define WIN_XEVENTS_CONVERT 2
#define WIN_XEVENTS_NOTIFY 3 #define WIN_XEVENTS_NOTIFY 3
#define WIN_CLIPBOARD_RETRIES 40
#define WIN_CLIPBOARD_DELAY 1
#define WM_WM_REINIT (WM_USER + 1) #define WM_WM_REINIT (WM_USER + 1)
@ -77,18 +48,8 @@
* References to external symbols * References to external symbols
*/ */
extern char *display;
extern void winDebug(const char *format, ...); extern void winDebug(const char *format, ...);
extern void winErrorFVerb(int verb, const char *format, ...); extern void ErrorF(const char *format, ...);
/*
* winclipboardinit.c
*/
Bool
winInitClipboard(void);
HWND winClipboardCreateMessagingWindow(void);
/* /*
* winclipboardtextconv.c * winclipboardtextconv.c
@ -104,23 +65,45 @@ void
* winclipboardthread.c * winclipboardthread.c
*/ */
void *winClipboardProc(void *);
typedef struct
{
Atom atomClipboard;
Atom atomLocalProperty;
Atom atomUTF8String;
Atom atomCompoundText;
Atom atomTargets;
} ClipboardAtoms;
/* /*
* winclipboardwndproc.c * winclipboardwndproc.c
*/ */
BOOL winClipboardFlushWindowsMessageQueue(HWND hwnd); Bool winClipboardFlushWindowsMessageQueue(HWND hwnd);
LRESULT CALLBACK LRESULT CALLBACK
winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
typedef struct
{
Display *pClipboardDisplay;
Window iClipboardWindow;
ClipboardAtoms *atoms;
} ClipboardWindowCreationParams;
/* /*
* winclipboardxevents.c * winclipboardxevents.c
*/ */
int int
winClipboardFlushXEvents(HWND hwnd, winClipboardFlushXEvents(HWND hwnd,
int iWindow, Display * pDisplay, Bool fUnicodeSupport); Window iWindow, Display * pDisplay, Bool fUnicodeSupport, ClipboardAtoms *atom);
Atom
winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms);
void
winClipboardInitMonitoredSelections(void);
#endif #endif

View File

@ -31,14 +31,18 @@
#ifdef HAVE_XWIN_CONFIG_H #ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h> #include <xwin-config.h>
#endif #endif
#include "win.h"
#include <stdio.h>
#include <stdlib.h>
void /*
winClipboardDOStoUNIX(char *pszSrc, int iLength); * Including any server header might define the macro _XSERVER64 on 64 bit machines.
void * That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
winClipboardUNIXtoDOS(char **ppszData, int iLength); * So let's undef that macro if necessary.
*/
#ifdef _XSERVER64
#undef _XSERVER64
#endif
#include <stdlib.h>
#include "internal.h"
/* /*
* Convert \r\n to \n * Convert \r\n to \n

View File

@ -35,42 +35,62 @@
#else #else
#define HAS_WINSOCK 1 #define HAS_WINSOCK 1
#endif #endif
#include <sys/types.h>
#include <signal.h>
#include "winclipboard.h"
#include "windisplay.h"
#ifdef __CYGWIN__
#include <errno.h>
#endif
#include "misc.h"
/* /*
* References to external symbols * Including any server header might define the macro _XSERVER64 on 64 bit machines.
* That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
* So let's undef that macro if necessary.
*/ */
#ifdef _XSERVER64
#undef _XSERVER64
#endif
extern Bool g_fUnicodeClipboard; #include <assert.h>
extern Bool g_fClipboardStarted; #include <unistd.h>
extern Bool g_fClipboardLaunched; #include <fcntl.h>
extern Bool g_fClipboard; #include <setjmp.h>
extern HWND g_hwndClipboard; #include <pthread.h>
extern void *g_pClipboardDisplay; #include <sys/param.h> // for MAX() macro
extern Window g_iClipboardWindow;
#ifdef HAS_WINSOCK
#include <X11/Xwinsock.h>
#else
#include <errno.h>
#endif
#include <X11/Xatom.h>
#include <X11/extensions/Xfixes.h>
#include "winclipboard.h"
#include "internal.h"
#define WIN_CONNECT_RETRIES 40
#define WIN_CONNECT_DELAY 4
#define WIN_CLIPBOARD_WINDOW_CLASS "xwinclip"
#define WIN_CLIPBOARD_WINDOW_TITLE "xwinclip"
#ifdef HAS_DEVWINDOWS
#define WIN_MSG_QUEUE_FNAME "/dev/windows"
#endif
/* /*
* Global variables * Global variables
*/ */
static HWND g_hwndClipboard = NULL;
static jmp_buf g_jmpEntry; static jmp_buf g_jmpEntry;
static int clipboardRestarts = 0;
static XIOErrorHandler g_winClipboardOldIOErrorHandler; static XIOErrorHandler g_winClipboardOldIOErrorHandler;
static pthread_t g_winClipboardProcThread; static pthread_t g_winClipboardProcThread;
Bool g_fUseUnicode = FALSE; int xfixes_event_base;
int xfixes_error_base;
/* /*
* Local function prototypes * Local function prototypes
*/ */
static HWND
winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAtoms *atoms);
static int static int
winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr); winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr);
@ -78,13 +98,15 @@ static int
winClipboardIOErrorHandler(Display * pDisplay); winClipboardIOErrorHandler(Display * pDisplay);
/* /*
* Main thread function * Create X11 and Win32 messaging windows, and run message processing loop
*
* returns TRUE if shutdown was signalled to loop, FALSE if some error occurred
*/ */
void * Bool
winClipboardProc(void *pvNotUsed) winClipboardProc(Bool fUseUnicode, char *szDisplay)
{ {
Atom atomClipboard; ClipboardAtoms atoms;
int iReturn; int iReturn;
HWND hwnd = NULL; HWND hwnd = NULL;
int iConnectionNumber = 0; int iConnectionNumber = 0;
@ -98,19 +120,11 @@ winClipboardProc(void *pvNotUsed)
int iMaxDescriptor; int iMaxDescriptor;
Display *pDisplay = NULL; Display *pDisplay = NULL;
Window iWindow = None; Window iWindow = None;
int iRetries;
Bool fUseUnicode;
char szDisplay[512];
int iSelectError; int iSelectError;
Bool fShutdown = FALSE;
static Bool fErrorHandlerSet = FALSE;
winDebug("winClipboardProc - Hello\n"); winDebug("winClipboardProc - Hello\n");
++clipboardRestarts;
/* Do we use Unicode clipboard? */
fUseUnicode = g_fUnicodeClipboard;
/* Save the Unicode support flag in a global */
g_fUseUnicode = fUseUnicode;
/* Allow multiple threads to access Xlib */ /* Allow multiple threads to access Xlib */
if (XInitThreads() == 0) { if (XInitThreads() == 0) {
@ -123,70 +137,29 @@ winClipboardProc(void *pvNotUsed)
ErrorF("winClipboardProc - Warning: Locale not supported by X.\n"); ErrorF("winClipboardProc - Warning: Locale not supported by X.\n");
} }
/* Set error handler */
XSetErrorHandler(winClipboardErrorHandler);
g_winClipboardProcThread = pthread_self(); g_winClipboardProcThread = pthread_self();
/* Set error handler */
if (!fErrorHandlerSet) {
XSetErrorHandler(winClipboardErrorHandler);
g_winClipboardOldIOErrorHandler = g_winClipboardOldIOErrorHandler =
XSetIOErrorHandler(winClipboardIOErrorHandler); XSetIOErrorHandler(winClipboardIOErrorHandler);
fErrorHandlerSet = TRUE;
}
/* Set jump point for Error exits */ /* Set jump point for Error exits */
iReturn = setjmp(g_jmpEntry); if (setjmp(g_jmpEntry)) {
/* Check if we should continue operations */
if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) {
/* setjmp returned an unknown value, exit */
ErrorF("winClipboardProc - setjmp returned: %d exiting\n", iReturn);
goto winClipboardProc_Exit;
}
else if (iReturn == WIN_JMP_ERROR_IO) {
/* TODO: Cleanup the Win32 window and free any allocated memory */
ErrorF("winClipboardProc - setjmp returned for IO Error Handler.\n"); ErrorF("winClipboardProc - setjmp returned for IO Error Handler.\n");
pthread_exit(NULL); goto winClipboardProc_Done;
} }
/* Use our generated cookie for authentication */
winSetAuthorization();
/* Initialize retry count */
iRetries = 0;
/* Setup the display connection string x */
/*
* NOTE: Always connect to screen 0 since we require that screen
* numbers start at 0 and increase without gaps. We only need
* to connect to one screen on the display to get events
* for all screens on the display. That is why there is only
* one clipboard client thread.
*/
winGetDisplayName(szDisplay, 0);
/* Print the display connection string */
ErrorF("winClipboardProc - DISPLAY=%s\n", szDisplay);
/* Open the X display */
do {
pDisplay = XOpenDisplay(szDisplay);
if (pDisplay == NULL) {
ErrorF("winClipboardProc - Could not open display, "
"try: %d, sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY);
++iRetries;
sleep(WIN_CONNECT_DELAY);
continue;
}
else
break;
}
while (pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES);
/* Make sure that the display opened */ /* Make sure that the display opened */
pDisplay = XOpenDisplay(szDisplay);
if (pDisplay == NULL) { if (pDisplay == NULL) {
ErrorF("winClipboardProc - Failed opening the display, giving up\n"); ErrorF("winClipboardProc - Failed opening the display, giving up\n");
goto winClipboardProc_Done; goto winClipboardProc_Done;
} }
/* Save the display in the screen privates */
g_pClipboardDisplay = pDisplay;
ErrorF("winClipboardProc - XOpenDisplay () returned and " ErrorF("winClipboardProc - XOpenDisplay () returned and "
"successfully opened the display.\n"); "successfully opened the display.\n");
@ -202,13 +175,20 @@ winClipboardProc(void *pvNotUsed)
} }
/* Find max of our file descriptors */ /* Find max of our file descriptors */
iMaxDescriptor = max(fdMessageQueue, iConnectionNumber) + 1; iMaxDescriptor = MAX(fdMessageQueue, iConnectionNumber) + 1;
#else #else
iMaxDescriptor = iConnectionNumber + 1; iMaxDescriptor = iConnectionNumber + 1;
#endif #endif
/* Create atom */ if (!XFixesQueryExtension(pDisplay, &xfixes_event_base, &xfixes_error_base))
atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False); ErrorF ("winClipboardProc - XFixes extension not present\n");
/* Create atoms */
atoms.atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False);
atoms.atomLocalProperty = XInternAtom (pDisplay, "CYGX_CUT_BUFFER", False);
atoms.atomUTF8String = XInternAtom (pDisplay, "UTF8_STRING", False);
atoms.atomCompoundText = XInternAtom (pDisplay, "COMPOUND_TEXT", False);
atoms.atomTargets = XInternAtom (pDisplay, "TARGETS", False);
/* Create a messaging window */ /* Create a messaging window */
iWindow = XCreateSimpleWindow(pDisplay, iWindow = XCreateSimpleWindow(pDisplay,
@ -230,13 +210,27 @@ winClipboardProc(void *pvNotUsed)
ErrorF("winClipboardProc - XSelectInput generated BadWindow " ErrorF("winClipboardProc - XSelectInput generated BadWindow "
"on messaging window\n"); "on messaging window\n");
/* Save the window in the screen privates */ XFixesSelectSelectionInput (pDisplay,
g_iClipboardWindow = iWindow; iWindow,
XA_PRIMARY,
XFixesSetSelectionOwnerNotifyMask |
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask);
XFixesSelectSelectionInput (pDisplay,
iWindow,
atoms.atomClipboard,
XFixesSetSelectionOwnerNotifyMask |
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask);
/* Initialize monitored selection state */
winClipboardInitMonitoredSelections();
/* Create Windows messaging window */ /* Create Windows messaging window */
hwnd = winClipboardCreateMessagingWindow(); hwnd = winClipboardCreateMessagingWindow(pDisplay, iWindow, &atoms);
/* Save copy of HWND in screen privates */ /* Save copy of HWND */
g_hwndClipboard = hwnd; g_hwndClipboard = hwnd;
/* Assert ownership of selections if Win32 clipboard is owned */ /* Assert ownership of selections if Win32 clipboard is owned */
@ -251,10 +245,10 @@ winClipboardProc(void *pvNotUsed)
} }
/* CLIPBOARD */ /* CLIPBOARD */
iReturn = XSetSelectionOwner(pDisplay, atomClipboard, iReturn = XSetSelectionOwner(pDisplay, atoms.atomClipboard,
iWindow, CurrentTime); iWindow, CurrentTime);
if (iReturn == BadAtom || iReturn == BadWindow || if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, atomClipboard) != iWindow) { XGetSelectionOwner(pDisplay, atoms.atomClipboard) != iWindow) {
ErrorF("winClipboardProc - Could not set CLIPBOARD owner\n"); ErrorF("winClipboardProc - Could not set CLIPBOARD owner\n");
goto winClipboardProc_Done; goto winClipboardProc_Done;
} }
@ -266,14 +260,12 @@ winClipboardProc(void *pvNotUsed)
* because there may be events in local data structures * because there may be events in local data structures
* already. * already.
*/ */
winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode); winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode, &atoms);
/* Pre-flush Windows messages */ /* Pre-flush Windows messages */
if (!winClipboardFlushWindowsMessageQueue(hwnd)) if (!winClipboardFlushWindowsMessageQueue(hwnd)) {
return 0; ErrorF("winClipboardProc - winClipboardFlushWindowsMessageQueue failed\n");
}
/* Signal that the clipboard client has started */
g_fClipboardStarted = TRUE;
/* Loop for X events */ /* Loop for X events */
while (1) { while (1) {
@ -326,7 +318,7 @@ winClipboardProc(void *pvNotUsed)
/* Branch on which descriptor became active */ /* Branch on which descriptor became active */
if (FD_ISSET(iConnectionNumber, &fdsRead)) { if (FD_ISSET(iConnectionNumber, &fdsRead)) {
/* Process X events */ /* Process X events */
winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode); winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode, &atoms);
} }
#ifdef HAS_DEVWINDOWS #ifdef HAS_DEVWINDOWS
@ -347,16 +339,13 @@ winClipboardProc(void *pvNotUsed)
} }
winClipboardProc_Exit: winClipboardProc_Exit:
/* disable the clipboard, which means the thread will die */ /* broke out of while loop on a shutdown message */
g_fClipboard = FALSE; fShutdown = TRUE;
winClipboardProc_Done: winClipboardProc_Done:
/* Close our Windows window */ /* Close our Windows window */
if (g_hwndClipboard) { if (g_hwndClipboard) {
/* Destroy the Window window (hwnd) */ winClipboardWindowDestroy();
winDebug("winClipboardProc - Destroy Windows window\n");
PostMessage(g_hwndClipboard, WM_DESTROY, 0, 0);
winClipboardFlushWindowsMessageQueue(g_hwndClipboard);
} }
/* Close our X window */ /* Close our X window */
@ -376,8 +365,11 @@ winClipboardProc(void *pvNotUsed)
#if 0 #if 0
/* /*
* FIXME: XCloseDisplay hangs if we call it, as of 2004/03/26. The * FIXME: XCloseDisplay hangs if we call it
* XSync and XSelectInput calls did not help. *
* XCloseDisplay() calls XSync(), so any outstanding errors are reported.
* If we are built into the server, this can deadlock if the server is
* in the process of exiting and waiting for this thread to exit.
*/ */
/* Discard any remaining events */ /* Discard any remaining events */
@ -393,42 +385,64 @@ winClipboardProc(void *pvNotUsed)
#endif #endif
/* global clipboard variable reset */ /* global clipboard variable reset */
g_fClipboardLaunched = FALSE;
g_fClipboardStarted = FALSE;
g_iClipboardWindow = None;
g_pClipboardDisplay = NULL;
g_hwndClipboard = NULL; g_hwndClipboard = NULL;
/* checking if we need to restart */ return fShutdown;
if (clipboardRestarts >= WIN_CLIPBOARD_RETRIES) {
/* terminates clipboard thread but the main server still lives */
ErrorF
("winClipboardProc - the clipboard thread has restarted %d times and seems to be unstable, disabling clipboard integration\n",
clipboardRestarts);
g_fClipboard = FALSE;
return NULL;
} }
if (g_fClipboard) { /*
sleep(WIN_CLIPBOARD_DELAY); * Create the Windows window that we use to receive Windows messages
ErrorF("winClipboardProc - trying to restart clipboard thread \n"); */
/* Create the clipboard client thread */
if (!winInitClipboard()) {
ErrorF("winClipboardProc - winClipboardInit failed.\n");
return NULL;
}
winDebug("winClipboardProc - winInitClipboard returned.\n"); static HWND
/* Flag that clipboard client has been launched */ winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAtoms *atoms)
g_fClipboardLaunched = TRUE; {
} WNDCLASSEX wc;
else { ClipboardWindowCreationParams cwcp;
ErrorF("winClipboardProc - Clipboard disabled - Exit from server \n"); HWND hwnd;
/* clipboard thread has exited, stop server as well */
raise(SIGTERM);
}
return NULL; /* Setup our window class */
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = winClipboardWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = 0;
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = WIN_CLIPBOARD_WINDOW_CLASS;
wc.hIconSm = 0;
RegisterClassEx(&wc);
/* Information to be passed to WM_CREATE */
cwcp.pClipboardDisplay = pDisplay;
cwcp.iClipboardWindow = iWindow;
cwcp.atoms = atoms;
/* Create the window */
hwnd = CreateWindowExA(0, /* Extended styles */
WIN_CLIPBOARD_WINDOW_CLASS, /* Class name */
WIN_CLIPBOARD_WINDOW_TITLE, /* Window name */
WS_OVERLAPPED, /* Not visible anyway */
CW_USEDEFAULT, /* Horizontal position */
CW_USEDEFAULT, /* Vertical position */
CW_USEDEFAULT, /* Right edge */
CW_USEDEFAULT, /* Bottom edge */
(HWND) NULL, /* No parent or owner window */
(HMENU) NULL, /* No menu */
GetModuleHandle(NULL), /* Instance handle */
&cwcp); /* Creation data */
assert(hwnd != NULL);
/* I'm not sure, but we may need to call this to start message processing */
ShowWindow(hwnd, SW_HIDE);
/* Similarly, we may need a call to this even though we don't paint */
UpdateWindow(hwnd);
return hwnd;
} }
/* /*
@ -458,7 +472,7 @@ winClipboardIOErrorHandler(Display * pDisplay)
if (pthread_equal(pthread_self(), g_winClipboardProcThread)) { if (pthread_equal(pthread_self(), g_winClipboardProcThread)) {
/* Restart at the main entry point */ /* Restart at the main entry point */
longjmp(g_jmpEntry, WIN_JMP_ERROR_IO); longjmp(g_jmpEntry, 2);
} }
if (g_winClipboardOldIOErrorHandler) if (g_winClipboardOldIOErrorHandler)
@ -466,3 +480,19 @@ winClipboardIOErrorHandler(Display * pDisplay)
return 0; return 0;
} }
void
winClipboardWindowDestroy(void)
{
if (g_hwndClipboard) {
SendMessage(g_hwndClipboard, WM_DESTROY, 0, 0);
}
}
void
winFixClipboardChain(void)
{
if (g_hwndClipboard) {
PostMessage(g_hwndClipboard, WM_WM_REINIT, 0, 0);
}
}

View File

@ -0,0 +1,36 @@
//
// Copyright © Jon TURNEY 2013
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File: winclipboard.h
// Purpose: public interface to winclipboard library
//
#ifndef WINCLIPBOARD_H
#define WINCLIPBOARD_H
Bool winClipboardProc(Bool fUseUnicode, char *szDisplay);
void winFixClipboardChain(void);
void winClipboardWindowDestroy(void);
#endif

View File

@ -33,10 +33,23 @@
#ifdef HAVE_XWIN_CONFIG_H #ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h> #include <xwin-config.h>
#endif #endif
/*
* Including any server header might define the macro _XSERVER64 on 64 bit machines.
* That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
* So let's undef that macro if necessary.
*/
#ifdef _XSERVER64
#undef _XSERVER64
#endif
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
#include <X11/Xatom.h>
#include "internal.h"
#include "winclipboard.h" #include "winclipboard.h"
#include "misc.h"
/* /*
* Constants * Constants
@ -44,21 +57,14 @@
#define WIN_POLL_TIMEOUT 1 #define WIN_POLL_TIMEOUT 1
/*
* References to external symbols
*/
extern void *g_pClipboardDisplay;
extern Window g_iClipboardWindow;
extern Atom g_atomLastOwnedSelection;
/* /*
* Process X events up to specified timeout * Process X events up to specified timeout
*/ */
static int static int
winProcessXEventsTimeout(HWND hwnd, int iWindow, Display * pDisplay, winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay,
Bool fUseUnicode, int iTimeoutSec) Bool fUseUnicode, ClipboardAtoms *atoms, int iTimeoutSec)
{ {
int iConnNumber; int iConnNumber;
struct timeval tv; struct timeval tv;
@ -111,7 +117,7 @@ winProcessXEventsTimeout(HWND hwnd, int iWindow, Display * pDisplay,
/* Process X events */ /* Process X events */
/* Exit when we see that server is shutting down */ /* Exit when we see that server is shutting down */
iReturn = winClipboardFlushXEvents(hwnd, iReturn = winClipboardFlushXEvents(hwnd,
iWindow, pDisplay, fUseUnicode); iWindow, pDisplay, fUseUnicode, atoms);
winDebug winDebug
("winProcessXEventsTimeout () - winClipboardFlushXEvents returned %d\n", ("winProcessXEventsTimeout () - winClipboardFlushXEvents returned %d\n",
@ -139,6 +145,9 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
static HWND s_hwndNextViewer; static HWND s_hwndNextViewer;
static Bool s_fCBCInitialized; static Bool s_fCBCInitialized;
static Display *pDisplay;
static Window iWindow;
static ClipboardAtoms *atoms;
/* Branch on message type */ /* Branch on message type */
switch (message) { switch (message) {
@ -159,9 +168,14 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
HWND first, next; HWND first, next;
DWORD error_code = 0; DWORD error_code = 0;
ClipboardWindowCreationParams *cwcp = (ClipboardWindowCreationParams *)((CREATESTRUCT *)lParam)->lpCreateParams;
winDebug("winClipboardWindowProc - WM_CREATE\n"); winDebug("winClipboardWindowProc - WM_CREATE\n");
pDisplay = cwcp->pClipboardDisplay;
iWindow = cwcp->iClipboardWindow;
atoms = cwcp->atoms;
first = GetClipboardViewer(); /* Get handle to first viewer in chain. */ first = GetClipboardViewer(); /* Get handle to first viewer in chain. */
if (first == hwnd) if (first == hwnd)
return 0; /* Make sure it's not us! */ return 0; /* Make sure it's not us! */
@ -185,7 +199,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
s_hwndNextViewer = (HWND) lParam; s_hwndNextViewer = (HWND) lParam;
if (s_hwndNextViewer == hwnd) { if (s_hwndNextViewer == hwnd) {
s_hwndNextViewer = NULL; s_hwndNextViewer = NULL;
winErrorFVerb(1, "winClipboardWindowProc - WM_CHANGECBCHAIN: " ErrorF("winClipboardWindowProc - WM_CHANGECBCHAIN: "
"attempted to set next window to ourselves."); "attempted to set next window to ourselves.");
} }
} }
@ -241,20 +255,11 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_DRAWCLIPBOARD: case WM_DRAWCLIPBOARD:
{ {
static Atom atomClipboard;
static int generation;
static Bool s_fProcessingDrawClipboard = FALSE; static Bool s_fProcessingDrawClipboard = FALSE;
Display *pDisplay = g_pClipboardDisplay;
Window iWindow = g_iClipboardWindow;
int iReturn; int iReturn;
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Enter\n"); winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Enter\n");
if (generation != serverGeneration) {
generation = serverGeneration;
atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False);
}
/* /*
* We've occasionally seen a loop in the clipboard chain. * We've occasionally seen a loop in the clipboard chain.
* Try and fix it on the first hint of recursion. * Try and fix it on the first hint of recursion.
@ -267,7 +272,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
s_fCBCInitialized = FALSE; s_fCBCInitialized = FALSE;
ChangeClipboardChain(hwnd, s_hwndNextViewer); ChangeClipboardChain(hwnd, s_hwndNextViewer);
winFixClipboardChain(); winFixClipboardChain();
winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - " ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"Nested calls detected. Re-initing.\n"); "Nested calls detected. Re-initing.\n");
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
s_fProcessingDrawClipboard = FALSE; s_fProcessingDrawClipboard = FALSE;
@ -324,26 +329,26 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/* Release PRIMARY selection if owned */ /* Release PRIMARY selection if owned */
iReturn = XGetSelectionOwner(pDisplay, XA_PRIMARY); iReturn = XGetSelectionOwner(pDisplay, XA_PRIMARY);
if (iReturn == g_iClipboardWindow) { if (iReturn == iWindow) {
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - " winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"PRIMARY selection is owned by us.\n"); "PRIMARY selection is owned by us.\n");
XSetSelectionOwner(pDisplay, XA_PRIMARY, None, CurrentTime); XSetSelectionOwner(pDisplay, XA_PRIMARY, None, CurrentTime);
} }
else if (BadWindow == iReturn || BadAtom == iReturn) else if (BadWindow == iReturn || BadAtom == iReturn)
winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - " ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"XGetSelection failed for PRIMARY: %d\n", "XGetSelectionOwner failed for PRIMARY: %d\n",
iReturn); iReturn);
/* Release CLIPBOARD selection if owned */ /* Release CLIPBOARD selection if owned */
iReturn = XGetSelectionOwner(pDisplay, atomClipboard); iReturn = XGetSelectionOwner(pDisplay, atoms->atomClipboard);
if (iReturn == g_iClipboardWindow) { if (iReturn == iWindow) {
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - " winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"CLIPBOARD selection is owned by us.\n"); "CLIPBOARD selection is owned by us, releasing\n");
XSetSelectionOwner(pDisplay, atomClipboard, None, CurrentTime); XSetSelectionOwner(pDisplay, atoms->atomClipboard, None, CurrentTime);
} }
else if (BadWindow == iReturn || BadAtom == iReturn) else if (BadWindow == iReturn || BadAtom == iReturn)
winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - " ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"XGetSelection failed for CLIPBOARD: %d\n", "XGetSelectionOwner failed for CLIPBOARD: %d\n",
iReturn); iReturn);
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
@ -358,7 +363,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
XA_PRIMARY, iWindow, CurrentTime); XA_PRIMARY, iWindow, CurrentTime);
if (iReturn == BadAtom || iReturn == BadWindow || if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) { XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) {
winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - " ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"Could not reassert ownership of PRIMARY\n"); "Could not reassert ownership of PRIMARY\n");
} }
else { else {
@ -368,11 +373,11 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/* Reassert ownership of the CLIPBOARD */ /* Reassert ownership of the CLIPBOARD */
iReturn = XSetSelectionOwner(pDisplay, iReturn = XSetSelectionOwner(pDisplay,
atomClipboard, iWindow, CurrentTime); atoms->atomClipboard, iWindow, CurrentTime);
if (iReturn == BadAtom || iReturn == BadWindow || if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, atomClipboard) != iWindow) { XGetSelectionOwner(pDisplay, atoms->atomClipboard) != iWindow) {
winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - " ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"Could not reassert ownership of CLIPBOARD\n"); "Could not reassert ownership of CLIPBOARD\n");
} }
else { else {
@ -409,8 +414,6 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_RENDERALLFORMATS: case WM_RENDERALLFORMATS:
{ {
int iReturn; int iReturn;
Display *pDisplay = g_pClipboardDisplay;
Window iWindow = g_iClipboardWindow;
Bool fConvertToUnicode; Bool fConvertToUnicode;
winDebug("winClipboardWindowProc - WM_RENDER*FORMAT - Hello.\n"); winDebug("winClipboardWindowProc - WM_RENDER*FORMAT - Hello.\n");
@ -423,14 +426,12 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/* Request the selection contents */ /* Request the selection contents */
iReturn = XConvertSelection(pDisplay, iReturn = XConvertSelection(pDisplay,
g_atomLastOwnedSelection, winClipboardGetLastOwnedSelectionAtom(atoms),
XInternAtom(pDisplay, atoms->atomCompoundText,
"COMPOUND_TEXT", False), atoms->atomLocalProperty,
XInternAtom(pDisplay,
"CYGX_CUT_BUFFER", False),
iWindow, CurrentTime); iWindow, CurrentTime);
if (iReturn == BadAtom || iReturn == BadWindow) { if (iReturn == BadAtom || iReturn == BadWindow) {
winErrorFVerb(1, "winClipboardWindowProc - WM_RENDER*FORMAT - " ErrorF("winClipboardWindowProc - WM_RENDER*FORMAT - "
"XConvertSelection () failed\n"); "XConvertSelection () failed\n");
break; break;
} }
@ -445,14 +446,14 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
if (!OpenClipboard(hwnd)) { if (!OpenClipboard(hwnd)) {
winErrorFVerb(1, "winClipboardWindowProc - WM_RENDER*FORMATS - " ErrorF("winClipboardWindowProc - WM_RENDER*FORMATS - "
"OpenClipboard () failed: %08x\n", "OpenClipboard () failed: %08x\n",
GetLastError()); GetLastError());
break; break;
} }
if (!EmptyClipboard()) { if (!EmptyClipboard()) {
winErrorFVerb(1, "winClipboardWindowProc - WM_RENDER*FORMATS - " ErrorF("winClipboardWindowProc - WM_RENDER*FORMATS - "
"EmptyClipboard () failed: %08x\n", "EmptyClipboard () failed: %08x\n",
GetLastError()); GetLastError());
break; break;
@ -463,7 +464,9 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
iReturn = winProcessXEventsTimeout(hwnd, iReturn = winProcessXEventsTimeout(hwnd,
iWindow, iWindow,
pDisplay, pDisplay,
fConvertToUnicode, WIN_POLL_TIMEOUT); fConvertToUnicode,
atoms,
WIN_POLL_TIMEOUT);
/* /*
* The last call to winProcessXEventsTimeout * The last call to winProcessXEventsTimeout
@ -486,8 +489,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/* We must close the clipboard */ /* We must close the clipboard */
if (!CloseClipboard()) { if (!CloseClipboard()) {
winErrorFVerb(1, ErrorF("winClipboardWindowProc - WM_RENDERALLFORMATS - "
"winClipboardWindowProc - WM_RENDERALLFORMATS - "
"CloseClipboard () failed: %08x\n", "CloseClipboard () failed: %08x\n",
GetLastError()); GetLastError());
break; break;
@ -507,7 +509,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
* Process any pending Windows messages * Process any pending Windows messages
*/ */
BOOL Bool
winClipboardFlushWindowsMessageQueue(HWND hwnd) winClipboardFlushWindowsMessageQueue(HWND hwnd)
{ {
MSG msg; MSG msg;

View File

@ -33,8 +33,104 @@
#ifdef HAVE_XWIN_CONFIG_H #ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h> #include <xwin-config.h>
#endif #endif
#include "winclipboard.h"
#include "misc.h" /*
* Including any server header might define the macro _XSERVER64 on 64 bit machines.
* That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
* So let's undef that macro if necessary.
*/
#ifdef _XSERVER64
#undef _XSERVER64
#endif
#include "internal.h"
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xfixes.h>
/*
* Constants
*/
#define CLIP_NUM_SELECTIONS 2
#define CLIP_OWN_NONE -1
#define CLIP_OWN_PRIMARY 0
#define CLIP_OWN_CLIPBOARD 1
/*
* Global variables
*/
extern int xfixes_event_base;
/*
* Local variables
*/
static Window s_iOwners[CLIP_NUM_SELECTIONS] = { None, None };
static const char *szSelectionNames[CLIP_NUM_SELECTIONS] =
{ "PRIMARY", "CLIPBOARD" };
static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE;
static void
MonitorSelection(XFixesSelectionNotifyEvent * e, unsigned int i)
{
/* Look for owned -> not owned transition */
if (None == e->owner && None != s_iOwners[i]) {
unsigned int other_index;
winDebug("MonitorSelection - %s - Going from owned to not owned.\n",
szSelectionNames[i]);
/* If this selection is not owned, the other monitored selection must be the most
recently owned, if it is owned at all */
if (i == CLIP_OWN_PRIMARY)
other_index = CLIP_OWN_CLIPBOARD;
if (i == CLIP_OWN_CLIPBOARD)
other_index = CLIP_OWN_PRIMARY;
if (None != s_iOwners[other_index])
lastOwnedSelectionIndex = other_index;
else
lastOwnedSelectionIndex = CLIP_OWN_NONE;
}
/* Save last owned selection */
if (None != e->owner) {
lastOwnedSelectionIndex = i;
}
/* Save new selection owner or None */
s_iOwners[i] = e->owner;
winDebug("MonitorSelection - %s - Now owned by XID %x\n",
szSelectionNames[i], e->owner);
}
Atom
winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms)
{
if (lastOwnedSelectionIndex == CLIP_OWN_NONE)
return None;
if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY)
return XA_PRIMARY;
if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD)
return atoms->atomClipboard;
return None;
}
void
winClipboardInitMonitoredSelections(void)
{
/* Initialize static variables */
for (int i = 0; i < CLIP_NUM_SELECTIONS; ++i)
s_iOwners[i] = None;
lastOwnedSelectionIndex = CLIP_OWN_NONE;
}
/* /*
* Process any pending X events * Process any pending X events
@ -42,21 +138,13 @@
int int
winClipboardFlushXEvents(HWND hwnd, winClipboardFlushXEvents(HWND hwnd,
int iWindow, Display * pDisplay, Bool fUseUnicode) Window iWindow, Display * pDisplay, Bool fUseUnicode, ClipboardAtoms *atoms)
{ {
static Atom atomLocalProperty; Atom atomClipboard = atoms->atomClipboard;
static Atom atomCompoundText; Atom atomLocalProperty = atoms->atomLocalProperty;
static Atom atomUTF8String; Atom atomUTF8String = atoms->atomUTF8String;
static Atom atomTargets; Atom atomCompoundText = atoms->atomCompoundText;
static int generation; Atom atomTargets = atoms->atomTargets;
if (generation != serverGeneration) {
generation = serverGeneration;
atomLocalProperty = XInternAtom(pDisplay, WIN_LOCAL_PROPERTY, False);
atomUTF8String = XInternAtom(pDisplay, "UTF8_STRING", False);
atomCompoundText = XInternAtom(pDisplay, "COMPOUND_TEXT", False);
atomTargets = XInternAtom(pDisplay, "TARGETS", False);
}
/* Process all pending events */ /* Process all pending events */
while (XPending(pDisplay)) { while (XPending(pDisplay)) {
@ -77,7 +165,6 @@ winClipboardFlushXEvents(HWND hwnd,
wchar_t *pwszUnicodeStr = NULL; wchar_t *pwszUnicodeStr = NULL;
int iUnicodeLen = 0; int iUnicodeLen = 0;
int iReturnDataLen = 0; int iReturnDataLen = 0;
int i;
Bool fAbort = FALSE; Bool fAbort = FALSE;
Bool fCloseClipboard = FALSE; Bool fCloseClipboard = FALSE;
Bool fSetClipboardData = TRUE; Bool fSetClipboardData = TRUE;
@ -525,6 +612,8 @@ winClipboardFlushXEvents(HWND hwnd,
if (iReturn == Success || iReturn > 0) { if (iReturn == Success || iReturn > 0) {
/* Conversion succeeded or some unconvertible characters */ /* Conversion succeeded or some unconvertible characters */
if (ppszTextList != NULL) { if (ppszTextList != NULL) {
int i;
iReturnDataLen = 0; iReturnDataLen = 0;
for (i = 0; i < iCount; i++) { for (i = 0; i < iCount; i++) {
iReturnDataLen += strlen(ppszTextList[i]); iReturnDataLen += strlen(ppszTextList[i]);
@ -693,8 +782,78 @@ winClipboardFlushXEvents(HWND hwnd,
break; break;
default: default:
if (event.type == XFixesSetSelectionOwnerNotify + xfixes_event_base) {
XFixesSelectionNotifyEvent *e =
(XFixesSelectionNotifyEvent *) & event;
winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n");
/* Save selection owners for monitored selections, ignore other selections */
if (e->selection == XA_PRIMARY) {
MonitorSelection(e, CLIP_OWN_PRIMARY);
}
else if (e->selection == atomClipboard) {
MonitorSelection(e, CLIP_OWN_CLIPBOARD);
}
else
break;
/* Selection is being disowned */
if (e->owner == None) {
winDebug
("winClipboardFlushXEvents - No window, returning.\n");
break;
}
/*
XXX: there are all kinds of wacky edge cases we might need here:
- we own windows clipboard, but neither PRIMARY nor CLIPBOARD have an owner, so we should disown it?
- root window is taking ownership?
*/
/* If we are the owner of the most recently owned selection, don't go all recursive :) */
if ((lastOwnedSelectionIndex != CLIP_OWN_NONE) &&
(s_iOwners[lastOwnedSelectionIndex] == iWindow)) {
winDebug("winClipboardFlushXEvents - Ownership changed to us, aborting.\n");
break;
}
/* Close clipboard if we have it open already (possible? correct??) */
if (GetOpenClipboardWindow() == hwnd) {
CloseClipboard();
}
/* Access the Windows clipboard */
if (!OpenClipboard(hwnd)) {
ErrorF("winClipboardFlushXEvents - OpenClipboard () failed: %08x\n",
(int) GetLastError());
break;
}
/* Take ownership of the Windows clipboard */
if (!EmptyClipboard()) {
ErrorF("winClipboardFlushXEvents - EmptyClipboard () failed: %08x\n",
(int) GetLastError());
break;
}
/* Advertise regular text and unicode */
SetClipboardData(CF_UNICODETEXT, NULL);
SetClipboardData(CF_TEXT, NULL);
/* Release the clipboard */
if (!CloseClipboard()) {
ErrorF("winClipboardFlushXEvents - CloseClipboard () failed: %08x\n",
(int) GetLastError());
break;
}
}
/* XFixesSelectionWindowDestroyNotifyMask */
/* XFixesSelectionClientCloseNotifyMask */
else {
ErrorF("winClipboardFlushXEvents - unexpected event type %d\n", ErrorF("winClipboardFlushXEvents - unexpected event type %d\n",
event.type); event.type);
}
break; break;
} }
} }

View File

@ -0,0 +1,127 @@
/*
*Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
*Copyright (C) Colin Harrison 2005-2008
*
*Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
*"Software"), to deal in the Software without restriction, including
*without limitation the rights to use, copy, modify, merge, publish,
*distribute, sublicense, and/or sell copies of the Software, and to
*permit persons to whom the Software is furnished to do so, subject to
*the following conditions:
*
*The above copyright notice and this permission notice shall be
*included in all copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*Except as contained in this notice, the name of the copyright holder(s)
*and author(s) shall not be used in advertising or otherwise to promote
*the sale, use or other dealings in this Software without prior written
*authorization from the copyright holder(s) and author(s).
*
* Authors: Harold L Hunt II
* Colin Harrison
*/
#ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h>
#endif
/*
* Including any server header might define the macro _XSERVER64 on 64 bit machines.
* That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
* So let's undef that macro if necessary.
*/
#ifdef _XSERVER64
#undef _XSERVER64
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* X headers */
#include <X11/Xlib.h>
#ifdef X_LOCALE
#include <X11/Xlocale.h>
#else /* X_LOCALE */
#include <locale.h>
#endif /* X_LOCALE */
#include "winclipboard.h"
/*
* Main function
*/
int
main (int argc, char *argv[])
{
int i;
char *pszDisplay = NULL;
int fUnicodeClipboard = 1;
/* Parse command-line parameters */
for (i = 1; i < argc; ++i)
{
/* Look for -display "display_name" or --display "display_name" */
if (i < argc - 1
&& (!strcmp (argv[i], "-display")
|| !strcmp (argv[i], "--display")))
{
/* Grab a pointer to the display parameter */
pszDisplay = argv[i + 1];
/* Skip the display argument */
i++;
continue;
}
/* Look for -nounicodeclipboard */
if (!strcmp (argv[i], "-nounicodeclipboard"))
{
fUnicodeClipboard = 0;
continue;
}
/* Yack when we find a parameter that we don't know about */
printf ("Unknown parameter: %s\nExiting.\n", argv[i]);
exit (1);
}
/* Do we have Unicode support? */
if (fUnicodeClipboard)
{
printf ("Unicode clipboard I/O\n");
}
else
{
printf ("Non Unicode clipboard I/O\n");
}
/* Apply locale specified in the LANG environment variable */
if (!setlocale (LC_ALL, ""))
{
printf ("setlocale() error\n");
exit (1);
}
/* See if X supports the current locale */
if (XSupportsLocale () == False)
{
printf ("Locale not supported by X, falling back to 'C' locale.\n");
setlocale(LC_ALL, "C");
}
winClipboardProc(fUnicodeClipboard, pszDisplay);
return 0;
}

View File

@ -0,0 +1,61 @@
.TH xwinclip 1 __xorgversion__
.SH NAME
xwinclip - An X11 and Windows clipboard integration tool
.SH SYNOPSIS
.B xwinclip [OPTION]...
.SH DESCRIPTION
\fIxwinclip\fP is a tool for copying and pasting text between the Windows and X11 clipboard systems.
\fIxwinclip\fP watches for updates to either clipboard and copies data between them when either one is updated.
\fIxwinclip\fP monitors the X PRIMARY and CLIBPOARD selections for changes in ownership, and makes
the contents of the most recent one to change available to paste from the Windows clipboard.
It also monitors the contents of the Windows clipboard for changes, taking ownership of the PRIMARY and
CLIPBOARD selections, and making the contents of the Windows clipboard available in them.
.B Note well:
The \fIXWin(1)\fP X server has internal clipboard integration that is enabled by default.
Do \fINOT\fP run \fIxwinclip\fP unless \fIXWin(1)\fP has been started with the -noclipboard option.
.SH OPTIONS
\fIxwinclip\fP accepts the following optional command line switches:
.TP 8
.B \-display [display]
Specifies the X server display to connect to.
.TP 8
.B \-nounicodeclipboard
Do not use unicode text on the clipboard.
.SH "SEE ALSO"
XWin(1)
.SH BUGS
Only text clipboard contents are supported.
The INCR (Incrememntal transfer) clipboard protocol for clipboard contents larger than the maximum size of an
X request is not supported.
Some X clients, notably ones written in Tcl/Tk, do not re-assert ownership of the PRIMARY selection or update
it's timestamp when it's contents change, which currently prevents \fIxwinclip\fP from correctly noticing that
the PRIMARY selection's contents have changed.
Windows clipboard rendering is synchronous in the WM_RENDER*FORMAT message (that is, we must have placed the
contents onto the clipboard by the time we return from processing this message), but we must wait for the X
client which owns the selection to convert the selection to our requested format. This is currently achieved
using a fixed timeout of one second.
The XWin(1) server should indicate somehow (by placing an atom on the root window?) that it is running with it's
internal clipboard integration enabled, and xwinclip should notice this and exit with an appropriate error.
Probably many other bugs.
.SH "CONFORMING TO"
ICCCM (Inter-Client Communication Conventions Manual) 2.0
.SH AUTHORS
Contributors to xwinclip include Benjamin Riefenstahl, Roland Cassard, Brian Genisio, Colin Harrison,
Harold L Hunt II, Matsuzaki Kensuke, Jon Turney, Chris Twiner and Jeremy Wilkins.

View File

@ -31,25 +31,79 @@
#ifdef HAVE_XWIN_CONFIG_H #ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h> #include <xwin-config.h>
#endif #endif
#include "dixstruct.h"
#include "winclipboard.h" #include <unistd.h>
#include <pthread.h>
#include "win.h"
#include "winclipboard/winclipboard.h"
#include "windisplay.h"
#define WIN_CLIPBOARD_RETRIES 40
#define WIN_CLIPBOARD_DELAY 1
/* /*
* Local typedefs * Local variables
*/ */
typedef int (*winDispatchProcPtr) (ClientPtr); static pthread_t g_ptClipboardProc;
int winProcSetSelectionOwner(ClientPtr /* client */ );
/* /*
* References to external symbols *
*/ */
static void *
winClipboardThreadProc(void *arg)
{
char szDisplay[512];
int clipboardRestarts = 0;
extern pthread_t g_ptClipboardProc; while (1)
extern winDispatchProcPtr winProcSetSelectionOwnerOrig; {
extern Bool g_fClipboard; Bool fShutdown;
extern HWND g_hwndClipboard;
++clipboardRestarts;
/* Use our generated cookie for authentication */
winSetAuthorization();
/* Setup the display connection string */
/*
* NOTE: Always connect to screen 0 since we require that screen
* numbers start at 0 and increase without gaps. We only need
* to connect to one screen on the display to get events
* for all screens on the display. That is why there is only
* one clipboard client thread.
*/
winGetDisplayName(szDisplay, 0);
/* Print the display connection string */
ErrorF("winClipboardThreadProc - DISPLAY=%s\n", szDisplay);
/* Flag that clipboard client has been launched */
g_fClipboardStarted = TRUE;
fShutdown = winClipboardProc(g_fUnicodeClipboard, szDisplay);
/* Flag that clipboard client has stopped */
g_fClipboardStarted = FALSE;
if (fShutdown)
break;
/* checking if we need to restart */
if (clipboardRestarts >= WIN_CLIPBOARD_RETRIES) {
/* terminates clipboard thread but the main server still lives */
ErrorF("winClipboardProc - the clipboard thread has restarted %d times and seems to be unstable, disabling clipboard integration\n", clipboardRestarts);
g_fClipboard = FALSE;
break;
}
sleep(WIN_CLIPBOARD_DELAY);
ErrorF("winClipboardProc - trying to restart clipboard thread \n");
}
return NULL;
}
/* /*
* Intialize the Clipboard module * Intialize the Clipboard module
@ -60,14 +114,8 @@ winInitClipboard(void)
{ {
winDebug("winInitClipboard ()\n"); winDebug("winInitClipboard ()\n");
/* Wrap some internal server functions */
if (ProcVector[X_SetSelectionOwner] != winProcSetSelectionOwner) {
winProcSetSelectionOwnerOrig = ProcVector[X_SetSelectionOwner];
ProcVector[X_SetSelectionOwner] = winProcSetSelectionOwner;
}
/* Spawn a thread for the Clipboard module */ /* Spawn a thread for the Clipboard module */
if (pthread_create(&g_ptClipboardProc, NULL, winClipboardProc, NULL)) { if (pthread_create(&g_ptClipboardProc, NULL, winClipboardThreadProc, NULL)) {
/* Bail if thread creation failed */ /* Bail if thread creation failed */
ErrorF("winInitClipboard - pthread_create failed.\n"); ErrorF("winInitClipboard - pthread_create failed.\n");
return FALSE; return FALSE;
@ -76,59 +124,19 @@ winInitClipboard(void)
return TRUE; return TRUE;
} }
/*
* Create the Windows window that we use to receive Windows messages
*/
HWND
winClipboardCreateMessagingWindow(void)
{
WNDCLASSEX wc;
HWND hwnd;
/* Setup our window class */
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = winClipboardWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = 0;
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = WIN_CLIPBOARD_WINDOW_CLASS;
wc.hIconSm = 0;
RegisterClassEx(&wc);
/* Create the window */
hwnd = CreateWindowExA(0, /* Extended styles */
WIN_CLIPBOARD_WINDOW_CLASS, /* Class name */
WIN_CLIPBOARD_WINDOW_TITLE, /* Window name */
WS_OVERLAPPED, /* Not visible anyway */
CW_USEDEFAULT, /* Horizontal position */
CW_USEDEFAULT, /* Vertical position */
CW_USEDEFAULT, /* Right edge */
CW_USEDEFAULT, /* Bottom edge */
(HWND) NULL, /* No parent or owner window */
(HMENU) NULL, /* No menu */
GetModuleHandle(NULL), /* Instance handle */
NULL); /* Creation data */
assert(hwnd != NULL);
/* I'm not sure, but we may need to call this to start message processing */
ShowWindow(hwnd, SW_HIDE);
/* Similarly, we may need a call to this even though we don't paint */
UpdateWindow(hwnd);
return hwnd;
}
void void
winFixClipboardChain(void) winClipboardShutdown(void)
{ {
if (g_fClipboard && g_hwndClipboard) { /* Close down clipboard resources */
PostMessage(g_hwndClipboard, WM_WM_REINIT, 0, 0); if (g_fClipboard && g_fClipboardStarted) {
/* Synchronously destroy the clipboard window */
winClipboardWindowDestroy();
/* Wait for the clipboard thread to exit */
pthread_join(g_ptClipboardProc, NULL);
g_fClipboardStarted = FALSE;
winDebug("winClipboardShutdown - Clipboard thread has exited.\n");
} }
} }

View File

@ -33,36 +33,21 @@
#ifdef HAVE_XWIN_CONFIG_H #ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h> #include <xwin-config.h>
#endif #endif
#include "win.h" #include "win.h"
#include "dixstruct.h" #include "dixstruct.h"
#include <X11/Xatom.h>
/*
* Constants
*/
#define CLIP_NUM_SELECTIONS 2
#define CLIP_OWN_PRIMARY 0
#define CLIP_OWN_CLIPBOARD 1
/* /*
* Local function prototypes * Local function prototypes
*/ */
DISPATCH_PROC(winProcEstablishConnection); DISPATCH_PROC(winProcEstablishConnection);
DISPATCH_PROC(winProcSetSelectionOwner);
/* /*
* References to external symbols * References to external symbols
*/ */
extern Bool g_fClipboardLaunched;
extern Bool g_fClipboardStarted;
extern Bool g_fClipboard; extern Bool g_fClipboard;
extern Window g_iClipboardWindow;
extern Atom g_atomLastOwnedSelection;
extern HWND g_hwndClipboard;
/* /*
* Wrapper for internal EstablishConnection function. * Wrapper for internal EstablishConnection function.
@ -127,13 +112,6 @@ winProcEstablishConnection(ClientPtr client)
/* Clear original function pointer */ /* Clear original function pointer */
winProcEstablishConnectionOrig = NULL; winProcEstablishConnectionOrig = NULL;
/* If the clipboard client has already been started, abort */
if (g_fClipboardLaunched) {
ErrorF("winProcEstablishConnection - Clipboard client already "
"launched, returning.\n");
return iReturn;
}
/* Startup the clipboard client if clipboard mode is being used */ /* Startup the clipboard client if clipboard mode is being used */
if (g_fClipboard) { if (g_fClipboard) {
/* /*
@ -163,207 +141,5 @@ winProcEstablishConnection(ClientPtr client)
ErrorF("winProcEstablishConnection - winInitClipboard returned.\n"); ErrorF("winProcEstablishConnection - winInitClipboard returned.\n");
} }
/* Flag that clipboard client has been launched */
g_fClipboardLaunched = TRUE;
return iReturn; return iReturn;
} }
/*
* Wrapper for internal SetSelectionOwner function.
* Grabs ownership of Windows clipboard when X11 clipboard owner changes.
*/
int
winProcSetSelectionOwner(ClientPtr client)
{
int i;
DrawablePtr pDrawable;
WindowPtr pWindow = None;
Bool fOwnedToNotOwned = FALSE;
static Window s_iOwners[CLIP_NUM_SELECTIONS] = { None };
static unsigned long s_ulServerGeneration = 0;
REQUEST(xSetSelectionOwnerReq);
REQUEST_SIZE_MATCH(xSetSelectionOwnerReq);
winDebug("winProcSetSelectionOwner - Hello.\n");
/* Watch for server reset */
if (s_ulServerGeneration != serverGeneration) {
/* Save new generation number */
s_ulServerGeneration = serverGeneration;
/* Initialize static variables */
for (i = 0; i < CLIP_NUM_SELECTIONS; ++i)
s_iOwners[i] = None;
}
/* Abort if clipboard not completely initialized yet */
if (!g_fClipboardStarted) {
/* ErrorF ("winProcSetSelectionOwner - Clipboard not yet started, "
"aborting.\n"); */
goto winProcSetSelectionOwner_Done;
}
/* Grab window if we have one */
if (None != stuff->window) {
/* Grab the Window from the request */
int rc =
dixLookupWindow(&pWindow, stuff->window, client, DixReadAccess);
if (rc != Success) {
ErrorF("winProcSetSelectionOwner - Found BadWindow, aborting.\n");
goto winProcSetSelectionOwner_Done;
}
}
/* Now we either have a valid window or None */
/* Save selection owners for monitored selections, ignore other selections */
if (XA_PRIMARY == stuff->selection) {
/* Look for owned -> not owned transition */
if (None == stuff->window && None != s_iOwners[CLIP_OWN_PRIMARY]) {
fOwnedToNotOwned = TRUE;
winDebug("winProcSetSelectionOwner - PRIMARY - Going from "
"owned to not owned.\n");
/* Adjust last owned selection */
if (None != s_iOwners[CLIP_OWN_CLIPBOARD])
g_atomLastOwnedSelection = MakeAtom("CLIPBOARD", 9, TRUE);
else
g_atomLastOwnedSelection = None;
}
/* Save new selection owner or None */
s_iOwners[CLIP_OWN_PRIMARY] = stuff->window;
winDebug("winProcSetSelectionOwner - PRIMARY - Now owned by: %d\n",
stuff->window);
}
else if (MakeAtom("CLIPBOARD", 9, TRUE) == stuff->selection) {
/* Look for owned -> not owned transition */
if (None == stuff->window && None != s_iOwners[CLIP_OWN_CLIPBOARD]) {
fOwnedToNotOwned = TRUE;
winDebug("winProcSetSelectionOwner - CLIPBOARD - Going from "
"owned to not owned.\n");
/* Adjust last owned selection */
if (None != s_iOwners[CLIP_OWN_PRIMARY])
g_atomLastOwnedSelection = XA_PRIMARY;
else
g_atomLastOwnedSelection = None;
}
/* Save new selection owner or None */
s_iOwners[CLIP_OWN_CLIPBOARD] = stuff->window;
winDebug("winProcSetSelectionOwner - CLIPBOARD - Now owned by: %d\n",
stuff->window);
}
else
goto winProcSetSelectionOwner_Done;
/*
* At this point, if one of the selections is still owned by the
* clipboard manager then it should be marked as unowned since
* we will be taking ownership of the Win32 clipboard.
*/
if (g_iClipboardWindow == s_iOwners[CLIP_OWN_PRIMARY])
s_iOwners[CLIP_OWN_PRIMARY] = None;
if (g_iClipboardWindow == s_iOwners[CLIP_OWN_CLIPBOARD])
s_iOwners[CLIP_OWN_CLIPBOARD] = None;
/*
* Handle case when selection is being disowned,
* WM_DRAWCLIPBOARD did not do the disowning,
* both monitored selections are no longer owned,
* an owned to not owned transition was detected,
* and we currently own the Win32 clipboard.
*/
if (stuff->window == None
&& s_iOwners[CLIP_OWN_PRIMARY] == None
&& s_iOwners[CLIP_OWN_CLIPBOARD] == None
&& fOwnedToNotOwned
&& g_hwndClipboard != NULL && g_hwndClipboard == GetClipboardOwner()) {
winDebug("winProcSetSelectionOwner - We currently own the "
"clipboard and neither the PRIMARY nor the CLIPBOARD "
"selections are owned, releasing ownership of Win32 "
"clipboard.\n");
/* Release ownership of the Windows clipboard */
OpenClipboard(NULL);
EmptyClipboard();
CloseClipboard();
goto winProcSetSelectionOwner_Done;
}
/* Abort if no window at this point */
if (None == stuff->window) {
winDebug("winProcSetSelectionOwner - No window, returning.\n");
goto winProcSetSelectionOwner_Done;
}
/* Abort if invalid selection */
if (!ValidAtom(stuff->selection)) {
ErrorF("winProcSetSelectionOwner - Found BadAtom, aborting.\n");
goto winProcSetSelectionOwner_Done;
}
/* Cast Window to Drawable */
pDrawable = (DrawablePtr) pWindow;
/* Abort if clipboard manager is owning the selection */
if (pDrawable->id == g_iClipboardWindow) {
winDebug("winProcSetSelectionOwner - We changed ownership, "
"aborting.\n");
goto winProcSetSelectionOwner_Done;
}
/* Abort if root window is taking ownership */
if (pDrawable->id == 0) {
ErrorF("winProcSetSelectionOwner - Root window taking ownership, "
"aborting\n");
goto winProcSetSelectionOwner_Done;
}
/* Close clipboard if we have it open already */
if (GetOpenClipboardWindow() == g_hwndClipboard) {
CloseClipboard();
}
/* Access the Windows clipboard */
if (!OpenClipboard(g_hwndClipboard)) {
ErrorF("winProcSetSelectionOwner - OpenClipboard () failed: %08x\n",
(int) GetLastError());
goto winProcSetSelectionOwner_Done;
}
/* Take ownership of the Windows clipboard */
if (!EmptyClipboard()) {
ErrorF("winProcSetSelectionOwner - EmptyClipboard () failed: %08x\n",
(int) GetLastError());
goto winProcSetSelectionOwner_Done;
}
/* Advertise regular text and unicode */
SetClipboardData(CF_UNICODETEXT, NULL);
SetClipboardData(CF_TEXT, NULL);
/* Save handle to last owned selection */
g_atomLastOwnedSelection = stuff->selection;
/* Release the clipboard */
if (!CloseClipboard()) {
ErrorF("winProcSetSelectionOwner - CloseClipboard () failed: "
"%08x\n", (int) GetLastError());
goto winProcSetSelectionOwner_Done;
}
winProcSetSelectionOwner_Done:
return (*winProcSetSelectionOwnerOrig) (client);
}

View File

@ -36,13 +36,6 @@
#include <shellapi.h> #include <shellapi.h>
#include "winprefs.h" #include "winprefs.h"
/*
* References to external globals
*/
#ifdef XWIN_CLIPBOARD
extern Bool g_fClipboardStarted;
#endif
/* /*
* Local function prototypes * Local function prototypes
*/ */

View File

@ -86,7 +86,6 @@ pthread_mutex_t g_pmTerminating = PTHREAD_MUTEX_INITIALIZER;
* Wrapped DIX functions * Wrapped DIX functions
*/ */
winDispatchProcPtr winProcEstablishConnectionOrig = NULL; winDispatchProcPtr winProcEstablishConnectionOrig = NULL;
winDispatchProcPtr winProcSetSelectionOwnerOrig = NULL;
/* /*
* Clipboard variables * Clipboard variables
@ -94,13 +93,7 @@ winDispatchProcPtr winProcSetSelectionOwnerOrig = NULL;
Bool g_fUnicodeClipboard = TRUE; Bool g_fUnicodeClipboard = TRUE;
Bool g_fClipboard = TRUE; Bool g_fClipboard = TRUE;
Bool g_fClipboardLaunched = FALSE;
Bool g_fClipboardStarted = FALSE; Bool g_fClipboardStarted = FALSE;
pthread_t g_ptClipboardProc;
HWND g_hwndClipboard = NULL;
void *g_pClipboardDisplay = NULL;
Window g_iClipboardWindow = None;
Atom g_atomLastOwnedSelection = None;
#endif #endif
/* /*
@ -112,10 +105,4 @@ void
winInitializeGlobals(void) winInitializeGlobals(void)
{ {
g_dwCurrentThreadID = GetCurrentThreadId(); g_dwCurrentThreadID = GetCurrentThreadId();
#ifdef XWIN_CLIPBOARD
g_iClipboardWindow = None;
g_pClipboardDisplay = NULL;
g_atomLastOwnedSelection = None;
g_hwndClipboard = NULL;
#endif
} }

View File

@ -72,8 +72,10 @@ typedef int (*winDispatchProcPtr) (ClientPtr);
* Wrapped DIX functions * Wrapped DIX functions
*/ */
extern winDispatchProcPtr winProcEstablishConnectionOrig; extern winDispatchProcPtr winProcEstablishConnectionOrig;
extern winDispatchProcPtr winProcSetSelectionOwnerOrig;
#endif #endif
extern Bool g_fUnicodeClipboard;
extern Bool g_fClipboard;
extern Bool g_fClipboardStarted;
/* The global X default icons */ /* The global X default icons */
#if defined(XWIN_MULTIWINDOW) #if defined(XWIN_MULTIWINDOW)

View File

@ -42,6 +42,9 @@
#include "winmsg.h" #include "winmsg.h"
#include "winmonitors.h" #include "winmonitors.h"
#include "inputstr.h" #include "inputstr.h"
#ifdef XWIN_CLIPBOARD
#include "winclipboard/winclipboard.h"
#endif
/* /*
* Global variables * Global variables