diff options
author | Jon TURNEY <jon.turney@dronecode.org.uk> | 2013-06-14 12:57:45 +0100 |
---|---|---|
committer | Jon TURNEY <jon.turney@dronecode.org.uk> | 2013-06-15 12:34:25 +0100 |
commit | 3673fcb94804ae4e31e20a5d18f7f4e43850098f (patch) | |
tree | 1c922c6ad8ee1e5bd682ef7d9d0ac0945943bab4 | |
parent | 38dcfd7e18eddd28309458a63d10eb5692e4e2ea (diff) |
Import current clipboard integration code from X server
Import current clipboard integration code from X server, and use the
XFixesSetSelectionNotify event instead of a SetSelectionOwner wrapper
SetSelectionOwner, the equivalent client-side mechanism.
Changes this includes are:
- adding ourselves to the clipboard viewer chain to look for changes to the
windows clipboard ownership
- all the checking to ensure that some other application hasn't damaged the chain
- removing the obsolete 'does OS support unicode' check
- lots of clipboard bugfixes.
- provide stub functions for winError/winDebug output
- merging license texts
- re-indentation and clean-up
-rw-r--r-- | Makefile.am | 5 | ||||
-rw-r--r-- | configure.ac | 14 | ||||
-rw-r--r-- | debug.c | 54 | ||||
-rw-r--r-- | debug.h | 38 | ||||
-rw-r--r-- | textconv.c | 158 | ||||
-rw-r--r-- | textconv.h | 6 | ||||
-rw-r--r-- | wndproc.c | 537 | ||||
-rw-r--r-- | wndproc.h | 29 | ||||
-rw-r--r-- | xevents.c | 1485 | ||||
-rw-r--r-- | xevents.h | 21 | ||||
-rw-r--r-- | xwinclip.c | 589 |
11 files changed, 1820 insertions, 1116 deletions
diff --git a/Makefile.am b/Makefile.am index 85f7bc1..48e5896 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,5 +7,6 @@ EXTRA_DIST = $(man_MANS) bin_PROGRAMS = xwinclip xwinclip_SOURCES = xwinclip.c textconv.c wndproc.c xevents.c \ - textconv.h wndproc.h xevents.h -xwinclip_LDADD = $(X_LIBS) -lX11 -lgdi32 + textconv.h wndproc.h xevents.h \ + debug.c debug.h +xwinclip_LDADD = $(X_LIBS) -lXfixes -lX11 -lgdi32 diff --git a/configure.ac b/configure.ac index cfbd6ee..40b25b0 100644 --- a/configure.ac +++ b/configure.ac @@ -3,6 +3,7 @@ dnl Process this file with autoconf to produce a configure script. dnl Auto* initialization AC_INIT(xwinclip, 1.2.0) AC_CONFIG_SRCDIR(xwinclip.c) +AC_CANONICAL_HOST AM_INIT_AUTOMAKE([dist-bzip2]) @@ -28,7 +29,16 @@ AC_PATH_X AC_PATH_XTRA -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT +dnl Checks for host +case $host_os in + cygwin*) + AC_DEFINE(HAS_DEVWINDOWS,1,[Cygwin has /dev/windows for signaling new Windows messages]) + ;; + mingw*) + AC_DEFINE(HAS_WINSOCK,1,[Use Windows sockets]) + ;; +esac +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT @@ -0,0 +1,54 @@ +// +// Copyright © Jon TURNEY 2012 +// +// 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> + +#include "debug.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 +winError(const char *format, ...) +{ + int count; + va_list ap; + va_start(ap, format); + count = vfprintf(stderr, format, ap); + va_end(ap); + return count; +} @@ -0,0 +1,38 @@ +// +// Copyright © Jon TURNEY 2012 +// +// 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. +// + +#ifndef DEBUG_H +#define DEBUG_H + +int winError(const char *format, ...); + +#if 1 +int winDebug(const char *format, ...); +#define DEBUG winDebug +#else +#define DEBUG(Args...) +#endif + +#endif /* DEBUG_H */ @@ -1,5 +1,6 @@ /* *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + *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 @@ -15,138 +16,137 @@ *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 XFREE86 PROJECT BE LIABLE FOR + *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 XFree86 Project - *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 XFree86 Project. + *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 */ -#include "textconv.h" -#include <stdio.h> +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + #include <stdlib.h> +#include "textconv.h" +#include "debug.h" /* * Convert \r\n to \n * - * NOTE: This was heavily inspired by, if not down right stolen from, - * Cygwin's winsup/cygwin/fhandler.cc/fhandler_base::read () + * NOTE: This was heavily inspired by, Cygwin's + * winsup/cygwin/fhandler.cc/fhandler_base::read () */ void -DOStoUNIX (char *pszSrc, int iLength) +DOStoUNIX (char *pszData, int iLength) { - char *pszDest = pszSrc; - char *pszEnd = pszSrc + iLength; + char *pszSrc = pszData; + char *pszDest = pszSrc; + char *pszEnd = pszSrc + iLength; + + winDebug("DOXtoUNIX() - Original data:'%s'\n", pszData); /* Loop until the last character */ - while (pszSrc < pszEnd) - { - /* Copy the current source character to current destination character */ - *pszDest = *pszSrc; + while (pszSrc < pszEnd) { + /* Copy the current source character to current destination character */ + *pszDest = *pszSrc; - /* Advance to the next source character */ - 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++; - } + /* 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'; -} + winDebug("DOStoUNIX() - Final string:'%s'\n", pszData); +} /* * Convert \n to \r\n */ void -UNIXtoDOS (unsigned char **ppszData, int iLength) +UNIXtoDOS (char **ppszData, int iLength) { - int iNewlineCount = 0; - unsigned char *pszSrc = *ppszData; - unsigned char *pszEnd = pszSrc + iLength; - unsigned char *pszDest = NULL, *pszDestBegin = NULL; + int iNewlineCount = 0; + char *pszSrc = *ppszData; + char *pszEnd = pszSrc + iLength; + char *pszDest = NULL, *pszDestBegin = NULL; -#if 0 - printf ("UNIXtoDOS () - Original data:\n%s\n", *ppszData); -#endif + 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++; + 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) + if (iNewlineCount == 0) { + winDebug("UNIXtoDOS () - no conversion necessary\n"); return; + } /* Allocate a new string */ - pszDestBegin = pszDest = malloc (iLength + iNewlineCount + 1); + 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 */ + while (pszSrc < pszEnd) { + /* Copy line endings that are already valid */ + if (*pszSrc == '\r' && pszSrc + 1 < pszEnd && *(pszSrc + 1) == '\n') { *pszDest = *pszSrc; - pszSrc++; - pszDest++; + *(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); + free(*ppszData); *ppszData = pszDestBegin; -#if 0 - printf ("UNIXtoDOS () - Final string:\n%s\n", pszDestBegin); -#endif + winDebug("UNIXtoDOS () - Final string:'%s'\n", pszDestBegin); } @@ -1,5 +1,3 @@ -#if !defined(TEXTCONV_H) -#define TEXTCONV_H 1 /* *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. * @@ -30,6 +28,8 @@ * Authors: Harold L Hunt II */ +#if !defined(TEXTCONV_H) +#define TEXTCONV_H 1 /* * Function prototypes @@ -39,6 +39,6 @@ void DOStoUNIX (char *pszData, int iLength); void -UNIXtoDOS (unsigned char **ppszData, int iLength); +UNIXtoDOS (char **ppszData, int iLength); #endif @@ -1,5 +1,7 @@ /* *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 @@ -15,72 +17,547 @@ *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 XFREE86 PROJECT BE LIABLE FOR + *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 XFree86 Project - *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 XFree86 Project. + *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_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <sys/time.h> + +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/Xwindows.h> + #include "wndproc.h" +#include "xevents.h" +#include "debug.h" + +/* + * Constants + */ + +#define WIN_POLL_TIMEOUT 1 + +#define WM_WM_REINIT (WM_USER + 1) + +/* + * Process X events up to specified timeout + */ + +static int +ProcessXEventsTimeout(HWND hwnd, int iWindow, Display * pDisplay, + Bool fUseUnicode, int iTimeoutSec) +{ + int iConnNumber; + struct timeval tv; + int iReturn; + DWORD dwStopTime = GetTickCount() + iTimeoutSec * 1000; + + winDebug("ProcessXEventsTimeout () - pumping X events for %d seconds\n", + iTimeoutSec); + + /* Get our connection number */ + iConnNumber = XConnectionNumber(pDisplay); + + /* Loop for X events */ + while (1) { + fd_set fdsRead; + long remainingTime; + + /* We need to ensure that all pending events are processed */ + XSync(pDisplay, FALSE); + + /* 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("ProcessXEventsTimeout () - %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) { + winError("ProcessXEventsTimeout - Call to select () failed: %d. " + "Bailing.\n", iReturn); + 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 = FlushXEvents(hwnd, + XInternAtom(pDisplay, "CYGX_CUT_BUFFER", False), + XInternAtom(pDisplay, "UTF8_STRING", False), + XInternAtom(pDisplay, "COMPOUND_TEXT", False), + XInternAtom(pDisplay, "TARGETS", False), + iWindow, pDisplay, fUseUnicode); + + winDebug + ("ProcessXEventsTimeout () - FlushXEvents returned %d\n", iReturn); + + if (WIN_XEVENTS_NOTIFY == iReturn) { + /* Bail out if notify processed */ + return iReturn; + } + } + else { + winDebug("ProcessXEventsTimeout - Spurious wake\n"); + } + } + return WIN_XEVENTS_SUCCESS; +} /* * Process a given Windows message */ LRESULT CALLBACK -WindowProc (HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam) +WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { + static HWND s_hwndNextViewer; + static Bool s_fCBCInitialized; + static Display *pDisplay; + static Window iWindow; + /* Branch on message type */ - switch (message) + switch (message) { + case WM_DESTROY: { - case WM_DESTROY: - PostQuitMessage (0); - return 0; + winDebug("WindowProc - WM_DESTROY\n"); - case WM_CREATE: -#if 0 - printf ("WindowProc - WM_CREATE\n"); -#endif + /* Remove ourselves from the clipboard chain */ + ChangeClipboardChain(hwnd, s_hwndNextViewer); + + s_hwndNextViewer = NULL; + + PostQuitMessage(0); + } + return 0; + + case WM_CREATE: + { + HWND first, next; + DWORD error_code = 0; + + winDebug("WindowProc - WM_CREATE\n"); + + WindowCreationParams *wcp = (WindowCreationParams *)((CREATESTRUCT *)lParam)->lpCreateParams; + pDisplay = wcp->pClipboardDisplay; + iWindow = wcp->iClipboardWindow; + + first = GetClipboardViewer(); /* Get handle to first viewer in chain. */ + if (first == hwnd) + return 0; /* Make sure it's not us! */ + + /* Add ourselves to the clipboard viewer chain */ + next = SetClipboardViewer(hwnd); + error_code = GetLastError(); + if (SUCCEEDED(error_code) && (next == first)) /* SetClipboardViewer must have succeeded, and the handle */ + s_hwndNextViewer = next; /* it returned must have been the first window in the chain */ + else + s_fCBCInitialized = FALSE; + } + return 0; + + case WM_CHANGECBCHAIN: + { + winDebug("WindowProc - 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) { + s_hwndNextViewer = NULL; + winError("WindowProc - WM_CHANGECBCHAIN: " + "attempted to set next window to ourselves."); + } + } + else if (s_hwndNextViewer) + SendMessage(s_hwndNextViewer, message, wParam, lParam); + + } + winDebug("WindowProc - 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; + + winDebug("WindowProc - WM_WM_REINIT: Enter\n"); + + first = GetClipboardViewer(); /* Get handle to first viewer in chain. */ + if (first == hwnd) + return 0; /* Make sure it's not us! */ + winDebug(" WM_WM_REINIT: Replacing us(%x) with %x at head " + "of chain\n", hwnd, s_hwndNextViewer); + s_fCBCInitialized = FALSE; + ChangeClipboardChain(hwnd, s_hwndNextViewer); + s_hwndNextViewer = NULL; + s_fCBCInitialized = FALSE; + winDebug(" WM_WM_REINIT: Putting us back at head of chain.\n"); + first = GetClipboardViewer(); /* Get handle to first viewer in chain. */ + if (first == hwnd) + return 0; /* Make sure it's not us! */ + next = SetClipboardViewer(hwnd); + error_code = GetLastError(); + if (SUCCEEDED(error_code) && (next == first)) /* SetClipboardViewer must have succeeded, and the handle */ + s_hwndNextViewer = next; /* it returned must have been the first window in the chain */ + else + s_fCBCInitialized = FALSE; + } + winDebug("WindowProc - WM_WM_REINIT: Exit\n"); + return 0; + + case WM_DRAWCLIPBOARD: + { + static Atom atomClipboard; + static Bool s_fProcessingDrawClipboard = FALSE; + int iReturn; + + winDebug("WindowProc - WM_DRAWCLIPBOARD: Enter\n"); + + 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 */ + s_fCBCInitialized = FALSE; + ChangeClipboardChain(hwnd, s_hwndNextViewer); + PostMessage(hwnd, WM_WM_REINIT, 0, 0); + winError("WindowProc - WM_DRAWCLIPBOARD - " + "Nested calls detected. Re-initing.\n"); + winDebug("WindowProc - WM_DRAWCLIPBOARD: Exit\n"); + s_fProcessingDrawClipboard = FALSE; + return 0; + } + + /* Bail on first message */ + if (!s_fCBCInitialized) { + s_fCBCInitialized = TRUE; + s_fProcessingDrawClipboard = FALSE; + winDebug("WindowProc - WM_DRAWCLIPBOARD: Exit\n"); + return 0; + } + + /* + * NOTE: We cannot bail out when NULL == GetClipboardOwner () + * because some applications deal with the clipboard in a manner + * that causes the clipboard owner to be NULL when they are in + * fact taking ownership. One example of this is the Win32 + * native compile of emacs. + */ + + /* Bail when we still own the clipboard */ + if (hwnd == GetClipboardOwner()) { + + winDebug("WindowProc - WM_DRAWCLIPBOARD - " + "We own the clipboard, returning.\n"); + winDebug("WindowProc - WM_DRAWCLIPBOARD: Exit\n"); + s_fProcessingDrawClipboard = FALSE; + if (s_hwndNextViewer) + SendMessage(s_hwndNextViewer, message, wParam, lParam); + 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("WindowProc - WM_DRAWCLIPBOARD - " + "Clipboard does not contain CF_TEXT nor " + "CF_UNICODETEXT.\n"); + + winDebug("WindowProc: %d formats\n", + CountClipboardFormats()); + + if (OpenClipboard(hwnd)) + { + unsigned int format = 0; + + do { + format = EnumClipboardFormats(format); + if (GetLastError() != ERROR_SUCCESS) { + winDebug + ("WindowProc: EnumClipboardFormats failed %x\n", + GetLastError()); + } + if (format > 0xc000) { + char buff[256]; + + GetClipboardFormatName(format, buff, 256); + winDebug("WindowProc: %d %s\n", format, + buff); + } + else if (format > 0) + winDebug("WindowProc: %d\n", format); + } while (format != 0); + CloseClipboard(); + } + else + { + winDebug("WindowProc: could not open clipboard to enumerate formats\n"); + } + + /* + * We need to make sure that the X Server has processed + * previous XSetSelectionOwner messages. + */ + XSync(pDisplay, FALSE); + winDebug("WindowProc - XSync done.\n"); + + /* Release PRIMARY selection if owned */ + iReturn = XGetSelectionOwner(pDisplay, XA_PRIMARY); + if (iReturn == iWindow) { + winDebug("WindowProc - WM_DRAWCLIPBOARD - " + "PRIMARY selection is owned by us, releasing\n"); + XSetSelectionOwner(pDisplay, XA_PRIMARY, None, CurrentTime); + } + else if (BadWindow == iReturn || BadAtom == iReturn) + winError("WindowProc - WM_DRAWCLIPBOARD - " + "XGetSelectionOwner failed for PRIMARY: %d\n", + iReturn); + + /* Release CLIPBOARD selection if owned */ + iReturn = XGetSelectionOwner(pDisplay, atomClipboard); + if (iReturn == iWindow) { + winDebug("WindowProc - WM_DRAWCLIPBOARD - " + "CLIPBOARD selection is owned by us, releasing\n"); + XSetSelectionOwner(pDisplay, atomClipboard, None, CurrentTime); + } + else if (BadWindow == iReturn || BadAtom == iReturn) + winError("WindowProc - WM_DRAWCLIPBOARD - " + "XGetSelectionOwner failed for CLIPBOARD: %d\n", + iReturn); + + winDebug("WindowProc - WM_DRAWCLIPBOARD: Exit\n"); + s_fProcessingDrawClipboard = FALSE; + if (s_hwndNextViewer) + SendMessage(s_hwndNextViewer, message, wParam, lParam); + return 0; + } + + /* Reassert ownership of PRIMARY */ + iReturn = XSetSelectionOwner(pDisplay, + XA_PRIMARY, iWindow, CurrentTime); + if (iReturn == BadAtom || iReturn == BadWindow || + XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) { + winError("WindowProc - WM_DRAWCLIPBOARD - " + "Could not reassert ownership of PRIMARY\n"); + } + else { + winDebug("WindowProc - 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) { + winError("WindowProc - WM_DRAWCLIPBOARD - " + "Could not reassert ownership of CLIPBOARD\n"); + } + else { + winDebug("WindowProc - WM_DRAWCLIPBOARD - " + "Reasserted ownership of CLIPBOARD\n"); + } + + /* Flush the pending SetSelectionOwner event now */ + XFlush(pDisplay); + + s_fProcessingDrawClipboard = FALSE; + } + winDebug("WindowProc - 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("WindowProc - WM_DESTROYCLIPBOARD - Ignored.\n"); + return 0; + + case WM_RENDERFORMAT: + case WM_RENDERALLFORMATS: + { + int iReturn; + Bool fConvertToUnicode; + + if (message == WM_RENDERALLFORMATS) + winDebug("WindowProc - WM_RENDERALLFORMATS - Hello.\n"); + else + winDebug("WindowProc - WM_RENDERFORMAT %d - Hello.\n", + wParam); + + /* 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, + GetLastOwnedSelectionAtom(), + XInternAtom(pDisplay, "COMPOUND_TEXT", False), + XInternAtom(pDisplay, "CYGX_CUT_BUFFER", False), + iWindow, CurrentTime); + if (iReturn == BadAtom || iReturn == BadWindow) { + winError("WindowProc - WM_RENDER*FORMAT - " + "XConvertSelection () failed\n"); + break; + } + + /* Special handling for WM_RENDERALLFORMATS */ + if (message == WM_RENDERALLFORMATS) { + /* We must open and empty the clipboard */ + + /* Close clipboard if we have it open already */ + if (GetOpenClipboardWindow() == hwnd) { + CloseClipboard(); + } + + if (!OpenClipboard(hwnd)) { + winError("WindowProc - WM_RENDER*FORMATS - " + "OpenClipboard () failed: %08x\n", + GetLastError()); + break; + } + + if (!EmptyClipboard()) { + winError("WindowProc - WM_RENDER*FORMATS - " + "EmptyClipboard () failed: %08x\n", + GetLastError()); + break; + } + } + + /* Process the SelectionNotify event */ + iReturn = ProcessXEventsTimeout(hwnd, + iWindow, + pDisplay, + fConvertToUnicode, WIN_POLL_TIMEOUT); + + /* + * The last call to ProcessXEventsTimeout + * 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) { + /* Paste no data, to satisfy required call to SetClipboardData */ + SetClipboardData(CF_UNICODETEXT, NULL); + SetClipboardData(CF_TEXT, NULL); + + winError("WindowProc - timed out waiting for WIN_XEVENTS_NOTIFY\n"); + } + + /* Special handling for WM_RENDERALLFORMATS */ + if (message == WM_RENDERALLFORMATS) { + /* We must close the clipboard */ + + if (!CloseClipboard()) { + winError("WindowProc - WM_RENDERALLFORMATS - " + "CloseClipboard () failed: %08x\n", + GetLastError()); + break; + } + } + + winDebug("WindowProc - WM_RENDER*FORMAT - Returning.\n"); return 0; } + } /* Let Windows perform default processing for unhandled messages */ - return DefWindowProc (hwnd, message, wParam, lParam); + return DefWindowProc(hwnd, message, wParam, lParam); } - /* * Process any pending Windows messages */ -BOOL -FlushWindowsMessageQueue (HWND hwnd) +WINBOOL +FlushWindowsMessageQueue(HWND hwnd) { - MSG msg; + 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); - } - + 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; } - @@ -1,5 +1,3 @@ -#if !defined (WNDPROC_H) -#define WNDPROC_H 1 /* *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. * @@ -30,32 +28,27 @@ * Authors: Harold L Hunt II */ -/* Fixups to prevent collisions between Windows and X headers */ -#undef MINSHORT -#undef MAXSHORT - -/* Flags for Windows header options */ -#define NONAMELESSUNION -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif +#if !defined (WNDPROC_H) +#define WNDPROC_H 1 /* Windows headers */ -#include <windows.h> -#include <windowsx.h> - +#include <X11/Xwindows.h> /* * Function prototypes */ -BOOL +WINBOOL FlushWindowsMessageQueue (HWND hwnd); LRESULT CALLBACK -WindowProc (HWND hwnd, UINT message, +WindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); -#endif - +typedef struct +{ + Display *pClipboardDisplay; + Window iClipboardWindow; +} WindowCreationParams; +#endif @@ -1,5 +1,7 @@ /* *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 @@ -15,730 +17,839 @@ *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 XFREE86 PROJECT BE LIABLE FOR + *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 XFree86 Project - *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 XFree86 Project. + *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_CONFIG_H +#include <config.h> +#endif -/* Standard library headers */ -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> - - -/* X headers */ #include <X11/Xlib.h> #include <X11/Xutil.h> -#include <X11/Xos.h> #include <X11/Xatom.h> -#include <X11/keysym.h> +#include <X11/extensions/Xfixes.h> + +/* Local headers */ +#include "xevents.h" +#include "textconv.h" +#include "debug.h" +/* + * Constants + */ -/* Fixups to prevent collisions between Windows and X headers */ -#undef MINSHORT -#undef MAXSHORT +#define CLIP_NUM_SELECTIONS 2 +#define CLIP_OWN_NONE -1 +#define CLIP_OWN_PRIMARY 0 +#define CLIP_OWN_CLIPBOARD 1 -/* Flags for Windows header options */ -#define NONAMELESSUNION -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif +/* + * Global variables + */ -/* Windows headers */ -#include <windows.h> -#include <windowsx.h> +extern int xfixes_event_base; +/* + * Local variables + */ -/* Application constants */ -#define WINDOW_CLASS "xwinclip" -#define WINDOW_TITLE "xwinclip" -#define WIN_MSG_QUEUE_FNAME "/dev/windows" -#define WIN_USE_SELECT 1 +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 Atom atomClipboard = None; -/* Local headers */ -#include "xevents.h" -#include "textconv.h" +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 +GetLastOwnedSelectionAtom(void) +{ + if (lastOwnedSelectionIndex == CLIP_OWN_NONE) + return None; + + if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY) + return XA_PRIMARY; -extern Atom atomClipboard; + if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD) + return atomClipboard; + return None; +} /* * Process any pending X events */ -Bool +int FlushXEvents (HWND hwnd, Atom atomLocalProperty, Atom atomUTF8String, - Atom atomCompoundText, Atom atomTargets, Atom atomDeleteWindow, + Atom atomCompoundText, Atom atomTargets, int iWindow, Display *pDisplay, - Bool fUnicodeSupport) + Bool fUseUnicode) { -#if 0 - Atom atomReturnType; - int iReturnFormat; - unsigned long ulReturnItems; -#endif - XTextProperty xtpText; - XEvent event; - XSelectionEvent eventSelection; - unsigned long ulReturnBytesLeft; - unsigned char *pszReturnData = NULL; - char *pszGlobalData = NULL; - int iReturn; - HGLOBAL hGlobal; - Bool fReturn = TRUE; - XICCEncodingStyle xiccesStyle; - int iConvertDataLen = 0; - char *pszConvertData = NULL; - char *pszTextList[2]; - int iCount; - char **ppszTextList = NULL; - wchar_t *pwszUnicodeStr = NULL; - int iUnicodeLen = 0; - int iReturnDataLen = 0; - int i; + atomClipboard = XInternAtom (pDisplay, "CLIPBOARD", False); /* Process all pending events */ - while (XPending (pDisplay)) - { - /* Get the next event - will not block because one is ready */ - XNextEvent (pDisplay, &event); - - /* Branch on the event type */ - switch (event.type) - { - case ClientMessage: - if (event.xclient.data.l[0] == atomDeleteWindow) - { - printf ("\nReceived WM_DELETE_WINDOW\n\n"); - fReturn = FALSE; - } - else - printf ("\nUnknown ClientMessage\n\n"); - break; - - case SelectionClear: - /* Request the lost selection contents */ - iReturn = XConvertSelection (pDisplay, - event.xselectionclear.selection, - atomCompoundText, - atomLocalProperty, - iWindow, - CurrentTime); - if (iReturn == BadAtom || iReturn == BadWindow) - { - printf ("SelectionClear - XConvertSelection () failed\n"); - exit (1); - } - break; - - - /* - * SelectionRequest - */ - - case SelectionRequest: -#if 0 - printf ("SelectionRequest - target %d\n", - event.xselectionrequest.target); - printf ("SelectionRequest - Target atom name %s\n", - XGetAtomName (pDisplay, event.xselectionrequest.target)); + 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; + Bool fAbort = FALSE; + Bool fCloseClipboard = FALSE; + Bool fSetClipboardData = TRUE; + + /* Get the next event - will not block because one is ready */ + XNextEvent(pDisplay, &event); + + /* Branch on the event type */ + switch (event.type) { + /* + * SelectionRequest + */ + + case SelectionRequest: + { + 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; + } + + /* 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 FlushXEvents_SelectionRequest_Done; + } + + /* Handle targets type of request */ + if (event.xselectionrequest.target == atomTargets) { + Atom atomTargetArr[] = { atomTargets, + atomCompoundText, + atomUTF8String, + XA_STRING + }; + winDebug("SelectionRequest - populating targets\n"); + + /* 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) { + winError("FlushXEvents - 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) { + winError("FlushXEvents - SelectionRequest - " + "XSendEvent () failed\n"); + } + break; + } + + /* Close clipboard if we have it open already */ + if (GetOpenClipboardWindow() == hwnd) { + CloseClipboard(); + } + + /* Access the clipboard */ + if (!OpenClipboard(hwnd)) { + winError("FlushXEvents - SelectionRequest - " + "OpenClipboard () failed: %08lx\n", GetLastError()); + + /* Abort */ + fAbort = TRUE; + goto FlushXEvents_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) + winError("FlushXEvents - CF_UNICODETEXT is not " + "available from Win32 clipboard. Aborting %d.\n", + count); + lasthwnd = hwnd; + + /* Abort */ + fAbort = TRUE; + goto FlushXEvents_SelectionRequest_Done; + } + else if (!fUseUnicode && !IsClipboardFormatAvailable(CF_TEXT)) { + winError("FlushXEvents - CF_TEXT is not " + "available from Win32 clipboard. Aborting.\n"); + + /* Abort */ + fAbort = TRUE; + goto FlushXEvents_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 - - /* Abort if invalid target type */ - if (event.xselectionrequest.target != XA_STRING - && event.xselectionrequest.target != atomUTF8String - && event.xselectionrequest.target != atomCompoundText - && event.xselectionrequest.target != atomTargets) - { - /* 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) - { - printf ("XSendEvent () failed\n"); - exit (1); - } - - break; - } - - /* Handle targets type of request */ - if (event.xselectionrequest.target == atomTargets) - { - Atom atomTargetArr[4] = {atomTargets, - atomCompoundText, - atomUTF8String, - XA_STRING}; - - /* Try to change the property */ - iReturn = XChangeProperty (pDisplay, - event.xselectionrequest.requestor, - event.xselectionrequest.property, - event.xselectionrequest.target, - 8, - PropModeReplace, - (char *) atomTargetArr, - sizeof (atomTargetArr)); - if (iReturn == BadAlloc - || iReturn == BadAtom - || iReturn == BadMatch - || iReturn == BadValue - || iReturn == BadWindow) - { - printf ("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) - { - printf ("XSendEvent () failed\n"); - } - break; - } - - /* Access the clipboard */ - if (!OpenClipboard (hwnd)) - { - printf ("OpenClipboard () failed: %08x\n", - (unsigned int) GetLastError ()); - exit (1); - } - - /* Setup the string style */ - if (event.xselectionrequest.target == XA_STRING) - xiccesStyle = XStringStyle; - else if (event.xselectionrequest.target == atomUTF8String) - xiccesStyle = XUTF8StringStyle; - else if (event.xselectionrequest.target == atomCompoundText) - xiccesStyle = XCompoundTextStyle; - else - xiccesStyle = XStringStyle; - - /* - * FIXME: Can't pass CF_UNICODETEXT on Windows 95/98/Me - */ - - /* Get a pointer to the clipboard text */ - if (fUnicodeSupport) - hGlobal = GetClipboardData (CF_UNICODETEXT); - else - hGlobal = GetClipboardData (CF_TEXT); - if (!hGlobal) - { - printf ("GetClipboardData () failed: %08x\n", - (unsigned int) GetLastError ()); - exit (1); - } - pszGlobalData = (char *) GlobalLock (hGlobal); - - /* Convert the Unicode string to UTF8 (MBCS) */ - if (fUnicodeSupport) - { - iConvertDataLen = WideCharToMultiByte (CP_UTF8, - 0, - (LPCWSTR)pszGlobalData, - -1, - NULL, - 0, - NULL, - NULL); - pszConvertData = (char *) malloc (iConvertDataLen); /* Don't need +1 */ - 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 */ - DOStoUNIX (pszConvertData, strlen (pszConvertData)); - - /* Setup our text list */ - pszTextList[0] = pszConvertData; - pszTextList[1] = NULL; - - /* Initialize the text property */ - xtpText.value = NULL; - - /* Create the text property from the text list */ - if (fUnicodeSupport) - { - iReturn = Xutf8TextListToTextProperty (pDisplay, - pszTextList, - 1, - xiccesStyle, - &xtpText); - } - else - { - iReturn = XmbTextListToTextProperty (pDisplay, - pszTextList, - 1, - xiccesStyle, - &xtpText); - } - if (iReturn == XNoMemory || iReturn == XLocaleNotSupported) - { - printf ("SelectionRequest - X*TextListToTextProperty " - "failed: %d\n", - iReturn); - exit(1); - } - - /* Free the converted string */ - free (pszConvertData); - - /* - * FIXME: Pass pszGlobalData and strlen (pszGlobalData( - * on 1 byte, pass xtpText.value and xtpText.nitems - * on 2 byte. - */ - - /* 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) - { - printf ("SelectionRequest - XChangeProperty failed: %d\n", - iReturn); - exit (1); - } - - /* Release the clipboard data */ - GlobalUnlock (hGlobal); - pszGlobalData = NULL; - CloseClipboard (); - - /* FIXME: Don't clean up on 1 byte. */ - XFree (xtpText.value); - xtpText.value = NULL; - - /* 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) - { - printf ("XSendEvent () failed\n"); - exit (1); - } - break; - - - /* - * SelectionNotify - */ - - case SelectionNotify: -#if 0 - printf ("SelectionNotify\n"); -#endif - -#if 0 - /* - * TEMP: Bail if selection is anything other than CLIPBOARD - */ - - if (event.xselection.selection != atomClipboard) - break; -#endif - - /* - * - * What are we doing here? - * - */ - if (event.xselection.property == None) - { - if(event.xselection.target == XA_STRING) - { -#if 0 - printf ("SelectionNotify XA_STRING\n"); -#endif - return fReturn; - } - else if (event.xselection.target == atomUTF8String) - { - printf ("SelectionNotify UTF8\n"); - iReturn = XConvertSelection (pDisplay, - event.xselection.selection, - XA_STRING, - atomLocalProperty, - iWindow, - CurrentTime); - if (iReturn == BadAtom || iReturn == BadWindow) - { - printf ("SelectionNotify - XConvertSelection () " - "failed\n"); - exit (1); - } - return fReturn; - } - else if (event.xselection.target == atomCompoundText) - { - printf ("SelectionNotify CompoundText\n"); - iReturn = XConvertSelection (pDisplay, - event.xselection.selection, - atomUTF8String, - atomLocalProperty, - iWindow, - CurrentTime); - if (iReturn == BadAtom || iReturn == BadWindow) - { - printf ("SelectionNotify - XConvertSelection () " - "failed\n"); - exit (1); - } - return fReturn; - } - else - { - printf("Unknown format\n"); - return fReturn; - } - } - - /* 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) - { - printf ("SelectionNotify - XGetWindowProperty () failed\n"); - exit (1); - } - -#if 0 - printf ("SelectionNotify - returned data %d left %d\n", - xtpText.nitems, ulReturnBytesLeft); + 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) { + winError("FlushXEvents - SelectionRequest - " + "GetClipboardData () failed: %08lx\n", GetLastError()); + + /* Abort */ + fAbort = TRUE; + goto FlushXEvents_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 = (char *) 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 */ + DOStoUNIX(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 - - /* 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) - { - printf ("SelectionNotify - XGetWindowProperty () failed\n"); - exit (1); - } - -#if 0 - { - char *pszAtomName = NULL; - - printf ("SelectionNotify - returned data %d left %d\n", - prop.nitems, ulReturnBytesLeft); - - pszAtomName = XGetAtomName(pDisplay, xtpText.encoding); - ErrorF ("Notify atom name %s\n", pszAtomName); - XFree (pszAtomName); - pszAtomName = NULL; - } + } + else { + iReturn = XmbTextListToTextProperty(pDisplay, + pszTextList, + 1, xiccesStyle, &xtpText); + } + if (iReturn == XNoMemory || iReturn == XLocaleNotSupported) { + winError("FlushXEvents - SelectionRequest - " + "X*TextListToTextProperty failed: %d\n", iReturn); + + /* Abort */ + fAbort = TRUE; + goto FlushXEvents_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) { + winError("FlushXEvents - SelectionRequest - " + "XChangeProperty failed: %d\n", iReturn); + + /* Abort */ + fAbort = TRUE; + goto FlushXEvents_SelectionRequest_Done; + } + + /* Release the clipboard data */ + GlobalUnlock(hGlobal); + pszGlobalData = NULL; + 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) { + winError("FlushXEvents - SelectionRequest - " + "XSendEvent () failed\n"); + + /* Abort */ + fAbort = TRUE; + goto FlushXEvents_SelectionRequest_Done; + } + + FlushXEvents_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) { + winDebug("SelectionRequest - aborting\n"); + /* 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. + */ + winError("FlushXEvents - SelectionRequest - " + "XSendEvent () failed for abort event.\n"); + } + } + + /* Close clipboard if it was opened */ + if (fCloseClipboard) { + fCloseClipboard = FALSE; + CloseClipboard(); + } + break; + + /* + * SelectionNotify + */ + + case SelectionNotify: + + winDebug("FlushXEvents - SelectionNotify\n"); + { + char *pszAtomName; + + pszAtomName = XGetAtomName(pDisplay, + event.xselection.selection); + + winDebug + ("FlushXEvents - SelectionNotify - ATOM: %s\n", + pszAtomName); + XFree(pszAtomName); + } + + /* + * Request conversion of UTF8 and CompoundText targets. + */ + if (event.xselection.property == None) { + if (event.xselection.target == XA_STRING) { + winDebug("FlushXEvents - SelectionNotify - " + "XA_STRING\n"); + + return WIN_XEVENTS_CONVERT; + } + else if (event.xselection.target == atomUTF8String) { + winDebug("FlushXEvents - 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("FlushXEvents - 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 - - /* Convert the text property to a text list */ - if (fUnicodeSupport) - { - iReturn = Xutf8TextPropertyToTextList (pDisplay, - &xtpText, - &ppszTextList, - &iCount); - } - else - { - iReturn = XmbTextPropertyToTextList (pDisplay, - &xtpText, - &ppszTextList, - &iCount); - } - if (iReturn == Success || iReturn > 0) - { - /* Conversion succeeded or some unconvertible characters */ - if (ppszTextList != NULL) - { - for (i = 0; i < iCount; i++) - { - iReturnDataLen += strlen(ppszTextList[i]); - } - pszReturnData = malloc (iReturnDataLen + 1); - pszReturnData[0] = '\0'; - for (i = 0; i < iCount; i++) - { - strcat (pszReturnData, ppszTextList[i]); - } - } - else - { - printf ("winClipboardFlushXEvents - SelectionNotify - " - "X*TextPropertyToTextList list_return is NULL\n"); - pszReturnData = malloc (1); - pszReturnData[0] = '\0'; - } - } - else - { - switch (iReturn) - { - case XNoMemory: - printf ("winClipboardFlushXEvents - SelectionNotify - XNoMemory\n"); - break; - case XConverterNotFound: - printf ("winClipboardFlushXEvents - SelectionNotify - XConverterNotFound\n"); - break; - default: - printf ("winClipboardFlushXEvents - SelectionNotify - Unknown Error\n"); - break; - } - pszReturnData = malloc (1); - pszReturnData[0] = '\0'; - } - - /* Free the data returned from XGetWindowProperty */ - XFreeStringList (ppszTextList); - XFree (xtpText.value); - - /* Convert the X clipboard string to DOS format */ - UNIXtoDOS (&pszReturnData, strlen (pszReturnData)); - - if (fUnicodeSupport) - { - /* 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 - = (wchar_t*) malloc (sizeof (wchar_t) * (iUnicodeLen + 1)); - - /* Do the actual conversion */ - MultiByteToWideChar (CP_UTF8, - 0, - pszReturnData, - -1, - pwszUnicodeStr, - iUnicodeLen); - } - else - { - pszConvertData = strdup (pszReturnData); - iConvertDataLen = strlen (pszConvertData) + 1; - } - - /* Access the Windows clipboard */ - if (!OpenClipboard (hwnd)) - { - printf ("OpenClipboard () failed: %08x\n", - (unsigned int) GetLastError ()); - exit (1); - } - - /* Take ownership of the Window clipboard */ - if (!EmptyClipboard ()) - { - printf ("EmptyClipboard () failed: %08x\n", - (unsigned int) GetLastError ()); - exit (1); - } - - /* Allocate global memory for the X clipboard data */ - if (fUnicodeSupport) - hGlobal = GlobalAlloc (GMEM_MOVEABLE, - sizeof (wchar_t) * (iUnicodeLen + 1)); - else - hGlobal = GlobalAlloc (GMEM_MOVEABLE, iConvertDataLen); - - /* Obtain a pointer to the global memory */ - pszGlobalData = GlobalLock (hGlobal); - if (pszGlobalData == NULL) - { - printf ("Could not lock global memory for clipboard transfer\n"); - exit (1); - } - - /* Copy the returned string into the global memory */ - if (fUnicodeSupport) - memcpy (pszGlobalData, - pwszUnicodeStr, - sizeof (wchar_t) * (iUnicodeLen + 1)); - else - strcpy (pszGlobalData, pszConvertData); - - /* Free the data returned from XGetWindowProperty */ - if (fUnicodeSupport) - { - free (pwszUnicodeStr); - pwszUnicodeStr = NULL; - } - else - { - free (pszConvertData); - pszConvertData = NULL; - } - - /* Release the pointer to the global memory */ - GlobalUnlock (hGlobal); - pszGlobalData = NULL; - - /* Push the selection data to the Windows clipboard */ - if (fUnicodeSupport) - SetClipboardData (CF_UNICODETEXT, hGlobal); - else - SetClipboardData (CF_TEXT, hGlobal); - - /* - * NOTE: Do not try to free pszGlobalData, it is owned by - * Windows after the call to SetClipboardData (). - */ - - /* Release the clipboard */ - if (!CloseClipboard ()) - { - printf ("CloseClipboard () failed: %08x\n", - (unsigned int) GetLastError ()); - exit (1); - } - - /* Reassert ownership of the selection */ - iReturn = XSetSelectionOwner (pDisplay, - event.xselection.selection, - iWindow, CurrentTime); - if (iReturn == BadAtom || iReturn == BadWindow) - { - printf ("SelectionNotify - Could not reassert ownership " - "of selection ATOM: %s\n", - XGetAtomName (pDisplay, - event.xselection.selection)); - exit (1); - } - else - { - printf ("SelectionNotify - Reasserted ownership of ATOM: %s\n", - XGetAtomName (pDisplay, - event.xselection.selection)); - } -#if 0 - /* Reassert ownership of the CLIPBOARD */ - iReturn = XSetSelectionOwner (pDisplay, - atomClipboard, - iWindow, CurrentTime); - if (iReturn == BadAtom || iReturn == BadWindow) - { - printf ("Could not reassert ownership of selection\n"); - exit (1); - } + else { + winError("FlushXEvents - SelectionNotify - " + "Unknown format. Cannot request conversion, " + "aborting.\n"); + break; + } + } + + case SelectionClear: + winDebug("SelectionClear - doing nothing\n"); + break; + + case PropertyNotify: + { + char *pszAtomName; + + pszAtomName = XGetAtomName(pDisplay, event.xproperty.atom); + winDebug("FlushXEvents - PropertyNotify - ATOM: %s\n", + pszAtomName); + XFree(pszAtomName); + } + + if (event.xproperty.atom != atomLocalProperty) + 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) { + winError("FlushXEvents - PropertyNotify - " + "XGetWindowProperty () failed, aborting: %d\n", iReturn); + break; + } + + winDebug("PropertyNotify - 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) { + winError("FlushXEvents - PropertyNotify - " + "XGetWindowProperty () failed, aborting: %d\n", iReturn); + break; + } + + { + char *pszAtomName = NULL; + + winDebug("PropertyNotify - returned data %d left %d\n", + xtpText.nitems, ulReturnBytesLeft); + pszAtomName = XGetAtomName(pDisplay, xtpText.encoding); + winDebug("PropertyNotify - encoding atom name %s\n", + pszAtomName); + XFree(pszAtomName); + pszAtomName = NULL; + } + + if (fUseUnicode) { +#ifdef X_HAVE_UTF8_STRING + /* Convert the text property to a text list */ + iReturn = Xutf8TextPropertyToTextList(pDisplay, + &xtpText, + &ppszTextList, &iCount); #endif - break; - -#if 0 - case CreateNotify: - printf ("FlushXEvents - CreateNotify parent: %ld\twindow: %ld\n", - event.xcreatewindow.parent, event.xcreatewindow.window); - break; - - case DestroyNotify: - printf ("FlushXEvents - DestroyNotify window: %ld\tevent: %ld\n", - event.xdestroywindow.window, event.xdestroywindow.event); - break; -#endif - - default: - break; - } + } + else { + iReturn = XmbTextPropertyToTextList(pDisplay, + &xtpText, + &ppszTextList, &iCount); + } + 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]); + } + pszReturnData = malloc(iReturnDataLen + 1); + pszReturnData[0] = '\0'; + for (i = 0; i < iCount; i++) { + strcat(pszReturnData, ppszTextList[i]); + } + } + else { + winError("FlushXEvents - PropertyNotify - " + "X*TextPropertyToTextList list_return is NULL.\n"); + pszReturnData = malloc(1); + pszReturnData[0] = '\0'; + } + } + else { + winError("FlushXEvents - PropertyNotify - " + "X*TextPropertyToTextList returned: "); + switch (iReturn) { + case XNoMemory: + winError("XNoMemory\n"); + break; + case XLocaleNotSupported: + winError("XLocaleNotSupported\n"); + break; + case XConverterNotFound: + winError("XConverterNotFound\n"); + break; + default: + winError("%d\n", iReturn); + break; + } + pszReturnData = 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 */ + UNIXtoDOS(&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 + = (wchar_t *) malloc(sizeof(wchar_t) * (iUnicodeLen + 1)); + if (!pwszUnicodeStr) { + winError("FlushXEvents - PropertyNotify " + "malloc failed for pwszUnicodeStr, aborting.\n"); + + /* Abort */ + fAbort = TRUE; + goto FlushXEvents_PropertyNotify_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) { + winError("FlushXEvents - PropertyNotify " + "GlobalAlloc failed, aborting: %ld\n", GetLastError()); + /* Abort */ + fAbort = TRUE; + goto FlushXEvents_PropertyNotify_Done; + } + + /* Obtain a pointer to the global memory */ + pszGlobalData = GlobalLock(hGlobal); + if (pszGlobalData == NULL) { + winError("FlushXEvents - Could not lock global " + "memory for clipboard transfer\n"); + + /* Abort */ + fAbort = TRUE; + goto FlushXEvents_PropertyNotify_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 (). + */ + + FlushXEvents_PropertyNotify_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; + + case MappingNotify: + break; + + default: + if (event.type == XFixesSetSelectionOwnerNotify + xfixes_event_base) + { + XFixesSelectionNotifyEvent *e = (XFixesSelectionNotifyEvent *)&event; + + winDebug("FlushXEvents - 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("winProcSetSelectionOwner - 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("winProcSetSelectionOwner - 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)) { + winError("winProcSetSelectionOwner - OpenClipboard () failed: %08x\n", (int) GetLastError()); + break; + } + + /* Take ownership of the Windows clipboard */ + if (!EmptyClipboard()) { + winError("winProcSetSelectionOwner - 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()) { + winError("winProcSetSelectionOwner - CloseClipboard () failed: %08x\n", (int) GetLastError()); + break; + } + } + /* XFixesSelectionWindowDestroyNotifyMask */ + /* XFixesSelectionClientCloseNotifyMask */ + else + { + winError("FlushXEvents - unexpected event type %d\n", event.type); + } + break; } + } - return fReturn; + return WIN_XEVENTS_SUCCESS; } @@ -1,5 +1,3 @@ -#if !defined (XEVENTS_H) -#define XEVENTS_H 1 /* *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. * @@ -30,15 +28,28 @@ * Authors: Harold L Hunt II */ +#if !defined (XEVENTS_H) +#define XEVENTS_H 1 + +#include <X11/Xlib.h> +#include <X11/Xwindows.h> + +#define WIN_XEVENTS_SUCCESS 0 +#define WIN_XEVENTS_SHUTDOWN 1 +#define WIN_XEVENTS_CONVERT 2 +#define WIN_XEVENTS_NOTIFY 3 /* * Function prototypes */ -Bool +int FlushXEvents (HWND hwnd, Atom atomLocalProperty, Atom atomUTF8String, - Atom atomCompoundText, Atom atomTargets, Atom atomDeleteWindow, + Atom atomCompoundText, Atom atomTargets, int iWindow, Display *pDisplay, - Bool fUnicodeSupport); + Bool fUseUnicode); + +Atom +GetLastOwnedSelectionAtom(void); #endif @@ -1,5 +1,7 @@ /* *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 @@ -15,126 +17,121 @@ *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 XFREE86 PROJECT BE LIABLE FOR + *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 XFree86 Project - *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 XFree86 Project. + *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_CONFIG_H +#include <config.h> +#endif /* Standard library headers */ #include <assert.h> #include <stdio.h> #include <stdlib.h> -#include <signal.h> +#include <fcntl.h> +#include <sys/param.h> +#include <unistd.h> +#ifndef HAS_WINSOCK #include <errno.h> +#endif +#include <setjmp.h> +#include <pthread.h> /* X headers */ #include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/Xos.h> #include <X11/Xatom.h> -#include <X11/keysym.h> #ifdef X_LOCALE #include <X11/Xlocale.h> #else /* X_LOCALE */ #include <locale.h> #endif /* X_LOCALE */ - - -/* Fixups to prevent collisions between Windows and X headers */ -#undef MINSHORT -#undef MAXSHORT - -/* Flags for Windows header options */ -#define NONAMELESSUNION -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif +#include <X11/extensions/Xfixes.h> /* Windows headers */ -#include <windows.h> -#include <windowsx.h> +#include <X11/Xwindows.h> -/* Other headers */ -#include <setjmp.h> +/* Local headers */ +#include "textconv.h" +#include "wndproc.h" +#include "xevents.h" +#include "debug.h" /* Application constants */ #define WINDOW_CLASS "xwinclip" #define WINDOW_TITLE "xwinclip" #define WIN_MSG_QUEUE_FNAME "/dev/windows" -#define WIN_USE_SELECT 1 + #define WIN_CONNECT_RETRIES 3 #define WIN_CONNECT_DELAY 4 -#define WIN_JMP_OKAY 0 -#define WIN_JMP_ERROR_IO 2 +/* + * Local variables + */ -/* Local headers */ -#include "textconv.h" -#include "wndproc.h" -#include "xevents.h" - +static jmp_buf g_jmpEntry; +static XIOErrorHandler g_ClipboardOldIOErrorHandler; +static pthread_t g_ClipboardProcThread; /* * Global variables */ -jmp_buf g_jmpEntry; -Bool g_fUnicodeClipboard = TRUE; - +int xfixes_event_base; +int xfixes_error_base; /* - * Function prototypes + * Local function prototypes */ -HWND -CreateMessagingWindow (); - -Bool -UnicodeSupport (); +static HWND +CreateMessagingWindow (Display *display, Window window); +void +ClipboardProc(Bool fUnicodeSupport, char *pszDisplay); /* - * Local functions + * ClipboardErrorHandler - Our application specific error handler */ - -#if 0 -void -handle_kill (int i) +static int +ClipboardErrorHandler(Display *pDisplay, XErrorEvent *pErr) { - printf ("\nhandle_kill!\n\n"); -} + char pszErrorMsg[100]; -int -error_handler (Display *pDisplay, XErrorEvent *pErrorEvent) -{ - printf ("\nerror_handler!\n\n"); + XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg)); + winError("ClipboardErrorHandler - ERROR: %s Serial: %lu, Request Code: %d, Minor Code: %d\n", + pszErrorMsg, pErr->serial, pErr->request_code, pErr->minor_code); return 0; } -#endif -int -error_handler_io (Display *pDisplay) +/* + * ClipboardIOErrorHandler - Our application specific IO error handler + */ +static int +ClipboardIOErrorHandler(Display *pDisplay) { - printf ("\nerror_handler_io!\n\n"); - - /* Restart at the main entry point */ - longjmp (g_jmpEntry, WIN_JMP_ERROR_IO); - - return 0; -} + winError("ClipboardIOErrorHandler!\n"); + if (pthread_equal(pthread_self(), g_ClipboardProcThread)) { + /* Restart at the main entry point */ + longjmp(g_jmpEntry, 2); + } -Atom atomClipboard, atomClipboardManager; + if (g_ClipboardOldIOErrorHandler) + g_ClipboardOldIOErrorHandler(pDisplay); + return 0; +} /* * Main function @@ -143,25 +140,9 @@ Atom atomClipboard, atomClipboardManager; int main (int argc, char *argv[]) { -#if 0 - Atom atomClipboard, atomClipboardManager; -#endif - Atom atomLocalProperty, atomCompoundText; - Atom atomUTF8String, atomTargets; - int iReturn; - HWND hwnd = NULL; - int iConnectionNumber; - int fdMessageQueue; - fd_set fdsRead; - int iMaxDescriptor; - Display *pDisplay; - Window iWindow; - Atom atomDeleteWindow; - Bool fReturn; - int iRetries; - Bool fUnicodeSupport; - char *pszDisplay = NULL; int i; + char *pszDisplay = NULL; + Bool fUnicodeClipboard = TRUE; /* Parse command-line parameters */ for (i = 1; i < argc; ++i) @@ -178,76 +159,92 @@ main (int argc, char *argv[]) i++; continue; } + /* Look for -nounicodeclipboard */ if (!strcmp (argv[i], "-nounicodeclipboard")) { - g_fUnicodeClipboard = FALSE; + fUnicodeClipboard = FALSE; continue; } - + /* Yack when we find a parameter that we don't know about */ printf ("Unknown parameter: %s\nExiting.\n", argv[i]); exit (1); } - /* Set jump point for IO Error exits */ - iReturn = setjmp (g_jmpEntry); - - /* Check if we should continue operations */ - if (iReturn != WIN_JMP_ERROR_IO - && iReturn != WIN_JMP_OKAY) + /* Do we have Unicode support? */ + if (fUnicodeClipboard) { - /* setjmp returned an unknown value, exit */ - printf ("setjmp returned: %d exiting\n", - iReturn); - exit (1); + printf ("Unicode clipboard I/O\n"); } - else if (iReturn == WIN_JMP_ERROR_IO) + else { - printf ("setjmp returned and hwnd: %08x\n", (unsigned int)hwnd); + printf ("Non Unicode clipboard I/O\n"); } - /* Initialize retry count */ - iRetries = 0; - - /* Do we have Unicode support? */ - fUnicodeSupport = g_fUnicodeClipboard && UnicodeSupport (); - if (fUnicodeSupport) + /* Set the current locale? What does this do? */ + if (!setlocale (LC_ALL, "")) { - printf ("Unicode clipboard I/O\n"); + printf ("setlocale() error\n"); + exit (1); } - else + + /* See if X supports the current locale */ + if (XSupportsLocale () == False) { - printf ("Non Unicode clipboard I/O\n"); + printf ("Locale not supported by X\n"); + exit (1); } -#if 0 - /* Specify our signal handlers */ - signal (SIGQUIT, handle_kill); + ClipboardProc(fUnicodeClipboard, pszDisplay); + + return 0; +} + +void +ClipboardProc(Bool fUnicodeSupport, char *pszDisplay) +{ + Atom atomLocalProperty, atomCompoundText; + Atom atomUTF8String, atomTargets; + 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; + int iSelectError; + + /* Initialize retry count */ + iRetries = 0; + + /* Set error handler */ + XSetErrorHandler(ClipboardErrorHandler); + g_ClipboardProcThread = pthread_self(); + g_ClipboardOldIOErrorHandler = XSetIOErrorHandler(ClipboardIOErrorHandler); + + /* Set jump point for error exits */ + if (setjmp(g_jmpEntry)) { + winError("ClipboardProc - setjmp returned for IO Error Handler.\n"); + /* Cleanup and exit */ + goto ClipboardProc_Done; + } - /* Set the current locale? What does this do? */ - 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\n"); - exit (1); - } - /* Open the X display */ do { pDisplay = XOpenDisplay (pszDisplay); if (pDisplay == NULL) { - printf ("Could not open display, try: %d, sleeping: %d\n", - iRetries + 1, WIN_CONNECT_DELAY); + winError ("Could not open display, try: %d, sleeping: %d\n", + iRetries + 1, WIN_CONNECT_DELAY); ++iRetries; sleep (WIN_CONNECT_DELAY); continue; @@ -260,34 +257,29 @@ main (int argc, char *argv[]) /* Make sure that the display opened */ if (pDisplay == NULL) { - printf ("Failed opening the display, giving up\n"); - return 1; + winError ("Failed opening the display, giving up\n"); + return; } - /* Create Windows messaging window */ - hwnd = CreateMessagingWindow (); - /* Get our connection number */ iConnectionNumber = ConnectionNumber (pDisplay); +#ifdef HAS_DEVWINDOWS /* Open a file descriptor for the windows message queue */ - fdMessageQueue = open (WIN_MSG_QUEUE_FNAME, O_RDONLY); - if (fdMessageQueue == -1) - { - printf ("Failed opening %s\n", WIN_MSG_QUEUE_FNAME); - exit (1); - } + fdMessageQueue = open(WIN_MSG_QUEUE_FNAME, O_RDONLY); + if (fdMessageQueue == -1) { + winError ("Failed opening %s\n", WIN_MSG_QUEUE_FNAME); + exit (1); + } /* Find max of our file descriptors */ - iMaxDescriptor = max (fdMessageQueue, iConnectionNumber) + 1; + iMaxDescriptor = MAX(fdMessageQueue, iConnectionNumber) + 1; +#else + iMaxDescriptor = iConnectionNumber + 1; +#endif - /* Select event types to watch */ - if (XSelectInput (pDisplay, - DefaultRootWindow (pDisplay), - SubstructureNotifyMask | - StructureNotifyMask | - PropertyChangeMask) == BadWindow) - printf ("XSelectInput generated BadWindow on RootWindow\n\n"); + if (!XFixesQueryExtension(pDisplay, &xfixes_event_base, &xfixes_error_base)) + winError ("XFixes extension not present\n"); /* Create a messaging window */ iWindow = XCreateSimpleWindow (pDisplay, @@ -299,91 +291,70 @@ main (int argc, char *argv[]) BlackPixel (pDisplay, 0)); if (iWindow == 0) { - printf ("Could not create a window\n"); + winError ("Could not create an X window\n"); exit (1); } -#if 0 /* Print out our window number */ - printf ("Window number: %d\n", iWindow); -#endif + winDebug("Window number: 0x%x\n", iWindow); -#if 0 - /* Display the messaging window, as a test */ - XMapWindow (pDisplay, iWindow); -#endif - - /* ChangeWindowAttributes can change own window's event mask */ -#if 0 - attrib.event_mask = StructureNotifyMask; - iReturn = XChangeWindowAttributes (pDisplay, iWindow, CWEventMask, &attrib); - if (iReturn == BadWindow) - printf ("XChangeWindowAttributes gave BadWindow\n"); - else if (iReturn == BadAccess) - printf ("XChangeWindowAttributes gave BadAccess\n"); - else if (iReturn == BadValue) - printf ("XChangeWindowAttributes gave BadValue\n"); -#endif - - /* This looks like our only hope for getting a message before shutdown */ - /* Register for WM_DELETE_WINDOW message from window manager */ - atomDeleteWindow = XInternAtom (pDisplay, "WM_DELETE_WINDOW", False); - XSetWMProtocols (pDisplay, iWindow, &atomDeleteWindow, 1); - - /* Set error handler */ -#if 0 - XSetErrorHandler (error_handler); -#endif - XSetIOErrorHandler (error_handler_io); + XStoreName(pDisplay, iWindow, "xwinclip"); - /* Create an atom for CLIPBOARD_MANAGER */ - atomClipboardManager = XInternAtom (pDisplay, "CLIPBOARD_MANAGER", False); - if (atomClipboardManager == None) - { - printf ("Could not create CLIPBOARD_MANAGER atom\n"); - exit (1); - } + /* Select event types to watch */ + if (XSelectInput(pDisplay, iWindow, PropertyChangeMask) == BadWindow) + winError("XSelectInput generated BadWindow on messaging window\n"); + + XFixesSelectSelectionInput (pDisplay, + iWindow, + XA_PRIMARY, + XFixesSetSelectionOwnerNotifyMask | + XFixesSelectionWindowDestroyNotifyMask | + XFixesSelectionClientCloseNotifyMask); + + XFixesSelectSelectionInput (pDisplay, + iWindow, + XInternAtom (pDisplay, "CLIPBOARD", False), + XFixesSetSelectionOwnerNotifyMask | + XFixesSelectionWindowDestroyNotifyMask | + XFixesSelectionClientCloseNotifyMask); - /* Assert ownership of CLIPBOARD_MANAGER */ - iReturn = XSetSelectionOwner (pDisplay, atomClipboardManager, - iWindow, CurrentTime); - if (iReturn == BadAtom || iReturn == BadWindow) - { - printf ("Could not set CLIPBOARD_MANAGER owner\n"); - exit (1); - } + /* Create Windows messaging window */ + hwnd = CreateMessagingWindow (pDisplay, iWindow); /* Create an atom for CLIPBOARD */ atomClipboard = XInternAtom (pDisplay, "CLIPBOARD", False); if (atomClipboard == None) { - printf ("Could not create CLIPBOARD atom\n"); + winError ("Could not create CLIPBOARD atom\n"); exit (1); } - /* Assert ownership of CLIPBOARD */ - iReturn = XSetSelectionOwner (pDisplay, atomClipboard, - iWindow, CurrentTime); - if (iReturn == BadAtom || iReturn == BadWindow) - { - printf ("Could not set CLIPBOARD owner\n"); + /* Assert ownership of selections if Win32 clipboard is owned */ + if (NULL != GetClipboardOwner()) { + /* PRIMARY */ + iReturn = XSetSelectionOwner(pDisplay, XA_PRIMARY, + iWindow, CurrentTime); + if (iReturn == BadAtom || iReturn == BadWindow || + XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) { + winError("Could not set PRIMARY owner\n"); exit (1); } - /* Assert ownership of PRIMARY */ - iReturn = XSetSelectionOwner (pDisplay, XA_PRIMARY, - iWindow, CurrentTime); - if (iReturn == BadAtom || iReturn == BadWindow) - { - printf ("Could not set PRIMARY owner\n"); + /* CLIPBOARD */ + iReturn = XSetSelectionOwner(pDisplay, atomClipboard, + iWindow, CurrentTime); + if (iReturn == BadAtom || iReturn == BadWindow || + XGetSelectionOwner(pDisplay, atomClipboard) != iWindow) { + winError("Could not set CLIPBOARD owner\n"); exit (1); } + } - /* Local property to hold pasted data */ + /* Create an atom for Local property to hold pasted data */ atomLocalProperty = XInternAtom (pDisplay, "CYGX_CUT_BUFFER", False); if (atomLocalProperty == None) { - printf ("Could not create CYGX_CUT_BUFFER atom\n"); + winError ("Could not create CYGX_CUT_BUFFER atom\n"); exit (1); } @@ -391,7 +362,7 @@ main (int argc, char *argv[]) atomUTF8String = XInternAtom (pDisplay, "UTF8_STRING", False); if (atomUTF8String == None) { - printf ("Could not create UTF8_STRING atom\n"); + winError ("Could not create UTF8_STRING atom\n"); exit (1); } @@ -399,7 +370,7 @@ main (int argc, char *argv[]) atomCompoundText = XInternAtom (pDisplay, "COMPOUND_TEXT", False); if (atomCompoundText == None) { - printf ("Could not create COMPOUND_TEXT atom\n"); + winError ("Could not create COMPOUND_TEXT atom\n"); exit (1); } @@ -407,24 +378,27 @@ main (int argc, char *argv[]) atomTargets = XInternAtom (pDisplay, "TARGETS", False); if (atomTargets == None) { - printf ("Could not create TARGETS atom\n"); + winError ("Could not create TARGETS atom\n"); exit (1); } /* 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. */ FlushXEvents (hwnd, atomLocalProperty, atomUTF8String, - atomCompoundText, atomTargets, atomDeleteWindow, + atomCompoundText, atomTargets, iWindow, pDisplay, fUnicodeSupport); /* Pre-flush Windows messages */ if (!FlushWindowsMessageQueue (hwnd)) - return 0; + { + winError("ClipboardFlushWindowsMessageQueue failed\n"); + return; + } /* Loop for X events */ while (1) @@ -436,143 +410,178 @@ main (int argc, char *argv[]) * which descriptors are ready. */ FD_ZERO (&fdsRead); - FD_SET (fdMessageQueue, &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 */ - NULL); /* No timeout */ +#ifdef HAS_DEVWINDOWS + NULL /* No timeout */ +#else + &tvTimeout /* Set timeout */ +#endif + ); + +#ifndef HAS_WINSOCK + iSelectError = errno; +#else + iSelectError = WSAGetLastError(); +#endif + if (iReturn <= 0) { - printf ("Call to select () failed: %d. Bailing.\n", iReturn); +#ifndef HAS_WINSOCK + if (iSelectError == EINTR) +#else + if (iSelectError == WSAEINTR) +#endif + continue; + + winError ("Call to select () failed: %d. Bailing.\n", iReturn); break; } - + + winDebug("select returned %d\n", iReturn); + /* Branch on which descriptor became active */ if (FD_ISSET (iConnectionNumber, &fdsRead)) { /* X event ready */ -#if 0 - printf ("X event ready\n"); -#endif + winDebug("X connection ready, pumping X event queue\n"); /* Process X events */ /* Exit when we see that server is shutting down */ - fReturn = FlushXEvents (hwnd, + iReturn = FlushXEvents (hwnd, atomLocalProperty, atomUTF8String, atomCompoundText, atomTargets, - atomDeleteWindow, iWindow, pDisplay, fUnicodeSupport); - if (!fReturn) - { - printf ("Caught WM_DELETE_WINDOW - shutting down\n"); + + if (WIN_XEVENTS_SHUTDOWN == iReturn) + { + winError ("Trapped shutdown event, exiting main loop.\n"); break; } } +#ifdef HAS_DEVWINDOWS /* Check for Windows event ready */ if (FD_ISSET (fdMessageQueue, &fdsRead)) - { - /* Windows event ready */ -#if 0 - printf ("Windows event ready\n"); +#else + if (1) +#endif + { + /* Windows event ready */ + winDebug ("/dev/windows ready, pumping Windows message queue\n"); + + /* Process Windows messages */ + if (!FlushWindowsMessageQueue (hwnd)) + { + winError("FlushWindowsMessageQueue trapped WM_QUIT message, exiting main loop.\n"); + break; + } + } + +#ifdef HAS_DEVWINDOWS + if (!(FD_ISSET(iConnectionNumber, &fdsRead)) && + !(FD_ISSET(fdMessageQueue, &fdsRead))) { + winDebug("Spurious wake\n"); + } #endif - - /* Process Windows messages */ - if (!FlushWindowsMessageQueue (hwnd)) - break; - } } - return 0; -} +ClipboardProc_Done: + /* Close our Windows window */ + if (hwnd) { + /* Destroy the Window window (hwnd) */ + winDebug("Destroy Windows window\n"); + PostMessage(hwnd, WM_DESTROY, 0, 0); + FlushWindowsMessageQueue(hwnd); + } + + /* Close our X window */ + if (pDisplay && iWindow) { + iReturn = XDestroyWindow(pDisplay, iWindow); + if (iReturn == BadWindow) + winError("XDestroyWindow returned BadWindow.\n"); + else + winError("XDestroyWindow succeeded.\n"); + } + +#ifdef HAS_DEVWINDOWS + /* Close our Win32 message handle */ + if (fdMessageQueue) + close(fdMessageQueue); +#endif + + /* Close our X display */ + if (pDisplay) { + XCloseDisplay(pDisplay); + } + + // XXX: should return a value to indicate if this is a shutdown exit or error... +} /* * Create the Windows window that we use to recieve Windows messages */ -HWND -CreateMessagingWindow () +static HWND +CreateMessagingWindow (Display *display, Window window) { - WNDCLASS wc; - HWND hwnd; + WNDCLASSEX wc; + HWND hwnd; /* Setup our window class */ + wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; - wc.hInstance = GetModuleHandle (NULL); + wc.hInstance = GetModuleHandle(NULL); wc.hIcon = 0; wc.hCursor = 0; - wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); + wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = WINDOW_CLASS; - RegisterClass (&wc); + wc.hIconSm = 0; + RegisterClassEx(&wc); + + WindowCreationParams wcp; + wcp.pClipboardDisplay = display; + wcp.iClipboardWindow = window; /* Create the window */ - hwnd = CreateWindowExA (0, /* Extended styles */ - WINDOW_CLASS, /* Class name */ - 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); /* ScreenPrivates */ - assert (hwnd != NULL); + hwnd = CreateWindowExA(0, /* Extended styles */ + WINDOW_CLASS, /* Class name */ + 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 */ + &wcp); /* Creation data */ + assert(hwnd != NULL); /* I'm not sure, but we may need to call this to start message processing */ - ShowWindow (hwnd, SW_HIDE); + ShowWindow(hwnd, SW_HIDE); /* Similarly, we may need a call to this even though we don't paint */ - UpdateWindow (hwnd); + UpdateWindow(hwnd); return hwnd; } - - -/* - * Determine whether we suport Unicode or not. - * NOTE: Currently, just check if we are on an NT-based platform or not. - */ - -Bool -UnicodeSupport () -{ - Bool fReturn = FALSE; - OSVERSIONINFO osvi; - - /* Get operating system version information */ - ZeroMemory (&osvi, sizeof (osvi)); - osvi.dwOSVersionInfoSize = sizeof (osvi); - GetVersionEx (&osvi); - - /* Branch on platform ID */ - switch (osvi.dwPlatformId) - { - case VER_PLATFORM_WIN32_NT: - /* Engine 4 is supported on NT only */ - printf ("UnicodeSupport - Windows NT/2000/XP\n"); - fReturn = TRUE; - break; - - case VER_PLATFORM_WIN32_WINDOWS: - /* Engine 4 is supported on NT only */ - printf ("UnicodeSupport - Windows 95/98/Me\n"); - fReturn = FALSE; - break; - } - - return fReturn; -} |