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_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
PKG_CHECK_EXISTS($WINDOWSWMPROTO, [WINDOWSWM=yes], [WINDOWSWM=no])
@ -2600,6 +2600,7 @@ hw/xnest/man/Makefile
hw/xwin/Makefile
hw/xwin/glx/Makefile
hw/xwin/man/Makefile
hw/xwin/winclipboard/Makefile
hw/xquartz/Makefile
hw/xquartz/GL/Makefile
hw/xquartz/bundle/Makefile

View File

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

View File

@ -66,24 +66,11 @@ typedef WINAPI HRESULT(*SHGETFOLDERPATHPROC) (HWND hwndOwner,
/*
* 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
*/
#ifdef XWIN_CLIPBOARD
static void
winClipboardShutdown(void);
#endif
static Bool
winCheckDisplayNumber(void);
@ -125,31 +112,6 @@ static PixmapFormatRec g_PixmapFormats[] = {
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[] = {
#ifdef GLXEXT
{ GlxExtensionInit, "GLX", &noGlxExtension },

View File

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

View File

@ -793,7 +793,7 @@ Bool
winInitClipboard(void);
void
winFixClipboardChain(void);
winClipboardShutdown(void);
#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.
*
@ -30,46 +29,18 @@
* Authors: Harold L Hunt II
*/
/* Standard library headers */
#include <assert.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>
#ifndef WINCLIPBOARD_INTERNAL_H
#define WINCLIPBOARD_INTERNAL_H
/* X headers */
#include <X11/X.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#include <X11/Xlocale.h>
#include <X11/Xlib.h>
/* Windows headers */
#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_CONVERT 2
#define WIN_XEVENTS_NOTIFY 3
#define WIN_CLIPBOARD_RETRIES 40
#define WIN_CLIPBOARD_DELAY 1
#define WM_WM_REINIT (WM_USER + 1)
@ -77,18 +48,8 @@
* References to external symbols
*/
extern char *display;
extern void winDebug(const char *format, ...);
extern void winErrorFVerb(int verb, const char *format, ...);
/*
* winclipboardinit.c
*/
Bool
winInitClipboard(void);
HWND winClipboardCreateMessagingWindow(void);
extern void ErrorF(const char *format, ...);
/*
* winclipboardtextconv.c
@ -104,23 +65,45 @@ void
* winclipboardthread.c
*/
void *winClipboardProc(void *);
typedef struct
{
Atom atomClipboard;
Atom atomLocalProperty;
Atom atomUTF8String;
Atom atomCompoundText;
Atom atomTargets;
} ClipboardAtoms;
/*
* winclipboardwndproc.c
*/
BOOL winClipboardFlushWindowsMessageQueue(HWND hwnd);
Bool winClipboardFlushWindowsMessageQueue(HWND hwnd);
LRESULT CALLBACK
winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
typedef struct
{
Display *pClipboardDisplay;
Window iClipboardWindow;
ClipboardAtoms *atoms;
} ClipboardWindowCreationParams;
/*
* winclipboardxevents.c
*/
int
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

View File

@ -31,14 +31,18 @@
#ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h>
#endif
#include "win.h"
#include <stdio.h>
#include <stdlib.h>
void
winClipboardDOStoUNIX(char *pszSrc, int iLength);
void
winClipboardUNIXtoDOS(char **ppszData, int iLength);
/*
* 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 <stdlib.h>
#include "internal.h"
/*
* Convert \r\n to \n

View File

@ -35,42 +35,62 @@
#else
#define HAS_WINSOCK 1
#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;
extern Bool g_fClipboardStarted;
extern Bool g_fClipboardLaunched;
extern Bool g_fClipboard;
extern HWND g_hwndClipboard;
extern void *g_pClipboardDisplay;
extern Window g_iClipboardWindow;
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <setjmp.h>
#include <pthread.h>
#include <sys/param.h> // for MAX() macro
#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
*/
static HWND g_hwndClipboard = NULL;
static jmp_buf g_jmpEntry;
static int clipboardRestarts = 0;
static XIOErrorHandler g_winClipboardOldIOErrorHandler;
static pthread_t g_winClipboardProcThread;
Bool g_fUseUnicode = FALSE;
int xfixes_event_base;
int xfixes_error_base;
/*
* Local function prototypes
*/
static HWND
winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAtoms *atoms);
static int
winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr);
@ -78,13 +98,15 @@ static int
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 *
winClipboardProc(void *pvNotUsed)
Bool
winClipboardProc(Bool fUseUnicode, char *szDisplay)
{
Atom atomClipboard;
ClipboardAtoms atoms;
int iReturn;
HWND hwnd = NULL;
int iConnectionNumber = 0;
@ -98,19 +120,11 @@ winClipboardProc(void *pvNotUsed)
int iMaxDescriptor;
Display *pDisplay = NULL;
Window iWindow = None;
int iRetries;
Bool fUseUnicode;
char szDisplay[512];
int iSelectError;
Bool fShutdown = FALSE;
static Bool fErrorHandlerSet = FALSE;
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 */
if (XInitThreads() == 0) {
@ -123,70 +137,29 @@ winClipboardProc(void *pvNotUsed)
ErrorF("winClipboardProc - Warning: Locale not supported by X.\n");
}
/* Set error handler */
XSetErrorHandler(winClipboardErrorHandler);
g_winClipboardProcThread = pthread_self();
g_winClipboardOldIOErrorHandler =
XSetIOErrorHandler(winClipboardIOErrorHandler);
/* Set error handler */
if (!fErrorHandlerSet) {
XSetErrorHandler(winClipboardErrorHandler);
g_winClipboardOldIOErrorHandler =
XSetIOErrorHandler(winClipboardIOErrorHandler);
fErrorHandlerSet = TRUE;
}
/* Set jump point for Error exits */
iReturn = 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 */
if (setjmp(g_jmpEntry)) {
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 */
pDisplay = XOpenDisplay(szDisplay);
if (pDisplay == NULL) {
ErrorF("winClipboardProc - Failed opening the display, giving up\n");
goto winClipboardProc_Done;
}
/* Save the display in the screen privates */
g_pClipboardDisplay = pDisplay;
ErrorF("winClipboardProc - XOpenDisplay () returned and "
"successfully opened the display.\n");
@ -202,13 +175,20 @@ winClipboardProc(void *pvNotUsed)
}
/* Find max of our file descriptors */
iMaxDescriptor = max(fdMessageQueue, iConnectionNumber) + 1;
iMaxDescriptor = MAX(fdMessageQueue, iConnectionNumber) + 1;
#else
iMaxDescriptor = iConnectionNumber + 1;
#endif
/* Create atom */
atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False);
if (!XFixesQueryExtension(pDisplay, &xfixes_event_base, &xfixes_error_base))
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 */
iWindow = XCreateSimpleWindow(pDisplay,
@ -230,13 +210,27 @@ winClipboardProc(void *pvNotUsed)
ErrorF("winClipboardProc - XSelectInput generated BadWindow "
"on messaging window\n");
/* Save the window in the screen privates */
g_iClipboardWindow = iWindow;
XFixesSelectSelectionInput (pDisplay,
iWindow,
XA_PRIMARY,
XFixesSetSelectionOwnerNotifyMask |
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask);
XFixesSelectSelectionInput (pDisplay,
iWindow,
atoms.atomClipboard,
XFixesSetSelectionOwnerNotifyMask |
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask);
/* Initialize monitored selection state */
winClipboardInitMonitoredSelections();
/* 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;
/* Assert ownership of selections if Win32 clipboard is owned */
@ -251,29 +245,27 @@ winClipboardProc(void *pvNotUsed)
}
/* CLIPBOARD */
iReturn = XSetSelectionOwner(pDisplay, atomClipboard,
iReturn = XSetSelectionOwner(pDisplay, atoms.atomClipboard,
iWindow, CurrentTime);
if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, atomClipboard) != iWindow) {
XGetSelectionOwner(pDisplay, atoms.atomClipboard) != iWindow) {
ErrorF("winClipboardProc - Could not set CLIPBOARD owner\n");
goto winClipboardProc_Done;
}
}
/* Pre-flush X events */
/*
/*
* NOTE: Apparently you'll freeze if you don't do this,
* because there may be events in local data structures
* already.
*/
winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode);
winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode, &atoms);
/* Pre-flush Windows messages */
if (!winClipboardFlushWindowsMessageQueue(hwnd))
return 0;
/* Signal that the clipboard client has started */
g_fClipboardStarted = TRUE;
if (!winClipboardFlushWindowsMessageQueue(hwnd)) {
ErrorF("winClipboardProc - winClipboardFlushWindowsMessageQueue failed\n");
}
/* Loop for X events */
while (1) {
@ -326,7 +318,7 @@ winClipboardProc(void *pvNotUsed)
/* Branch on which descriptor became active */
if (FD_ISSET(iConnectionNumber, &fdsRead)) {
/* Process X events */
winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode);
winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode, &atoms);
}
#ifdef HAS_DEVWINDOWS
@ -347,16 +339,13 @@ winClipboardProc(void *pvNotUsed)
}
winClipboardProc_Exit:
/* disable the clipboard, which means the thread will die */
g_fClipboard = FALSE;
/* broke out of while loop on a shutdown message */
fShutdown = TRUE;
winClipboardProc_Done:
/* Close our Windows window */
if (g_hwndClipboard) {
/* Destroy the Window window (hwnd) */
winDebug("winClipboardProc - Destroy Windows window\n");
PostMessage(g_hwndClipboard, WM_DESTROY, 0, 0);
winClipboardFlushWindowsMessageQueue(g_hwndClipboard);
winClipboardWindowDestroy();
}
/* Close our X window */
@ -376,8 +365,11 @@ winClipboardProc(void *pvNotUsed)
#if 0
/*
* FIXME: XCloseDisplay hangs if we call it, as of 2004/03/26. The
* XSync and XSelectInput calls did not help.
* FIXME: XCloseDisplay hangs if we call it
*
* 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 */
@ -393,42 +385,64 @@ winClipboardProc(void *pvNotUsed)
#endif
/* global clipboard variable reset */
g_fClipboardLaunched = FALSE;
g_fClipboardStarted = FALSE;
g_iClipboardWindow = None;
g_pClipboardDisplay = NULL;
g_hwndClipboard = NULL;
/* 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;
return NULL;
}
return fShutdown;
}
if (g_fClipboard) {
sleep(WIN_CLIPBOARD_DELAY);
ErrorF("winClipboardProc - trying to restart clipboard thread \n");
/* Create the clipboard client thread */
if (!winInitClipboard()) {
ErrorF("winClipboardProc - winClipboardInit failed.\n");
return NULL;
}
/*
* Create the Windows window that we use to receive Windows messages
*/
winDebug("winClipboardProc - winInitClipboard returned.\n");
/* Flag that clipboard client has been launched */
g_fClipboardLaunched = TRUE;
}
else {
ErrorF("winClipboardProc - Clipboard disabled - Exit from server \n");
/* clipboard thread has exited, stop server as well */
raise(SIGTERM);
}
static HWND
winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAtoms *atoms)
{
WNDCLASSEX wc;
ClipboardWindowCreationParams cwcp;
HWND hwnd;
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)) {
/* Restart at the main entry point */
longjmp(g_jmpEntry, WIN_JMP_ERROR_IO);
longjmp(g_jmpEntry, 2);
}
if (g_winClipboardOldIOErrorHandler)
@ -466,3 +480,19 @@ winClipboardIOErrorHandler(Display * pDisplay)
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
#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 <sys/types.h>
#include <sys/time.h>
#include <X11/Xatom.h>
#include "internal.h"
#include "winclipboard.h"
#include "misc.h"
/*
* Constants
@ -44,21 +57,14 @@
#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
*/
static int
winProcessXEventsTimeout(HWND hwnd, int iWindow, Display * pDisplay,
Bool fUseUnicode, int iTimeoutSec)
winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay,
Bool fUseUnicode, ClipboardAtoms *atoms, int iTimeoutSec)
{
int iConnNumber;
struct timeval tv;
@ -111,7 +117,7 @@ winProcessXEventsTimeout(HWND hwnd, int iWindow, Display * pDisplay,
/* Process X events */
/* Exit when we see that server is shutting down */
iReturn = winClipboardFlushXEvents(hwnd,
iWindow, pDisplay, fUseUnicode);
iWindow, pDisplay, fUseUnicode, atoms);
winDebug
("winProcessXEventsTimeout () - winClipboardFlushXEvents returned %d\n",
@ -139,6 +145,9 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND s_hwndNextViewer;
static Bool s_fCBCInitialized;
static Display *pDisplay;
static Window iWindow;
static ClipboardAtoms *atoms;
/* Branch on message type */
switch (message) {
@ -159,9 +168,14 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HWND first, next;
DWORD error_code = 0;
ClipboardWindowCreationParams *cwcp = (ClipboardWindowCreationParams *)((CREATESTRUCT *)lParam)->lpCreateParams;
winDebug("winClipboardWindowProc - WM_CREATE\n");
pDisplay = cwcp->pClipboardDisplay;
iWindow = cwcp->iClipboardWindow;
atoms = cwcp->atoms;
first = GetClipboardViewer(); /* Get handle to first viewer in chain. */
if (first == hwnd)
return 0; /* Make sure it's not us! */
@ -185,8 +199,8 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
s_hwndNextViewer = (HWND) lParam;
if (s_hwndNextViewer == hwnd) {
s_hwndNextViewer = NULL;
winErrorFVerb(1, "winClipboardWindowProc - WM_CHANGECBCHAIN: "
"attempted to set next window to ourselves.");
ErrorF("winClipboardWindowProc - WM_CHANGECBCHAIN: "
"attempted to set next window to ourselves.");
}
}
else if (s_hwndNextViewer)
@ -241,20 +255,11 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_DRAWCLIPBOARD:
{
static Atom atomClipboard;
static int generation;
static Bool s_fProcessingDrawClipboard = FALSE;
Display *pDisplay = g_pClipboardDisplay;
Window iWindow = g_iClipboardWindow;
int iReturn;
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.
* Try and fix it on the first hint of recursion.
@ -267,8 +272,8 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
s_fCBCInitialized = FALSE;
ChangeClipboardChain(hwnd, s_hwndNextViewer);
winFixClipboardChain();
winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"Nested calls detected. Re-initing.\n");
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"Nested calls detected. Re-initing.\n");
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
s_fProcessingDrawClipboard = FALSE;
return 0;
@ -324,27 +329,27 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/* Release PRIMARY selection if owned */
iReturn = XGetSelectionOwner(pDisplay, XA_PRIMARY);
if (iReturn == g_iClipboardWindow) {
if (iReturn == iWindow) {
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"PRIMARY selection is owned by us.\n");
XSetSelectionOwner(pDisplay, XA_PRIMARY, None, CurrentTime);
}
else if (BadWindow == iReturn || BadAtom == iReturn)
winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"XGetSelection failed for PRIMARY: %d\n",
iReturn);
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"XGetSelectionOwner failed for PRIMARY: %d\n",
iReturn);
/* Release CLIPBOARD selection if owned */
iReturn = XGetSelectionOwner(pDisplay, atomClipboard);
if (iReturn == g_iClipboardWindow) {
iReturn = XGetSelectionOwner(pDisplay, atoms->atomClipboard);
if (iReturn == iWindow) {
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"CLIPBOARD selection is owned by us.\n");
XSetSelectionOwner(pDisplay, atomClipboard, None, CurrentTime);
"CLIPBOARD selection is owned by us, releasing\n");
XSetSelectionOwner(pDisplay, atoms->atomClipboard, None, CurrentTime);
}
else if (BadWindow == iReturn || BadAtom == iReturn)
winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"XGetSelection failed for CLIPBOARD: %d\n",
iReturn);
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"XGetSelectionOwner failed for CLIPBOARD: %d\n",
iReturn);
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n");
s_fProcessingDrawClipboard = FALSE;
@ -358,8 +363,8 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
XA_PRIMARY, iWindow, CurrentTime);
if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) {
winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"Could not reassert ownership of PRIMARY\n");
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"Could not reassert ownership of PRIMARY\n");
}
else {
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
@ -368,12 +373,12 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/* Reassert ownership of the CLIPBOARD */
iReturn = XSetSelectionOwner(pDisplay,
atomClipboard, iWindow, CurrentTime);
atoms->atomClipboard, iWindow, CurrentTime);
if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, atomClipboard) != iWindow) {
winErrorFVerb(1, "winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"Could not reassert ownership of CLIPBOARD\n");
XGetSelectionOwner(pDisplay, atoms->atomClipboard) != iWindow) {
ErrorF("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
"Could not reassert ownership of CLIPBOARD\n");
}
else {
winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - "
@ -409,8 +414,6 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_RENDERALLFORMATS:
{
int iReturn;
Display *pDisplay = g_pClipboardDisplay;
Window iWindow = g_iClipboardWindow;
Bool fConvertToUnicode;
winDebug("winClipboardWindowProc - WM_RENDER*FORMAT - Hello.\n");
@ -423,15 +426,13 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/* Request the selection contents */
iReturn = XConvertSelection(pDisplay,
g_atomLastOwnedSelection,
XInternAtom(pDisplay,
"COMPOUND_TEXT", False),
XInternAtom(pDisplay,
"CYGX_CUT_BUFFER", False),
winClipboardGetLastOwnedSelectionAtom(atoms),
atoms->atomCompoundText,
atoms->atomLocalProperty,
iWindow, CurrentTime);
if (iReturn == BadAtom || iReturn == BadWindow) {
winErrorFVerb(1, "winClipboardWindowProc - WM_RENDER*FORMAT - "
"XConvertSelection () failed\n");
ErrorF("winClipboardWindowProc - WM_RENDER*FORMAT - "
"XConvertSelection () failed\n");
break;
}
@ -445,16 +446,16 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
}
if (!OpenClipboard(hwnd)) {
winErrorFVerb(1, "winClipboardWindowProc - WM_RENDER*FORMATS - "
"OpenClipboard () failed: %08x\n",
GetLastError());
ErrorF("winClipboardWindowProc - WM_RENDER*FORMATS - "
"OpenClipboard () failed: %08x\n",
GetLastError());
break;
}
if (!EmptyClipboard()) {
winErrorFVerb(1, "winClipboardWindowProc - WM_RENDER*FORMATS - "
"EmptyClipboard () failed: %08x\n",
GetLastError());
ErrorF("winClipboardWindowProc - WM_RENDER*FORMATS - "
"EmptyClipboard () failed: %08x\n",
GetLastError());
break;
}
}
@ -463,7 +464,9 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
iReturn = winProcessXEventsTimeout(hwnd,
iWindow,
pDisplay,
fConvertToUnicode, WIN_POLL_TIMEOUT);
fConvertToUnicode,
atoms,
WIN_POLL_TIMEOUT);
/*
* The last call to winProcessXEventsTimeout
@ -486,10 +489,9 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/* We must close the clipboard */
if (!CloseClipboard()) {
winErrorFVerb(1,
"winClipboardWindowProc - WM_RENDERALLFORMATS - "
"CloseClipboard () failed: %08x\n",
GetLastError());
ErrorF("winClipboardWindowProc - WM_RENDERALLFORMATS - "
"CloseClipboard () failed: %08x\n",
GetLastError());
break;
}
}
@ -507,7 +509,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
* Process any pending Windows messages
*/
BOOL
Bool
winClipboardFlushWindowsMessageQueue(HWND hwnd)
{
MSG msg;

View File

@ -33,8 +33,104 @@
#ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h>
#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
@ -42,21 +138,13 @@
int
winClipboardFlushXEvents(HWND hwnd,
int iWindow, Display * pDisplay, Bool fUseUnicode)
Window iWindow, Display * pDisplay, Bool fUseUnicode, ClipboardAtoms *atoms)
{
static Atom atomLocalProperty;
static Atom atomCompoundText;
static Atom atomUTF8String;
static Atom atomTargets;
static int generation;
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);
}
Atom atomClipboard = atoms->atomClipboard;
Atom atomLocalProperty = atoms->atomLocalProperty;
Atom atomUTF8String = atoms->atomUTF8String;
Atom atomCompoundText = atoms->atomCompoundText;
Atom atomTargets = atoms->atomTargets;
/* Process all pending events */
while (XPending(pDisplay)) {
@ -77,7 +165,6 @@ winClipboardFlushXEvents(HWND hwnd,
wchar_t *pwszUnicodeStr = NULL;
int iUnicodeLen = 0;
int iReturnDataLen = 0;
int i;
Bool fAbort = FALSE;
Bool fCloseClipboard = FALSE;
Bool fSetClipboardData = TRUE;
@ -525,6 +612,8 @@ winClipboardFlushXEvents(HWND hwnd,
if (iReturn == Success || iReturn > 0) {
/* Conversion succeeded or some unconvertible characters */
if (ppszTextList != NULL) {
int i;
iReturnDataLen = 0;
for (i = 0; i < iCount; i++) {
iReturnDataLen += strlen(ppszTextList[i]);
@ -693,8 +782,78 @@ winClipboardFlushXEvents(HWND hwnd,
break;
default:
ErrorF("winClipboardFlushXEvents - unexpected event type %d\n",
event.type);
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",
event.type);
}
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
#include <xwin-config.h>
#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);
int winProcSetSelectionOwner(ClientPtr /* client */ );
static pthread_t g_ptClipboardProc;
/*
* References to external symbols
*
*/
static void *
winClipboardThreadProc(void *arg)
{
char szDisplay[512];
int clipboardRestarts = 0;
extern pthread_t g_ptClipboardProc;
extern winDispatchProcPtr winProcSetSelectionOwnerOrig;
extern Bool g_fClipboard;
extern HWND g_hwndClipboard;
while (1)
{
Bool fShutdown;
++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
@ -60,14 +114,8 @@ winInitClipboard(void)
{
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 */
if (pthread_create(&g_ptClipboardProc, NULL, winClipboardProc, NULL)) {
if (pthread_create(&g_ptClipboardProc, NULL, winClipboardThreadProc, NULL)) {
/* Bail if thread creation failed */
ErrorF("winInitClipboard - pthread_create failed.\n");
return FALSE;
@ -76,59 +124,19 @@ winInitClipboard(void)
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
winFixClipboardChain(void)
winClipboardShutdown(void)
{
if (g_fClipboard && g_hwndClipboard) {
PostMessage(g_hwndClipboard, WM_WM_REINIT, 0, 0);
}
/* Close down clipboard resources */
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
#include <xwin-config.h>
#endif
#include "win.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
*/
DISPATCH_PROC(winProcEstablishConnection);
DISPATCH_PROC(winProcSetSelectionOwner);
/*
* References to external symbols
*/
extern Bool g_fClipboardLaunched;
extern Bool g_fClipboardStarted;
extern Bool g_fClipboard;
extern Window g_iClipboardWindow;
extern Atom g_atomLastOwnedSelection;
extern HWND g_hwndClipboard;
/*
* Wrapper for internal EstablishConnection function.
@ -127,13 +112,6 @@ winProcEstablishConnection(ClientPtr client)
/* Clear original function pointer */
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 */
if (g_fClipboard) {
/*
@ -163,207 +141,5 @@ winProcEstablishConnection(ClientPtr client)
ErrorF("winProcEstablishConnection - winInitClipboard returned.\n");
}
/* Flag that clipboard client has been launched */
g_fClipboardLaunched = TRUE;
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 "winprefs.h"
/*
* References to external globals
*/
#ifdef XWIN_CLIPBOARD
extern Bool g_fClipboardStarted;
#endif
/*
* Local function prototypes
*/

View File

@ -86,7 +86,6 @@ pthread_mutex_t g_pmTerminating = PTHREAD_MUTEX_INITIALIZER;
* Wrapped DIX functions
*/
winDispatchProcPtr winProcEstablishConnectionOrig = NULL;
winDispatchProcPtr winProcSetSelectionOwnerOrig = NULL;
/*
* Clipboard variables
@ -94,13 +93,7 @@ winDispatchProcPtr winProcSetSelectionOwnerOrig = NULL;
Bool g_fUnicodeClipboard = TRUE;
Bool g_fClipboard = TRUE;
Bool g_fClipboardLaunched = 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
/*
@ -112,10 +105,4 @@ void
winInitializeGlobals(void)
{
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
*/
extern winDispatchProcPtr winProcEstablishConnectionOrig;
extern winDispatchProcPtr winProcSetSelectionOwnerOrig;
#endif
extern Bool g_fUnicodeClipboard;
extern Bool g_fClipboard;
extern Bool g_fClipboardStarted;
/* The global X default icons */
#if defined(XWIN_MULTIWINDOW)

View File

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