diff options
author | marha <marha@users.sourceforge.net> | 2014-10-01 23:12:13 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2014-10-01 23:12:13 +0200 |
commit | 88236adfe3eb41b8368b4c9ecf3e09a7199dc474 (patch) | |
tree | 6acb3f7ad3c60c4605551245df9c321b5fb22c3b /xorg-server/hw/xwin/winclipboard | |
parent | e4086b3defb6186a2fb8a5845968c97e613fb493 (diff) | |
parent | 30eb28e89e513ba7c04e8424be0cba326a01882b (diff) | |
download | vcxsrv-88236adfe3eb41b8368b4c9ecf3e09a7199dc474.tar.gz vcxsrv-88236adfe3eb41b8368b4c9ecf3e09a7199dc474.tar.bz2 vcxsrv-88236adfe3eb41b8368b4c9ecf3e09a7199dc474.zip |
Merge remote-tracking branch 'origin/released'
Conflicts:
xorg-server/hw/xwin/InitOutput.c
xorg-server/hw/xwin/win.h
xorg-server/hw/xwin/winclipboard/internal.h
xorg-server/hw/xwin/winclipboard/thread.c
xorg-server/hw/xwin/winclipboard/wndproc.c
xorg-server/hw/xwin/winclipboard/xevents.c
xorg-server/hw/xwin/winclipboardinit.c
xorg-server/hw/xwin/winclipboardwrappers.c
xorg-server/hw/xwin/winglobals.c
Diffstat (limited to 'xorg-server/hw/xwin/winclipboard')
-rw-r--r-- | xorg-server/hw/xwin/winclipboard/Makefile.am | 25 | ||||
-rw-r--r-- | xorg-server/hw/xwin/winclipboard/debug.c | 52 | ||||
-rwxr-xr-x | xorg-server/hw/xwin/winclipboard/internal.h | 125 | ||||
-rw-r--r-- | xorg-server/hw/xwin/winclipboard/makefile | 18 | ||||
-rw-r--r-- | xorg-server/hw/xwin/winclipboard/textconv.c | 151 | ||||
-rwxr-xr-x | xorg-server/hw/xwin/winclipboard/thread.c | 480 | ||||
-rw-r--r-- | xorg-server/hw/xwin/winclipboard/winclipboard.h | 31 | ||||
-rwxr-xr-x | xorg-server/hw/xwin/winclipboard/wndproc.c | 516 | ||||
-rwxr-xr-x | xorg-server/hw/xwin/winclipboard/xevents.c | 747 | ||||
-rw-r--r-- | xorg-server/hw/xwin/winclipboard/xwinclip.c | 127 | ||||
-rw-r--r-- | xorg-server/hw/xwin/winclipboard/xwinclip.man | 61 |
11 files changed, 2333 insertions, 0 deletions
diff --git a/xorg-server/hw/xwin/winclipboard/Makefile.am b/xorg-server/hw/xwin/winclipboard/Makefile.am new file mode 100644 index 000000000..b1c95f4ef --- /dev/null +++ b/xorg-server/hw/xwin/winclipboard/Makefile.am @@ -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 diff --git a/xorg-server/hw/xwin/winclipboard/debug.c b/xorg-server/hw/xwin/winclipboard/debug.c new file mode 100644 index 000000000..78ab6d902 --- /dev/null +++ b/xorg-server/hw/xwin/winclipboard/debug.c @@ -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; +} diff --git a/xorg-server/hw/xwin/winclipboard/internal.h b/xorg-server/hw/xwin/winclipboard/internal.h new file mode 100755 index 000000000..d42497cc9 --- /dev/null +++ b/xorg-server/hw/xwin/winclipboard/internal.h @@ -0,0 +1,125 @@ +#ifndef _WINCLIPBOARD_H_ +#define _WINCLIPBOARD_H_ +/* + *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved. + * + *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 HAROLD L HUNT II 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 Harold L Hunt II + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from Harold L Hunt II. + * + * Authors: Harold L Hunt II + */ + +/* Standard library headers */ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#ifndef _MSC_VER +#include <unistd.h> +#endif +#ifdef __CYGWIN__ +#include <sys/select.h> +#else +#include <X11/Xwinsock.h> +#endif +#include <fcntl.h> +#include <setjmp.h> +#ifdef _MSC_VER +typedef int pid_t; +#endif +#include <pthread.h> + +/* X headers */ +#include <X11/X.h> +#include <X11/Xatom.h> +#include <X11/Xproto.h> +#include <X11/Xutil.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 + +#include "winmsg.h" + +/* + * References to external symbols + */ + +extern char *display; +/* + * winclipboardinit.c + */ + +Bool + winInitClipboard(void); + +HWND winClipboardCreateMessagingWindow(void); + +/* + * winclipboardtextconv.c + */ + +void + winClipboardDOStoUNIX(char *pszData, int iLength); + +void + winClipboardUNIXtoDOS(char **ppszData, int iLength); + +/* + * winclipboardthread.c + */ + +void *winClipboardProc(void *); + +/* + * winclipboardwndproc.c + */ + +BOOL winClipboardFlushWindowsMessageQueue(HWND hwnd); + +LRESULT CALLBACK +winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +/* + * winclipboardxevents.c + */ + +int + +winClipboardFlushXEvents(HWND hwnd, + int iWindow, Display * pDisplay, Bool fUnicodeSupport, Bool ClipboardOpened); +#endif diff --git a/xorg-server/hw/xwin/winclipboard/makefile b/xorg-server/hw/xwin/winclipboard/makefile new file mode 100644 index 000000000..f49117b3e --- /dev/null +++ b/xorg-server/hw/xwin/winclipboard/makefile @@ -0,0 +1,18 @@ +LIBRARY = libXWinclipboard + +CSRCS = \ + textconv.c \ + thread.c \ + wndproc.c \ + xevents.c + +INCLUDES += .. + +DEFINES += HAVE_XWIN_CONFIG_H +DEFINES += XWIN_CLIPBOARD +DEFINES += XWIN_MULTIWINDOW +DEFINES += XWIN_GLX_WINDOWS +DEFINES += XWIN_RANDR +DEFINES += RELOCATE_PROJECTROOT +DEFINES += PTW32_STATIC_LIB + diff --git a/xorg-server/hw/xwin/winclipboard/textconv.c b/xorg-server/hw/xwin/winclipboard/textconv.c new file mode 100644 index 000000000..9c9cb3529 --- /dev/null +++ b/xorg-server/hw/xwin/winclipboard/textconv.c @@ -0,0 +1,151 @@ +/* + *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved. + * + *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 HAROLD L HUNT II 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 Harold L Hunt II + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from Harold L Hunt II. + * + * Authors: Harold L Hunt II + */ + +#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 <stdlib.h> +#include "internal.h" + +/* + * Convert \r\n to \n + * + * NOTE: This was heavily inspired by, Cygwin's + * winsup/cygwin/fhandler.cc/fhandler_base::read () + */ + +void +winClipboardDOStoUNIX(char *pszSrc, int iLength) +{ + char *pszDest = pszSrc; + char *pszEnd = pszSrc + iLength; + + /* Loop until the last character */ + while (pszSrc < pszEnd) { + /* Copy the current source character to current destination character */ + *pszDest = *pszSrc; + + /* Advance to the next source character */ + pszSrc++; + + /* Don't advance the destination character if we need to drop an \r */ + if (*pszDest != '\r' || *pszSrc != '\n') + pszDest++; + } + + /* Move the terminating null */ + *pszDest = '\0'; +} + +/* + * Convert \n to \r\n + */ + +void +winClipboardUNIXtoDOS(char **ppszData, int iLength) +{ + int iNewlineCount = 0; + char *pszSrc = *ppszData; + char *pszEnd = pszSrc + iLength; + char *pszDest = NULL, *pszDestBegin = NULL; + + winDebug("UNIXtoDOS () - Original data:'%s'\n", *ppszData); + + /* Count \n characters without leading \r */ + while (pszSrc < pszEnd) { + /* Skip ahead two character if found set of \r\n */ + if (*pszSrc == '\r' && pszSrc + 1 < pszEnd && *(pszSrc + 1) == '\n') { + pszSrc += 2; + continue; + } + + /* Increment the count if found naked \n */ + if (*pszSrc == '\n') { + iNewlineCount++; + } + + pszSrc++; + } + + /* Return if no naked \n's */ + if (iNewlineCount == 0) + return; + + /* Allocate a new string */ + pszDestBegin = pszDest = malloc(iLength + iNewlineCount + 1); + + /* Set source pointer to beginning of data string */ + pszSrc = *ppszData; + + /* Loop through all characters in source string */ + while (pszSrc < pszEnd) { + /* Copy line endings that are already valid */ + if (*pszSrc == '\r' && pszSrc + 1 < pszEnd && *(pszSrc + 1) == '\n') { + *pszDest = *pszSrc; + *(pszDest + 1) = *(pszSrc + 1); + pszDest += 2; + pszSrc += 2; + continue; + } + + /* Add \r to naked \n's */ + if (*pszSrc == '\n') { + *pszDest = '\r'; + *(pszDest + 1) = *pszSrc; + pszDest += 2; + pszSrc += 1; + continue; + } + + /* Copy normal characters */ + *pszDest = *pszSrc; + pszSrc++; + pszDest++; + } + + /* Put terminating null at end of new string */ + *pszDest = '\0'; + + /* Swap string pointers */ + free(*ppszData); + *ppszData = pszDestBegin; + + winDebug("UNIXtoDOS () - Final string:'%s'\n", pszDestBegin); +} diff --git a/xorg-server/hw/xwin/winclipboard/thread.c b/xorg-server/hw/xwin/winclipboard/thread.c new file mode 100755 index 000000000..56f5484e6 --- /dev/null +++ b/xorg-server/hw/xwin/winclipboard/thread.c @@ -0,0 +1,480 @@ +/* + *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 HAROLD L HUNT II 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> +#else +#define HAS_WINSOCK 1 +#endif +#include <sys/types.h> +#include <signal.h> +#include <pthread.h> +#include "winclipboard.h" +#include "windisplay.h" +#ifdef __CYGWIN__ +#include <errno.h> +#endif +#include "misc.h" +#include "winmsg.h" +#include "internal.h" + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif +/* + * References to external symbols + */ + +extern Bool g_fUnicodeClipboard; +extern Bool g_fClipboardStarted; +extern Bool g_fClipboardLaunched; +extern HWND g_hwndClipboard; +extern void *g_pClipboardDisplay; +extern Window g_iClipboardWindow; +extern Bool g_fClipboardPrimary; + +/* + * Global variables + */ + +static jmp_buf g_jmpEntry; +static XIOErrorHandler g_winClipboardOldIOErrorHandler; +static pthread_t g_winClipboardProcThread; + +Bool g_fUseUnicode = FALSE; + +/* + * Local function prototypes + */ + +static int + winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr); + +static int + winClipboardIOErrorHandler(Display * pDisplay); + +static void +winClipboardThreadExit(void *arg); +/* + * Main thread function + */ + +void * +winClipboardProc(void *pvNotUsed) +{ + Atom atomClipboard; + int iReturn; + HWND hwnd = NULL; + int iConnectionNumber = 0; + +#ifdef HAS_DEVWINDOWS + int fdMessageQueue = 0; +#else + struct timeval tvTimeout; +#endif + fd_set fdsRead; + int iMaxDescriptor; + Display *pDisplay = NULL; + Window iWindow = None; + int iRetries; + Bool fUseUnicode; + char szDisplay[512]; + int iSelectError; + + pthread_cleanup_push(&winClipboardThreadExit, NULL); + + winDebug ("winClipboardProc - Hello\n"); + + /* Do we use Unicode clipboard? */ + fUseUnicode = g_fUnicodeClipboard; + + /* Save the Unicode support flag in a global */ + g_fUseUnicode = fUseUnicode; + + /* Create Windows messaging window */ + hwnd = winClipboardCreateMessagingWindow (); + + /* Save copy of HWND in screen privates */ + g_hwndClipboard = hwnd; + + /* Set error handler */ + XSetErrorHandler(winClipboardErrorHandler); + g_winClipboardProcThread = pthread_self(); + g_winClipboardOldIOErrorHandler = + XSetIOErrorHandler(winClipboardIOErrorHandler); + + /* 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 thread_errorexit; + } + 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"); + } + + /* 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 */ + winDebug ("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 */ + if (pDisplay == NULL) { + ErrorF("winClipboardProc - Failed opening the display, giving up\n"); + goto thread_errorexit; + } + + /* Save the display in the screen privates */ + g_pClipboardDisplay = pDisplay; + + winDebug ("winClipboardProc - XOpenDisplay () returned and " + "successfully opened the display.\n"); + + /* Get our connection number */ + iConnectionNumber = ConnectionNumber(pDisplay); + + winDebug("Clipboard is using socket %d\n",iConnectionNumber); + +#ifdef HAS_DEVWINDOWS + /* Open a file descriptor for the windows message queue */ + fdMessageQueue = open (WIN_MSG_QUEUE_FNAME, _O_RDONLY); + if (fdMessageQueue == -1) { + ErrorF("winClipboardProc - Failed opening %s\n", WIN_MSG_QUEUE_FNAME); + goto thread_errorexit; + } + + /* Find max of our file descriptors */ + iMaxDescriptor = max(fdMessageQueue, iConnectionNumber) + 1; +#else + iMaxDescriptor = iConnectionNumber + 1; +#endif + + /* Create atom */ + atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False); + XInternAtom (pDisplay, WIN_LOCAL_PROPERTY, False); + XInternAtom (pDisplay, "UTF8_STRING", False); + XInternAtom (pDisplay, "COMPOUND_TEXT", False); + XInternAtom (pDisplay, "TARGETS", False); + + /* Create a messaging window */ + iWindow = XCreateSimpleWindow(pDisplay, + DefaultRootWindow(pDisplay), + 1, 1, + 500, 500, + 0, + BlackPixel(pDisplay, 0), + BlackPixel(pDisplay, 0)); + if (iWindow == 0) { + ErrorF("winClipboardProc - Could not create an X window.\n"); + goto thread_errorexit; + } + + XStoreName(pDisplay, iWindow, "xwinclip"); + + /* Select event types to watch */ + if (XSelectInput(pDisplay, iWindow, PropertyChangeMask) == BadWindow) + ErrorF("winClipboardProc - XSelectInput generated BadWindow " + "on messaging window\n"); + + /* Save the window in the screen privates */ + g_iClipboardWindow = iWindow; + + /* Assert ownership of selections if Win32 clipboard is owned */ + if (NULL != GetClipboardOwner()) { + if (g_fClipboardPrimary) + { + /* PRIMARY */ + winDebug("winClipboardProc - asserted ownership.\n"); + iReturn = XSetSelectionOwner (pDisplay, XA_PRIMARY, + iWindow, CurrentTime); + if (iReturn == BadAtom || iReturn == BadWindow /*|| + XGetSelectionOwner (pDisplay, XA_PRIMARY) != iWindow*/) + { + ErrorF ("winClipboardProc - Could not set PRIMARY owner\n"); + goto thread_errorexit; + } + } + + /* CLIPBOARD */ + iReturn = XSetSelectionOwner(pDisplay, atomClipboard, + iWindow, CurrentTime); + if (iReturn == BadAtom || iReturn == BadWindow /*|| + XGetSelectionOwner (pDisplay, atomClipboard) != iWindow*/) + { + ErrorF ("winClipboardProc - Could not set CLIPBOARD owner\n"); + goto thread_errorexit; + } + } + + /* 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); + + /* Pre-flush Windows messages */ + winDebug ("Start flushing \n"); + if (!winClipboardFlushWindowsMessageQueue(hwnd)) + { + ErrorF ("winClipboardFlushWindowsMessageQueue - returned 0\n"); + goto thread_errorexit; + } + + winDebug ("winClipboardProc - Started\n"); + /* Signal that the clipboard client has started */ + g_fClipboardStarted = TRUE; + + /* Loop for X events */ + while (1) { + /* Setup the file descriptor set */ + /* + * NOTE: You have to do this before every call to select + * because select modifies the mask to indicate + * which descriptors are ready. + */ + FD_ZERO(&fdsRead); + FD_SET(iConnectionNumber, &fdsRead); +#ifdef HAS_DEVWINDOWS + FD_SET(fdMessageQueue, &fdsRead); +#else + tvTimeout.tv_sec = 0; + tvTimeout.tv_usec = 100; +#endif + + /* Wait for a Windows event or an X event */ + iReturn = select(iMaxDescriptor, /* Highest fds number */ + &fdsRead, /* Read mask */ + NULL, /* No write mask */ + NULL, /* No exception mask */ +#ifdef HAS_DEVWINDOWS + NULL /* No timeout */ +#else + &tvTimeout /* Set timeout */ +#endif + ); + +#ifndef HAS_WINSOCK + iSelectError = errno; +#else + iSelectError = WSAGetLastError(); +#endif + + if (iReturn < 0) { +#ifndef HAS_WINSOCK + if (iSelectError == EINTR) +#else + if (iSelectError == WSAEINTR) +#endif + continue; + + ErrorF("winClipboardProc - Call to select () failed: %d. " + "Bailing.\n", iReturn); + break; + } + + /* Branch on which descriptor became active */ +// if (FD_ISSET (iConnectionNumber, &fdsRead)) { +// Also do it when no read since winClipboardFlushXEvents +// is sending the output. + /* Process X events */ + winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode, FALSE); +// } + +#ifdef HAS_DEVWINDOWS + /* Check for Windows event ready */ + if (FD_ISSET(fdMessageQueue, &fdsRead)) +#else + if (1) +#endif + { + /* Process Windows messages */ + if (!winClipboardFlushWindowsMessageQueue(hwnd)) { + ErrorF("winClipboardProc - " + "winClipboardFlushWindowsMessageQueue trapped " + "WM_QUIT message, exiting main loop.\n"); + break; + } + } + } + + /* Close our X window */ + if (pDisplay && iWindow) { + iReturn = XDestroyWindow(pDisplay, iWindow); + if (iReturn == BadWindow) + ErrorF("winClipboardProc - XDestroyWindow returned BadWindow.\n"); +#ifdef WINDBG + else + winDebug("winClipboardProc - XDestroyWindow succeeded.\n"); +#endif + } + +#ifdef HAS_DEVWINDOWS + /* Close our Win32 message handle */ + if (fdMessageQueue) + close(fdMessageQueue); +#endif + +#if 0 + /* + * FIXME: XCloseDisplay hangs if we call it, as of 2004/03/26. The + * XSync and XSelectInput calls did not help. + */ + + /* Discard any remaining events */ + XSync(pDisplay, TRUE); + + /* Select event types to watch */ + XSelectInput(pDisplay, DefaultRootWindow(pDisplay), None); + + /* Close our X display */ + if (pDisplay) { + XCloseDisplay(pDisplay); + } +#endif + + goto commonexit; + +thread_errorexit: + if (g_pClipboardDisplay && g_iClipboardWindow) + { + iReturn = XDestroyWindow (g_pClipboardDisplay, g_iClipboardWindow); + if (iReturn == BadWindow) + ErrorF ("winClipboardProc - XDestroyWindow returned BadWindow.\n"); +#ifdef WINDBG + else + winDebug ("winClipboardProc - XDestroyWindow succeeded.\n"); +#endif + } + winDebug ("Clipboard thread died.\n"); + +commonexit: + g_iClipboardWindow = None; + g_pClipboardDisplay = NULL; + g_fClipboardLaunched = FALSE; + g_fClipboardStarted = FALSE; + + pthread_cleanup_pop(0); + + return NULL; +} + +/* + * winClipboardErrorHandler - Our application specific error handler + */ + +static int +winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr) +{ + char pszErrorMsg[100]; + + XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg)); + ErrorF("winClipboardErrorHandler - ERROR: \n\t%s\n" + " errorCode %d\n" + " serial %lu\n" + " resourceID 0x%x\n" + " majorCode %d\n" + " minorCode %d\n" + , pszErrorMsg + , pErr->error_code + , pErr->serial + , pErr->resourceid + , pErr->request_code + , pErr->minor_code); + return 0; +} + +/* + * winClipboardIOErrorHandler - Our application specific IO error handler + */ + +static int +winClipboardIOErrorHandler(Display * pDisplay) +{ + ErrorF("winClipboardIOErrorHandler!\n"); + + if (pthread_equal(pthread_self(), g_winClipboardProcThread)) { + /* Restart at the main entry point */ + longjmp(g_jmpEntry, WIN_JMP_ERROR_IO); + } + + if (g_winClipboardOldIOErrorHandler) + g_winClipboardOldIOErrorHandler(pDisplay); + + return 0; +} + +/* + * winClipboardThreadExit - Thread exit handler + */ + +static void +winClipboardThreadExit(void *arg) +{ + /* clipboard thread has exited, stop server as well */ + AbortDDX(EXIT_ERR_ABORT); + TerminateProcess(GetCurrentProcess(),1); +} diff --git a/xorg-server/hw/xwin/winclipboard/winclipboard.h b/xorg-server/hw/xwin/winclipboard/winclipboard.h new file mode 100644 index 000000000..e4011a172 --- /dev/null +++ b/xorg-server/hw/xwin/winclipboard/winclipboard.h @@ -0,0 +1,31 @@ +// +// 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 + + +#endif diff --git a/xorg-server/hw/xwin/winclipboard/wndproc.c b/xorg-server/hw/xwin/winclipboard/wndproc.c new file mode 100755 index 000000000..0819de4a5 --- /dev/null +++ b/xorg-server/hw/xwin/winclipboard/wndproc.c @@ -0,0 +1,516 @@ +/* + *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 HAROLD L HUNT II 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 +#include <sys/types.h> +#include <sys/time.h> +#include "winclipboard.h" +#include "misc.h" +#include "winmsg.h" +#include "objbase.h" +#include "ddraw.h" +#include "winwindow.h" +#include "internal.h" + +/* + * Constants + */ + +#define WIN_POLL_TIMEOUT 1 + +/* + * References to external symbols + */ + +extern void *g_pClipboardDisplay; +extern Window g_iClipboardWindow; +extern Atom g_atomLastOwnedSelection; +extern Bool g_fClipboardStarted; +extern HWND g_hwndClipboard; +extern Bool g_fClipboardPrimary; + +/* + * Process X events up to specified timeout + */ + +static int +winProcessXEventsTimeout(HWND hwnd, int iWindow, Display * pDisplay, + Bool fUseUnicode, int iTimeoutSec) +{ + int iConnNumber; + struct timeval tv; + int iReturn; + DWORD dwStopTime = GetTickCount() + iTimeoutSec * 1000; + + /* Make sure the output messages are sent before waiting on a response. */ + iReturn = winClipboardFlushXEvents (hwnd, + iWindow, + pDisplay, + fUseUnicode, + TRUE); + if (WIN_XEVENTS_NOTIFY == iReturn) + { + /* Bail out if notify processed */ + return iReturn; + } + + /* Get our connection number */ + iConnNumber = ConnectionNumber(pDisplay); + + /* Loop for X events */ + while (1) { + fd_set fdsRead; + long remainingTime; + + /* Setup the file descriptor set */ + FD_ZERO(&fdsRead); + FD_SET(iConnNumber, &fdsRead); + + /* Adjust timeout */ + remainingTime = dwStopTime - GetTickCount(); + tv.tv_sec = remainingTime / 1000; + tv.tv_usec = (remainingTime % 1000) * 1000; + winDebug("winProcessXEventsTimeout () - %d milliseconds left\n", + remainingTime); + + /* Break out if no time left */ + if (remainingTime <= 0) + return WIN_XEVENTS_SUCCESS; + + /* Wait for an X event */ + iReturn = select(iConnNumber + 1, /* Highest fds number */ + &fdsRead, /* Read mask */ + NULL, /* No write mask */ + NULL, /* No exception mask */ + &tv); /* Timeout */ + if (iReturn < 0) { + ErrorF("winProcessXEventsTimeout - Call to select () failed: %d (%x). " + "Bailing.\n", iReturn, WSAGetLastError()); + break; + } + + /* Branch on which descriptor became active */ + if (FD_ISSET(iConnNumber, &fdsRead)) { + /* Process X events */ + /* Exit when we see that server is shutting down */ + iReturn = winClipboardFlushXEvents(hwnd, + iWindow, pDisplay, fUseUnicode, TRUE); + + winDebug + ("winProcessXEventsTimeout () - winClipboardFlushXEvents returned %d\n", + iReturn); + + if (WIN_XEVENTS_NOTIFY == iReturn) { + /* Bail out if notify processed */ + return iReturn; + } + } + else { + winDebug("winProcessXEventsTimeout - Spurious wake\n"); + } + } + + return WIN_XEVENTS_SUCCESS; +} + +/* + * Process a given Windows message + */ + +LRESULT CALLBACK +winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static HWND s_hwndNextViewer; + + /* Branch on message type */ + switch (message) { + case WM_DESTROY: + { + winDebug("winClipboardWindowProc - WM_DESTROY\n"); + + /* Remove ourselves from the clipboard chain */ + ChangeClipboardChain(hwnd, s_hwndNextViewer); + + s_hwndNextViewer = NULL; + g_hwndClipboard = NULL; + PostQuitMessage(0); + } + return 0; + + case WM_CREATE: + { + HWND first, next; + DWORD error_code = 0; + + winDebug("winClipboardWindowProc - WM_CREATE\n"); + + /* Add ourselves to the clipboard viewer chain */ + s_hwndNextViewer = SetClipboardViewer (hwnd); + #ifdef _DEBUG + if (s_hwndNextViewer== hwnd) + { + ErrorF("WM_CREATE: SetClipboardViewer returned own window. This causes an endless loop, so reset s_hwndNextViewer. "); + s_hwndNextViewer=NULL; + } + #endif + + } + return 0; + + case WM_CHANGECBCHAIN: + { + winDebug("winClipboardWindowProc - WM_CHANGECBCHAIN: wParam(%x) " + "lParam(%x) s_hwndNextViewer(%x)\n", + wParam, lParam, s_hwndNextViewer); + + if ((HWND) wParam == s_hwndNextViewer) { + s_hwndNextViewer = (HWND) lParam; + if (s_hwndNextViewer == hwnd) { + winDebug("WM_CHANGECBCHAIN: trying to set s_hwndNextViewer to own window. Resetting it back to NULL. "); + s_hwndNextViewer=NULL; /* This would cause an endless loop, so break it by ending the loop here. I have seen this happening, why??? */ + } + } + else if (s_hwndNextViewer) + SendMessage(s_hwndNextViewer, message, wParam, lParam); + + } + winDebug("winClipboardWindowProc - WM_CHANGECBCHAIN: Exit\n"); + return 0; + + case WM_WM_REINIT: + { + /* Ensure that we're in the clipboard chain. Some apps, + * WinXP's remote desktop for one, don't play nice with the + * chain. This message is called whenever we receive a + * WM_ACTIVATEAPP message to ensure that we continue to + * receive clipboard messages. + * + * It might be possible to detect if we're still in the chain + * by calling SendMessage (GetClipboardViewer(), + * WM_DRAWCLIPBOARD, 0, 0); and then seeing if we get the + * WM_DRAWCLIPBOARD message. That, however, might be more + * expensive than just putting ourselves back into the chain. + */ + + HWND first, next; + DWORD error_code = 0; + if (!g_hwndClipboard) + return 0; + winDebug("winClipboardWindowProc - WM_WM_REINIT: Enter\n"); + + first = GetClipboardViewer(); /* Get handle to first viewer in chain. */ + if (first != hwnd) + { + winDebug (" WM_WM_REINIT: Replacing us(%x) with %x at head " + "of chain\n", hwnd, s_hwndNextViewer); + if (!wParam) ChangeClipboardChain (hwnd, s_hwndNextViewer); /* When wParam is set, the window was already removed from the chain */ + winDebug (" WM_WM_REINIT: Putting us back at head of chain.\n"); + s_hwndNextViewer = SetClipboardViewer (hwnd); + #ifdef _DEBUG + if (s_hwndNextViewer== hwnd) + { + ErrorF("WM_WM_REINIT: SetClipboardViewer returned own window. This causes an endless loop, so reset s_hwndNextViewer. "); + s_hwndNextViewer=NULL; + } + #endif + } + winDebug ("winClipboardWindowProc - WM_WM_REINIT: Exit\n"); + } + return 0; + + 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 0x%x 0x%x 0x%x: Enter\n",hwnd,wParam,lParam); + + if (!g_fClipboardStarted) { + winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit with no processing\n"); + if (s_hwndNextViewer) + SendMessage (s_hwndNextViewer, message, wParam, lParam); + return 0; + } + + 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. + */ + if (!s_fProcessingDrawClipboard) { + s_fProcessingDrawClipboard = TRUE; + } + else { + /* Attempt to break the nesting by getting out of the chain, twice?, and then fix and bail */ + ChangeClipboardChain(hwnd, s_hwndNextViewer); + winFixClipboardChain(1); + ErrorF ("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "Nested calls detected. Re-initing.\n"); + winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); + s_fProcessingDrawClipboard = FALSE; + return 0; + } + + /* + * Do not take ownership of the X11 selections when something + * other than CF_TEXT or CF_UNICODETEXT has been copied + * into the Win32 clipboard. + */ + if (!IsClipboardFormatAvailable(CF_TEXT) + && !IsClipboardFormatAvailable(CF_UNICODETEXT)) { + + winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "Clipboard does not contain CF_TEXT nor " + "CF_UNICODETEXT.\n"); + + /* + * We need to make sure that the X Server has processed + * previous XSetSelectionOwner messages. + */ + XSync(pDisplay, FALSE); + + if (g_fClipboardPrimary) + { + /* Release PRIMARY selection if owned */ + iReturn = XGetSelectionOwner (pDisplay, XA_PRIMARY); + if (iReturn == g_iClipboardWindow) { + winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "PRIMARY selection is owned by us.\n"); + XSetSelectionOwner (pDisplay, XA_PRIMARY, None, CurrentTime); + } + else if (BadWindow == iReturn || BadAtom == iReturn) + ErrorF ("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "XGetSelection failed for PRIMARY: %d\n", + iReturn); + } + /* Release CLIPBOARD selection if owned */ + iReturn = XGetSelectionOwner(pDisplay, atomClipboard); + if (iReturn == g_iClipboardWindow) { + winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "CLIPBOARD selection is owned by us.\n"); + XSetSelectionOwner(pDisplay, atomClipboard, None, CurrentTime); + } + else if (BadWindow == iReturn || BadAtom == iReturn) + ErrorF ("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "XGetSelection failed for CLIPBOARD: %d\n", + iReturn); + + winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); + s_fProcessingDrawClipboard = FALSE; + if (s_hwndNextViewer) + SendMessage(s_hwndNextViewer, message, wParam, lParam); + return 0; + } + /* Only reassert ownership when we did not change the clipboard ourselves */ + if (hwnd!=(HWND)wParam) { + if (g_fClipboardPrimary) { + /* Reassert ownership of PRIMARY */ + iReturn = XSetSelectionOwner (pDisplay, + XA_PRIMARY, iWindow, CurrentTime); + if (iReturn == BadAtom || iReturn == BadWindow || + XGetSelectionOwner (pDisplay, XA_PRIMARY) != iWindow) { + ErrorF ("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "Could not reassert ownership of PRIMARY\n"); + } + else { + winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "Reasserted ownership of PRIMARY\n"); + } + } + /* Reassert ownership of the CLIPBOARD */ + iReturn = XSetSelectionOwner (pDisplay, + atomClipboard, iWindow, CurrentTime); + + if (iReturn == BadAtom || iReturn == BadWindow || + XGetSelectionOwner (pDisplay, atomClipboard) != iWindow) { + ErrorF ("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "Could not reassert ownership of CLIPBOARD\n"); + } + else { + winDebug ("winClipboardWindowProc - WM_DRAWCLIPBOARD - " + "Reasserted ownership of CLIPBOARD\n"); + } + + /* Flush the pending SetSelectionOwner event now */ + XFlush (pDisplay); + } + + s_fProcessingDrawClipboard = FALSE; + winDebug("winClipboardWindowProc - WM_DRAWCLIPBOARD: Exit\n"); + /* Pass the message on the next window in the clipboard viewer chain */ + if (s_hwndNextViewer) + SendMessage(s_hwndNextViewer, message, wParam, lParam); + return 0; + + } + case WM_DESTROYCLIPBOARD: + /* + * NOTE: Intentionally do nothing. + * Changes in the Win32 clipboard are handled by WM_DRAWCLIPBOARD + * above. We only process this message to conform to the specs + * for delayed clipboard rendering in Win32. You might think + * that we need to release ownership of the X11 selections, but + * we do not, because a WM_DRAWCLIPBOARD message will closely + * follow this message and reassert ownership of the X11 + * selections, handling the issue for us. + */ + winDebug("winClipboardWindowProc - WM_DESTROYCLIPBOARD - Ignored.\n"); + return 0; + + case WM_RENDERFORMAT: + case WM_RENDERALLFORMATS: + { + int iReturn; + Display *pDisplay = g_pClipboardDisplay; + Window iWindow = g_iClipboardWindow; + Bool fConvertToUnicode; + + winDebug("winClipboardWindowProc - WM_RENDER*FORMAT - Hello.\n"); + + /* Flag whether to convert to Unicode or not */ + if (message == WM_RENDERALLFORMATS) + fConvertToUnicode = FALSE; + else + fConvertToUnicode = (CF_UNICODETEXT == wParam); + + /* Request the selection contents */ + iReturn = XConvertSelection(pDisplay, + g_atomLastOwnedSelection, + XInternAtom(pDisplay, + "COMPOUND_TEXT", False), + XInternAtom(pDisplay, + WIN_LOCAL_PROPERTY, False), + iWindow, CurrentTime); + if (iReturn == BadAtom || iReturn == BadWindow) { + ErrorF ("winClipboardWindowProc - WM_RENDER*FORMAT - " + "XConvertSelection () failed\n"); + break; + } + + /* Special handling for WM_RENDERALLFORMATS */ + if (message == WM_RENDERALLFORMATS) { + /* We must open and empty the clipboard */ + if (!OpenClipboard(hwnd)) { + ErrorF ("winClipboardWindowProc - WM_RENDER*FORMATS - " + "OpenClipboard () failed: %08x\n", + GetLastError()); + break; + } + + if (!EmptyClipboard()) { + ErrorF ("winClipboardWindowProc - WM_RENDER*FORMATS - " + "EmptyClipboard () failed: %08x\n", + GetLastError()); + CloseClipboard (); + break; + } + } + + /* Process the SelectionNotify event */ + iReturn = winProcessXEventsTimeout(hwnd, + iWindow, + pDisplay, + fConvertToUnicode, WIN_POLL_TIMEOUT); + + /* + * The last call to winProcessXEventsTimeout + * from above had better have seen a notify event, or else we + * are dealing with a buggy or old X11 app. In these cases we + * have to paste some fake data to the Win32 clipboard to + * satisfy the requirement that we write something to it. + */ + if (WIN_XEVENTS_NOTIFY != iReturn) { + ErrorF("winClipboardWindowProc - winProcessXEventsTimeout should have returned WIN_XEVENTS_NOTIFY was %d\n",iReturn); + /* Paste no data, to satisfy required call to SetClipboardData */ + SetClipboardData(CF_UNICODETEXT, NULL); + SetClipboardData(CF_TEXT, NULL); + + ErrorF + ("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY\n"); + } + + /* Special handling for WM_RENDERALLFORMATS */ + if (message == WM_RENDERALLFORMATS) { + /* We must close the clipboard */ + + if (!CloseClipboard()) { + ErrorF ( + "winClipboardWindowProc - WM_RENDERALLFORMATS - " + "CloseClipboard () failed: %08x\n", + GetLastError()); + break; + } + } + + winDebug("winClipboardWindowProc - WM_RENDER*FORMAT - Returning.\n"); + return 0; + } + } + + /* Let Windows perform default processing for unhandled messages */ + return DefWindowProc(hwnd, message, wParam, lParam); +} + +/* + * Process any pending Windows messages + */ + +BOOL +winClipboardFlushWindowsMessageQueue(HWND hwnd) +{ + MSG msg; + + /* Flush the messaging window queue */ + /* NOTE: Do not pass the hwnd of our messaging window to PeekMessage, + * as this will filter out many non-window-specific messages that + * are sent to our thread, such as WM_QUIT. + */ + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + /* Dispatch the message if not WM_QUIT */ + if (msg.message == WM_QUIT) + return FALSE; + else + DispatchMessage(&msg); + } + + return TRUE; +} diff --git a/xorg-server/hw/xwin/winclipboard/xevents.c b/xorg-server/hw/xwin/winclipboard/xevents.c new file mode 100755 index 000000000..cfbf0121e --- /dev/null +++ b/xorg-server/hw/xwin/winclipboard/xevents.c @@ -0,0 +1,747 @@ +/* + *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 HAROLD L HUNT II 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 +#include "winclipboard.h" +#include "misc.h" +#include "winmsg.h" +#include "internal.h" +#include <unistd.h> + +extern Bool g_fClipboardPrimary; + +/* + * Process any pending X events + */ + +int +winClipboardFlushXEvents(HWND hwnd, + int iWindow, Display * pDisplay, Bool fUseUnicode, Bool ClipboardOpened) +{ + 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); + } + + /* Process all pending events */ + while (XPending(pDisplay)) { + XTextProperty xtpText = { 0 }; + XEvent event; + XSelectionEvent eventSelection; + unsigned long ulReturnBytesLeft; + char *pszReturnData = NULL; + char *pszGlobalData = NULL; + int iReturn; + HGLOBAL hGlobal = NULL; + XICCEncodingStyle xiccesStyle; + int iConvertDataLen = 0; + char *pszConvertData = NULL; + char *pszTextList[2] = { NULL }; + int iCount; + char **ppszTextList = NULL; + wchar_t *pwszUnicodeStr = NULL; + int iUnicodeLen = 0; + int iReturnDataLen = 0; + int i; + Bool fAbort = FALSE; + Bool fCloseClipboard = FALSE; + Bool fSetClipboardData = TRUE; + + /* Get the next event - will not block because one is ready */ + XNextEvent(pDisplay, &event); + + winDebug ("Received event type %d\n",event.type); + + /* Branch on the event type */ + switch (event.type) { + /* + * SelectionRequest + */ + + case SelectionRequest: +#ifdef _DEBUG + { + char *pszAtomName = NULL; + + winDebug("SelectionRequest - target %d\n", + event.xselectionrequest.target); + + pszAtomName = XGetAtomName(pDisplay, + event.xselectionrequest.target); + winDebug("SelectionRequest - Target atom name %s\n", pszAtomName); + XFree(pszAtomName); + pszAtomName = NULL; + winDebug ("SelectionRequest - owner %d\n", event.xselectionrequest.owner); + winDebug ("SelectionRequest - requestor %d\n", event.xselectionrequest.requestor); + } +#endif + + /* Abort if invalid target type */ + if (event.xselectionrequest.target != XA_STRING + && event.xselectionrequest.target != atomUTF8String + && event.xselectionrequest.target != atomCompoundText + && event.xselectionrequest.target != atomTargets) { + /* Abort */ + fAbort = TRUE; + goto winClipboardFlushXEvents_SelectionRequest_Done; + } + + /* Handle targets type of request */ + if (event.xselectionrequest.target == atomTargets) { + Atom atomTargetArr[] = { atomTargets, + atomCompoundText, + atomUTF8String, + XA_STRING + }; + + /* Try to change the property */ + iReturn = XChangeProperty(pDisplay, + event.xselectionrequest.requestor, + event.xselectionrequest.property, + XA_ATOM, + 32, + PropModeReplace, + (unsigned char *) atomTargetArr, + (sizeof(atomTargetArr) + / sizeof(atomTargetArr[0]))); + if (iReturn == BadAlloc + || iReturn == BadAtom + || iReturn == BadMatch + || iReturn == BadValue || iReturn == BadWindow) { + ErrorF("winClipboardFlushXEvents - SelectionRequest - " + "XChangeProperty failed: %d\n", iReturn); + } + + /* Setup selection notify xevent */ + eventSelection.type = SelectionNotify; + eventSelection.send_event = True; + eventSelection.display = pDisplay; + eventSelection.requestor = event.xselectionrequest.requestor; + eventSelection.selection = event.xselectionrequest.selection; + eventSelection.target = event.xselectionrequest.target; + eventSelection.property = event.xselectionrequest.property; + eventSelection.time = event.xselectionrequest.time; + + /* + * Notify the requesting window that + * the operation has completed + */ + iReturn = XSendEvent(pDisplay, + eventSelection.requestor, + False, 0L, (XEvent *) &eventSelection); + if (iReturn == BadValue || iReturn == BadWindow) { + ErrorF("winClipboardFlushXEvents - SelectionRequest - " + "XSendEvent () failed\n"); + } + break; + } + + /* Access the clipboard */ + if (!ClipboardOpened) + { + if (!OpenClipboard (hwnd)) + { + ErrorF ("winClipboardFlushXEvents - SelectionRequest - " + "OpenClipboard () failed: %08lx\n", + GetLastError ()); + + /* Abort */ + fAbort = TRUE; + goto winClipboardFlushXEvents_SelectionRequest_Done; + } + + /* Indicate that clipboard was opened */ + fCloseClipboard = TRUE; + } + + /* Check that clipboard format is available */ + if (fUseUnicode && !IsClipboardFormatAvailable(CF_UNICODETEXT)) { + static int count; /* Hack to stop acroread spamming the log */ + static HWND lasthwnd; /* I've not seen any other client get here repeatedly? */ + + if (hwnd != lasthwnd) + count = 0; + count++; + if (count < 6) + ErrorF("winClipboardFlushXEvents - CF_UNICODETEXT is not " + "available from Win32 clipboard. Aborting %d.\n", + count); + lasthwnd = hwnd; + + /* Abort */ + fAbort = TRUE; + goto winClipboardFlushXEvents_SelectionRequest_Done; + } + else if (!fUseUnicode && !IsClipboardFormatAvailable(CF_TEXT)) { + ErrorF("winClipboardFlushXEvents - CF_TEXT is not " + "available from Win32 clipboard. Aborting.\n"); + + /* Abort */ + fAbort = TRUE; + goto winClipboardFlushXEvents_SelectionRequest_Done; + } + + /* Setup the string style */ + if (event.xselectionrequest.target == XA_STRING) + xiccesStyle = XStringStyle; +#ifdef X_HAVE_UTF8_STRING + else if (event.xselectionrequest.target == atomUTF8String) + xiccesStyle = XUTF8StringStyle; +#endif + else if (event.xselectionrequest.target == atomCompoundText) + xiccesStyle = XCompoundTextStyle; + else + xiccesStyle = XStringStyle; + + /* Get a pointer to the clipboard text, in desired format */ + if (fUseUnicode) { + /* Retrieve clipboard data */ + hGlobal = GetClipboardData(CF_UNICODETEXT); + } + else { + /* Retrieve clipboard data */ + hGlobal = GetClipboardData(CF_TEXT); + } + if (!hGlobal) { + if (GetLastError()==ERROR_CLIPBOARD_NOT_OPEN && ClipboardOpened) + { + ErrorF("We should not have received a SelectionRequest????\n" + "The owner is the clipboard, but in reality it was" + "an X window\n"); + /* Set the owner to None */ + if (g_fClipboardPrimary) XSetSelectionOwner (pDisplay, XA_PRIMARY, None, CurrentTime); + XSetSelectionOwner (pDisplay, XInternAtom (pDisplay, "CLIPBOARD", False), None, CurrentTime); + } + ErrorF ("winClipboardFlushXEvents - SelectionRequest - " + "GetClipboardData () failed: %08lx\n", GetLastError()); + + /* Abort */ + fAbort = TRUE; + goto winClipboardFlushXEvents_SelectionRequest_Done; + } + pszGlobalData = (char *) GlobalLock(hGlobal); + + /* Convert the Unicode string to UTF8 (MBCS) */ + if (fUseUnicode) { + iConvertDataLen = WideCharToMultiByte(CP_UTF8, + 0, + (LPCWSTR) pszGlobalData, + -1, NULL, 0, NULL, NULL); + /* NOTE: iConvertDataLen includes space for null terminator */ + pszConvertData = malloc(iConvertDataLen); + WideCharToMultiByte(CP_UTF8, + 0, + (LPCWSTR) pszGlobalData, + -1, + pszConvertData, + iConvertDataLen, NULL, NULL); + } + else { + pszConvertData = strdup(pszGlobalData); + iConvertDataLen = strlen(pszConvertData) + 1; + } + + /* Convert DOS string to UNIX string */ + winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData)); + + /* Setup our text list */ + pszTextList[0] = pszConvertData; + pszTextList[1] = NULL; + + /* Initialize the text property */ + xtpText.value = NULL; + xtpText.nitems = 0; + + /* Create the text property from the text list */ + if (fUseUnicode) { +#ifdef X_HAVE_UTF8_STRING + iReturn = Xutf8TextListToTextProperty(pDisplay, + pszTextList, + 1, xiccesStyle, &xtpText); +#endif + } + else { + iReturn = XmbTextListToTextProperty(pDisplay, + pszTextList, + 1, xiccesStyle, &xtpText); + } + if (iReturn == XNoMemory || iReturn == XLocaleNotSupported) { + ErrorF("winClipboardFlushXEvents - SelectionRequest - " + "X*TextListToTextProperty failed: %d\n", iReturn); + + /* Abort */ + fAbort = TRUE; + goto winClipboardFlushXEvents_SelectionRequest_Done; + } + + /* Free the converted string */ + free(pszConvertData); + pszConvertData = NULL; + + /* Copy the clipboard text to the requesting window */ + iReturn = XChangeProperty(pDisplay, + event.xselectionrequest.requestor, + event.xselectionrequest.property, + event.xselectionrequest.target, + 8, + PropModeReplace, + xtpText.value, xtpText.nitems); + if (iReturn == BadAlloc || iReturn == BadAtom + || iReturn == BadMatch || iReturn == BadValue + || iReturn == BadWindow) { + ErrorF("winClipboardFlushXEvents - SelectionRequest - " + "XChangeProperty failed: %d\n", iReturn); + + /* Abort */ + fAbort = TRUE; + goto winClipboardFlushXEvents_SelectionRequest_Done; + } + + /* Release the clipboard data */ + GlobalUnlock(hGlobal); + pszGlobalData = NULL; + if (fCloseClipboard) + { + fCloseClipboard = FALSE; + CloseClipboard (); + } + /* Clean up */ + XFree(xtpText.value); + xtpText.value = NULL; + xtpText.nitems = 0; + + /* Setup selection notify event */ + eventSelection.type = SelectionNotify; + eventSelection.send_event = True; + eventSelection.display = pDisplay; + eventSelection.requestor = event.xselectionrequest.requestor; + eventSelection.selection = event.xselectionrequest.selection; + eventSelection.target = event.xselectionrequest.target; + eventSelection.property = event.xselectionrequest.property; + eventSelection.time = event.xselectionrequest.time; + + /* Notify the requesting window that the operation has completed */ + iReturn = XSendEvent(pDisplay, + eventSelection.requestor, + False, 0L, (XEvent *) &eventSelection); + if (iReturn == BadValue || iReturn == BadWindow) { + ErrorF("winClipboardFlushXEvents - SelectionRequest - " + "XSendEvent () failed\n"); + + /* Abort */ + fAbort = TRUE; + goto winClipboardFlushXEvents_SelectionRequest_Done; + } + + winClipboardFlushXEvents_SelectionRequest_Done: + /* Free allocated resources */ + if (xtpText.value) { + XFree(xtpText.value); + xtpText.value = NULL; + xtpText.nitems = 0; + } + free(pszConvertData); + if (hGlobal && pszGlobalData) + GlobalUnlock(hGlobal); + + /* + * Send a SelectionNotify event to the requesting + * client when we abort. + */ + if (fAbort) { + /* Setup selection notify event */ + eventSelection.type = SelectionNotify; + eventSelection.send_event = True; + eventSelection.display = pDisplay; + eventSelection.requestor = event.xselectionrequest.requestor; + eventSelection.selection = event.xselectionrequest.selection; + eventSelection.target = event.xselectionrequest.target; + eventSelection.property = None; + eventSelection.time = event.xselectionrequest.time; + + /* Notify the requesting window that the operation is complete */ + iReturn = XSendEvent(pDisplay, + eventSelection.requestor, + False, 0L, (XEvent *) &eventSelection); + if (iReturn == BadValue || iReturn == BadWindow) { + /* + * Should not be a problem if XSendEvent fails because + * the client may simply have exited. + */ + ErrorF("winClipboardFlushXEvents - SelectionRequest - " + "XSendEvent () failed for abort event.\n"); + } + } + + /* Close clipboard if it was opened */ + if (fCloseClipboard) { + fCloseClipboard = FALSE; + CloseClipboard(); + } + break; + + /* + * SelectionNotify + */ + case SelectionNotify: +#ifdef _DEBUG + winDebug("winClipboardFlushXEvents - SelectionNotify\n"); + { + char *pszAtomName; + + pszAtomName = XGetAtomName(pDisplay, + event.xselection.selection); + + winDebug + ("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n", + pszAtomName); + winDebug ("SelectionNotify - requestor %d\n", event.xselectionrequest.requestor); + XFree(pszAtomName); + } +#endif + + + /* + * Request conversion of UTF8 and CompoundText targets. + */ + if (event.xselection.property == None) { + if (event.xselection.target == XA_STRING) { + winDebug("winClipboardFlushXEvents - SelectionNotify - " + "XA_STRING\n"); + + return WIN_XEVENTS_CONVERT; + } + else if (event.xselection.target == atomUTF8String) { + winDebug("winClipboardFlushXEvents - SelectionNotify - " + "Requesting conversion of UTF8 target.\n"); + + XConvertSelection(pDisplay, + event.xselection.selection, + XA_STRING, + atomLocalProperty, iWindow, CurrentTime); + + /* Process the ConvertSelection event */ + XFlush(pDisplay); + return WIN_XEVENTS_CONVERT; + } +#ifdef X_HAVE_UTF8_STRING + else if (event.xselection.target == atomCompoundText) { + winDebug("winClipboardFlushXEvents - SelectionNotify - " + "Requesting conversion of CompoundText target.\n"); + + XConvertSelection(pDisplay, + event.xselection.selection, + atomUTF8String, + atomLocalProperty, iWindow, CurrentTime); + + /* Process the ConvertSelection event */ + XFlush(pDisplay); + return WIN_XEVENTS_CONVERT; + } +#endif + else { + ErrorF("winClipboardFlushXEvents - SelectionNotify - " + "Unknown format. Cannot request conversion, " + "aborting.\n"); + break; + } + } + + /* Retrieve the size of the stored data */ + iReturn = XGetWindowProperty(pDisplay, iWindow, atomLocalProperty, 0, 0, /* Don't get data, just size */ + False, + AnyPropertyType, + &xtpText.encoding, + &xtpText.format, + &xtpText.nitems, + &ulReturnBytesLeft, &xtpText.value); + if (iReturn != Success) { + ErrorF("winClipboardFlushXEvents - SelectionNotify - " + "XGetWindowProperty () failed, aborting: %d\n", iReturn); + break; + } + + winDebug("SelectionNotify - returned data %d left %d\n", + xtpText.nitems, ulReturnBytesLeft); + + /* Request the selection data */ + iReturn = XGetWindowProperty(pDisplay, + iWindow, + atomLocalProperty, + 0, + ulReturnBytesLeft, + False, + AnyPropertyType, + &xtpText.encoding, + &xtpText.format, + &xtpText.nitems, + &ulReturnBytesLeft, &xtpText.value); + if (iReturn != Success) { + ErrorF("winClipboardFlushXEvents - SelectionNotify - " + "XGetWindowProperty () failed, aborting: %d\n", iReturn); + break; + } + +#ifdef WINDBG + { + char *pszAtomName = NULL; + + winDebug("SelectionNotify - returned data %d left %d\n", + xtpText.nitems, ulReturnBytesLeft); + pszAtomName = XGetAtomName(pDisplay, xtpText.encoding); + winDebug("Notify atom name %s\n", pszAtomName); + XFree(pszAtomName); + pszAtomName = NULL; + } +#endif + + if (fUseUnicode) { +#ifdef X_HAVE_UTF8_STRING + /* Convert the text property to a text list */ + iReturn = Xutf8TextPropertyToTextList(pDisplay, + &xtpText, + &ppszTextList, &iCount); +#endif + } + else { + iReturn = XmbTextPropertyToTextList(pDisplay, + &xtpText, + &ppszTextList, &iCount); + } + if (iReturn == Success || iReturn > 0) { + /* Conversion succeeded or some unconvertible characters */ + if (ppszTextList != NULL) { + iReturnDataLen = 0; + for (i = 0; i < iCount; i++) { + iReturnDataLen += strlen(ppszTextList[i]); + } + pszReturnData = (char *) malloc(iReturnDataLen + 1); + pszReturnData[0] = '\0'; + for (i = 0; i < iCount; i++) { + strcat(pszReturnData, ppszTextList[i]); + } + } + else { + ErrorF("winClipboardFlushXEvents - SelectionNotify - " + "X*TextPropertyToTextList list_return is NULL.\n"); + pszReturnData = (char *) malloc(1); + pszReturnData[0] = '\0'; + } + } + else { + ErrorF("winClipboardFlushXEvents - SelectionNotify - " + "X*TextPropertyToTextList returned: "); + switch (iReturn) { + case XNoMemory: + ErrorF("XNoMemory\n"); + break; + case XLocaleNotSupported: + ErrorF("XLocaleNotSupported\n"); + break; + case XConverterNotFound: + ErrorF("XConverterNotFound\n"); + break; + default: + ErrorF("%d\n", iReturn); + break; + } + pszReturnData = (char *) malloc(1); + pszReturnData[0] = '\0'; + } + + /* Free the data returned from XGetWindowProperty */ + if (ppszTextList) + XFreeStringList(ppszTextList); + ppszTextList = NULL; + XFree(xtpText.value); + xtpText.value = NULL; + xtpText.nitems = 0; + + /* Convert the X clipboard string to DOS format */ + winClipboardUNIXtoDOS((unsigned char **)&pszReturnData, strlen(pszReturnData)); + + if (fUseUnicode) { + /* Find out how much space needed to convert MBCS to Unicode */ + iUnicodeLen = MultiByteToWideChar(CP_UTF8, + 0, + pszReturnData, -1, NULL, 0); + + /* Allocate memory for the Unicode string */ + pwszUnicodeStr = malloc(sizeof(wchar_t) * (iUnicodeLen + 1)); + if (!pwszUnicodeStr) { + ErrorF("winClipboardFlushXEvents - SelectionNotify " + "malloc failed for pwszUnicodeStr, aborting.\n"); + + /* Abort */ + fAbort = TRUE; + goto winClipboardFlushXEvents_SelectionNotify_Done; + } + + /* Do the actual conversion */ + MultiByteToWideChar(CP_UTF8, + 0, + pszReturnData, + -1, pwszUnicodeStr, iUnicodeLen); + + /* Allocate global memory for the X clipboard data */ + hGlobal = GlobalAlloc(GMEM_MOVEABLE, + sizeof(wchar_t) * (iUnicodeLen + 1)); + } + else { + pszConvertData = strdup(pszReturnData); + iConvertDataLen = strlen(pszConvertData) + 1; + + /* Allocate global memory for the X clipboard data */ + hGlobal = GlobalAlloc(GMEM_MOVEABLE, iConvertDataLen); + } + + free(pszReturnData); + + /* Check that global memory was allocated */ + if (!hGlobal) { + ErrorF("winClipboardFlushXEvents - SelectionNotify " + "GlobalAlloc failed, aborting: %ld\n", GetLastError()); + + /* Abort */ + fAbort = TRUE; + goto winClipboardFlushXEvents_SelectionNotify_Done; + } + + /* Obtain a pointer to the global memory */ + pszGlobalData = GlobalLock(hGlobal); + if (pszGlobalData == NULL) { + ErrorF("winClipboardFlushXEvents - Could not lock global " + "memory for clipboard transfer\n"); + + /* Abort */ + fAbort = TRUE; + goto winClipboardFlushXEvents_SelectionNotify_Done; + } + + /* Copy the returned string into the global memory */ + if (fUseUnicode) { + memcpy(pszGlobalData, + pwszUnicodeStr, sizeof(wchar_t) * (iUnicodeLen + 1)); + free(pwszUnicodeStr); + pwszUnicodeStr = NULL; + } + else { + strcpy(pszGlobalData, pszConvertData); + free(pszConvertData); + pszConvertData = NULL; + } + + /* Release the pointer to the global memory */ + GlobalUnlock(hGlobal); + pszGlobalData = NULL; + + /* Push the selection data to the Windows clipboard */ + if (fUseUnicode) + SetClipboardData(CF_UNICODETEXT, hGlobal); + else + SetClipboardData(CF_TEXT, hGlobal); + + /* Flag that SetClipboardData has been called */ + fSetClipboardData = FALSE; + + /* + * NOTE: Do not try to free pszGlobalData, it is owned by + * Windows after the call to SetClipboardData (). + */ + + winClipboardFlushXEvents_SelectionNotify_Done: + /* Free allocated resources */ + if (ppszTextList) + XFreeStringList(ppszTextList); + if (xtpText.value) { + XFree(xtpText.value); + xtpText.value = NULL; + xtpText.nitems = 0; + } + free(pszConvertData); + free(pwszUnicodeStr); + if (hGlobal && pszGlobalData) + GlobalUnlock(hGlobal); + if (fSetClipboardData) { + SetClipboardData(CF_UNICODETEXT, NULL); + SetClipboardData(CF_TEXT, NULL); + } + return WIN_XEVENTS_NOTIFY; + + /* + * SelectionClear + */ + case SelectionClear: +#ifdef _DEBUG + winDebug("SelectionClear - doing nothing\n"); + { + char *pszAtomName; + + pszAtomName = XGetAtomName (pDisplay, + event.xselection.selection); + + winDebug ("SelectionClear - ATOM: %s\n", + pszAtomName); + winDebug ("SelectionClear - owner %d\n", event.xselectionrequest.owner); + + XFree (pszAtomName); + } +#endif + break; + + case PropertyNotify: + break; + + case MappingNotify: + XRefreshKeyboardMapping((XMappingEvent *)&event); + break; + + default: + ErrorF("winClipboardFlushXEvents - unexpected event type %d\n", + event.type); + break; + } + } + + return WIN_XEVENTS_SUCCESS; +} diff --git a/xorg-server/hw/xwin/winclipboard/xwinclip.c b/xorg-server/hw/xwin/winclipboard/xwinclip.c new file mode 100644 index 000000000..3677974c4 --- /dev/null +++ b/xorg-server/hw/xwin/winclipboard/xwinclip.c @@ -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; +} diff --git a/xorg-server/hw/xwin/winclipboard/xwinclip.man b/xorg-server/hw/xwin/winclipboard/xwinclip.man new file mode 100644 index 000000000..822db91d4 --- /dev/null +++ b/xorg-server/hw/xwin/winclipboard/xwinclip.man @@ -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. |