summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon TURNEY <jon.turney@dronecode.org.uk>2013-06-14 12:57:45 +0100
committerJon TURNEY <jon.turney@dronecode.org.uk>2013-06-15 12:34:25 +0100
commit3673fcb94804ae4e31e20a5d18f7f4e43850098f (patch)
tree1c922c6ad8ee1e5bd682ef7d9d0ac0945943bab4
parent38dcfd7e18eddd28309458a63d10eb5692e4e2ea (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.am5
-rw-r--r--configure.ac14
-rw-r--r--debug.c54
-rw-r--r--debug.h38
-rw-r--r--textconv.c158
-rw-r--r--textconv.h6
-rw-r--r--wndproc.c537
-rw-r--r--wndproc.h29
-rw-r--r--xevents.c1485
-rw-r--r--xevents.h21
-rw-r--r--xwinclip.c589
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
diff --git a/debug.c b/debug.c
new file mode 100644
index 0000000..28f4a05
--- /dev/null
+++ b/debug.c
@@ -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;
+}
diff --git a/debug.h b/debug.h
new file mode 100644
index 0000000..24eb2df
--- /dev/null
+++ b/debug.h
@@ -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 */
diff --git a/textconv.c b/textconv.c
index df02006..197e464 100644
--- a/textconv.c
+++ b/textconv.c
@@ -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);
}
diff --git a/textconv.h b/textconv.h
index 3d7463e..32659fc 100644
--- a/textconv.h
+++ b/textconv.h
@@ -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
diff --git a/wndproc.c b/wndproc.c
index 6a9b672..98fb974 100644
--- a/wndproc.c
+++ b/wndproc.c
@@ -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;
}
-
diff --git a/wndproc.h b/wndproc.h
index eb1adf3..8c7eea4 100644
--- a/wndproc.h
+++ b/wndproc.h
@@ -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
diff --git a/xevents.c b/xevents.c
index cee49a7..850ac3d 100644
--- a/xevents.c
+++ b/xevents.c
@@ -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;
}
diff --git a/xevents.h b/xevents.h
index 95fad29..4fd307c 100644
--- a/xevents.h
+++ b/xevents.h
@@ -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
diff --git a/xwinclip.c b/xwinclip.c
index fa78243..db12f2d 100644
--- a/xwinclip.c
+++ b/xwinclip.c
@@ -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;
-}