sync code with last improvements from OpenBSD

This commit is contained in:
purplerain 2023-08-28 05:57:34 +00:00
commit 88965415ff
Signed by: purplerain
GPG key ID: F42C07F07E2E35B7
26235 changed files with 29195616 additions and 0 deletions

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -0,0 +1,119 @@
/*
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
*
*Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
*"Software"), to deal in the Software without restriction, including
*without limitation the rights to use, copy, modify, merge, publish,
*distribute, sublicense, and/or sell copies of the Software, and to
*permit persons to whom the Software is furnished to do so, subject to
*the following conditions:
*
*The above copyright notice and this permission notice shall be
*included in all copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*Except as contained in this notice, the name of Harold L Hunt II
*shall not be used in advertising or otherwise to promote the sale, use
*or other dealings in this Software without prior written authorization
*from Harold L Hunt II.
*
* Authors: Harold L Hunt II
*/
#ifndef WINCLIPBOARD_INTERNAL_H
#define WINCLIPBOARD_INTERNAL_H
#include <xcb/xproto.h>
#include <X11/Xfuncproto.h> // for _X_ATTRIBUTE_PRINTF
#include <X11/Xmd.h> // for BOOL
/* Windows headers */
#include <X11/Xwindows.h>
#define WIN_XEVENTS_SUCCESS 0 // more like 'CONTINUE'
#define WIN_XEVENTS_FAILED 1
#define WIN_XEVENTS_NOTIFY_DATA 3
#define WIN_XEVENTS_NOTIFY_TARGETS 4
#define WM_WM_QUIT (WM_USER + 2)
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
/*
* References to external symbols
*/
extern void winDebug(const char *format, ...) _X_ATTRIBUTE_PRINTF(1, 2);
extern void ErrorF(const char *format, ...) _X_ATTRIBUTE_PRINTF(1, 2);
/*
* winclipboardtextconv.c
*/
void
winClipboardDOStoUNIX(char *pszData, int iLength);
void
winClipboardUNIXtoDOS(char **ppszData, int iLength);
/*
* winclipboardthread.c
*/
typedef struct
{
xcb_atom_t atomClipboard;
xcb_atom_t atomLocalProperty;
xcb_atom_t atomUTF8String;
xcb_atom_t atomCompoundText;
xcb_atom_t atomTargets;
xcb_atom_t atomIncr;
} ClipboardAtoms;
/*
* winclipboardwndproc.c
*/
BOOL winClipboardFlushWindowsMessageQueue(HWND hwnd);
LRESULT CALLBACK
winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
typedef struct
{
xcb_connection_t *pClipboardDisplay;
xcb_window_t iClipboardWindow;
ClipboardAtoms *atoms;
} ClipboardWindowCreationParams;
/*
* winclipboardxevents.c
*/
typedef struct
{
xcb_atom_t *targetList;
unsigned char *incr;
unsigned long int incrsize;
} ClipboardConversionData;
int
winClipboardFlushXEvents(HWND hwnd,
xcb_window_t iWindow, xcb_connection_t * pDisplay,
ClipboardConversionData *data, ClipboardAtoms *atoms);
xcb_atom_t
winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms);
void
winClipboardInitMonitoredSelections(void);
#endif

View file

@ -0,0 +1,41 @@
srcs_windows_clipboard = [
'winclipboard.h',
'textconv.c',
'thread.c',
'wndproc.c',
'xevents.c',
]
xwin_clipboard = static_library(
'XWinclipboard',
srcs_windows_clipboard,
include_directories: inc,
c_args: '-DHAVE_XWIN_CONFIG_H',
dependencies: [
dependency('xcb'),
dependency('xcb-aux'),
dependency('xcb-icccm'),
dependency('xcb-xfixes'),
socket_dep,
],
)
srcs_xwinclip = [
'xwinclip.c',
'debug.c',
]
executable(
'xwinclip',
srcs_xwinclip,
link_with: xwin_clipboard,
link_args: ['-lgdi32', '-lpthread'],
install: true,
)
xwinclip_man = configure_file(
input: 'xwinclip.man',
output: 'xwinclip.1',
configuration: manpage_config,
)
install_man(xwinclip_man)

View file

@ -0,0 +1,142 @@
/*
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
*
*Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
*"Software"), to deal in the Software without restriction, including
*without limitation the rights to use, copy, modify, merge, publish,
*distribute, sublicense, and/or sell copies of the Software, and to
*permit persons to whom the Software is furnished to do so, subject to
*the following conditions:
*
*The above copyright notice and this permission notice shall be
*included in all copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*Except as contained in this notice, the name of Harold L Hunt II
*shall not be used in advertising or otherwise to promote the sale, use
*or other dealings in this Software without prior written authorization
*from Harold L Hunt II.
*
* Authors: Harold L Hunt II
*/
#ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h>
#endif
#include <stdlib.h>
#include "internal.h"
/*
* Convert \r\n to \n
*
* NOTE: This was heavily inspired by, Cygwin's
* winsup/cygwin/fhandler.cc/fhandler_base::read ()
*/
void
winClipboardDOStoUNIX(char *pszSrc, int iLength)
{
char *pszDest = pszSrc;
char *pszEnd = pszSrc + iLength;
/* Loop until the last character */
while (pszSrc < pszEnd) {
/* Copy the current source character to current destination character */
*pszDest = *pszSrc;
/* Advance to the next source character */
pszSrc++;
/* Don't advance the destination character if we need to drop an \r */
if (*pszDest != '\r' || *pszSrc != '\n')
pszDest++;
}
/* Move the terminating null */
*pszDest = '\0';
}
/*
* Convert \n to \r\n
*/
void
winClipboardUNIXtoDOS(char **ppszData, int iLength)
{
int iNewlineCount = 0;
char *pszSrc = *ppszData;
char *pszEnd = pszSrc + iLength;
char *pszDest = NULL, *pszDestBegin = NULL;
winDebug("UNIXtoDOS () - Original data:'%s'\n", *ppszData);
/* Count \n characters without leading \r */
while (pszSrc < pszEnd) {
/* Skip ahead two character if found set of \r\n */
if (*pszSrc == '\r' && pszSrc + 1 < pszEnd && *(pszSrc + 1) == '\n') {
pszSrc += 2;
continue;
}
/* Increment the count if found naked \n */
if (*pszSrc == '\n') {
iNewlineCount++;
}
pszSrc++;
}
/* Return if no naked \n's */
if (iNewlineCount == 0)
return;
/* Allocate a new string */
pszDestBegin = pszDest = malloc(iLength + iNewlineCount + 1);
/* Set source pointer to beginning of data string */
pszSrc = *ppszData;
/* Loop through all characters in source string */
while (pszSrc < pszEnd) {
/* Copy line endings that are already valid */
if (*pszSrc == '\r' && pszSrc + 1 < pszEnd && *(pszSrc + 1) == '\n') {
*pszDest = *pszSrc;
*(pszDest + 1) = *(pszSrc + 1);
pszDest += 2;
pszSrc += 2;
continue;
}
/* Add \r to naked \n's */
if (*pszSrc == '\n') {
*pszDest = '\r';
*(pszDest + 1) = *pszSrc;
pszDest += 2;
pszSrc += 1;
continue;
}
/* Copy normal characters */
*pszDest = *pszSrc;
pszSrc++;
pszDest++;
}
/* Put terminating null at end of new string */
*pszDest = '\0';
/* Swap string pointers */
free(*ppszData);
*ppszData = pszDestBegin;
winDebug("UNIXtoDOS () - Final string:'%s'\n", pszDestBegin);
}

View file

@ -0,0 +1,439 @@
/*
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
*Copyright (C) Colin Harrison 2005-2008
*
*Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
*"Software"), to deal in the Software without restriction, including
*without limitation the rights to use, copy, modify, merge, publish,
*distribute, sublicense, and/or sell copies of the Software, and to
*permit persons to whom the Software is furnished to do so, subject to
*the following conditions:
*
*The above copyright notice and this permission notice shall be
*included in all copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*Except as contained in this notice, the name of the copyright holder(s)
*and author(s) shall not be used in advertising or otherwise to promote
*the sale, use or other dealings in this Software without prior written
*authorization from the copyright holder(s) and author(s).
*
* Authors: Harold L Hunt II
* Colin Harrison
*/
#ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h>
#else
#define HAS_WINSOCK 1
#endif
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/param.h> // for MAX() macro
#ifdef HAS_WINSOCK
#include <X11/Xwinsock.h>
#else
#include <errno.h>
#endif
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xfixes.h>
#include "winclipboard.h"
#include "internal.h"
#define WIN_CONNECT_RETRIES 40
#define WIN_CONNECT_DELAY 4
#define WIN_CLIPBOARD_WINDOW_CLASS "xwinclip"
#define WIN_CLIPBOARD_WINDOW_TITLE "xwinclip"
#ifdef HAS_DEVWINDOWS
#define WIN_MSG_QUEUE_FNAME "/dev/windows"
#endif
/*
* Global variables
*/
static HWND g_hwndClipboard = NULL;
int xfixes_event_base;
int xfixes_error_base;
/*
* Local function prototypes
*/
static HWND
winClipboardCreateMessagingWindow(xcb_connection_t *conn, xcb_window_t iWindow, ClipboardAtoms *atoms);
static xcb_atom_t
intern_atom(xcb_connection_t *conn, const char *atomName)
{
xcb_intern_atom_reply_t *atom_reply;
xcb_intern_atom_cookie_t atom_cookie;
xcb_atom_t atom = XCB_ATOM_NONE;
atom_cookie = xcb_intern_atom(conn, 0, strlen(atomName), atomName);
atom_reply = xcb_intern_atom_reply(conn, atom_cookie, NULL);
if (atom_reply) {
atom = atom_reply->atom;
free(atom_reply);
}
return atom;
}
/*
* Create X11 and Win32 messaging windows, and run message processing loop
*
* returns TRUE if shutdown was signalled to loop, FALSE if some error occurred
*/
BOOL
winClipboardProc(char *szDisplay, xcb_auth_info_t *auth_info)
{
ClipboardAtoms atoms;
int iReturn;
HWND hwnd = NULL;
int iConnectionNumber = 0;
#ifdef HAS_DEVWINDOWS
int fdMessageQueue = 0;
#else
struct timeval tvTimeout;
#endif
fd_set fdsRead;
int iMaxDescriptor;
xcb_connection_t *conn;
xcb_window_t iWindow = XCB_NONE;
int iSelectError;
BOOL fShutdown = FALSE;
ClipboardConversionData data;
int screen;
winDebug("winClipboardProc - Hello\n");
/* Make sure that the display opened */
conn = xcb_connect_to_display_with_auth_info(szDisplay, auth_info, &screen);
if (xcb_connection_has_error(conn)) {
ErrorF("winClipboardProc - Failed opening the display, giving up\n");
goto winClipboardProc_Done;
}
ErrorF("winClipboardProc - xcb_connect () returned and "
"successfully opened the display.\n");
/* Get our connection number */
iConnectionNumber = xcb_get_file_descriptor(conn);
#ifdef HAS_DEVWINDOWS
/* Open a file descriptor for the windows message queue */
fdMessageQueue = open(WIN_MSG_QUEUE_FNAME, O_RDONLY);
if (fdMessageQueue == -1) {
ErrorF("winClipboardProc - Failed opening %s\n", WIN_MSG_QUEUE_FNAME);
goto winClipboardProc_Done;
}
/* Find max of our file descriptors */
iMaxDescriptor = MAX(fdMessageQueue, iConnectionNumber) + 1;
#else
iMaxDescriptor = iConnectionNumber + 1;
#endif
const xcb_query_extension_reply_t *xfixes_query;
xfixes_query = xcb_get_extension_data(conn, &xcb_xfixes_id);
if (!xfixes_query->present)
ErrorF ("winClipboardProc - XFixes extension not present\n");
xfixes_event_base = xfixes_query->first_event;
xfixes_error_base = xfixes_query->first_error;
/* Must advise server of XFIXES version we require */
xcb_xfixes_query_version_unchecked(conn, 1, 0);
/* Create atoms */
atoms.atomClipboard = intern_atom(conn, "CLIPBOARD");
atoms.atomLocalProperty = intern_atom(conn, "CYGX_CUT_BUFFER");
atoms.atomUTF8String = intern_atom(conn, "UTF8_STRING");
atoms.atomCompoundText = intern_atom(conn, "COMPOUND_TEXT");
atoms.atomTargets = intern_atom(conn, "TARGETS");
atoms.atomIncr = intern_atom(conn, "INCR");
xcb_screen_t *root_screen = xcb_aux_get_screen(conn, screen);
xcb_window_t root_window_id = root_screen->root;
/* Create a messaging window */
iWindow = xcb_generate_id(conn);
xcb_void_cookie_t cookie = xcb_create_window_checked(conn,
XCB_COPY_FROM_PARENT,
iWindow,
root_window_id,
1, 1,
500, 500,
0,
XCB_WINDOW_CLASS_INPUT_ONLY,
XCB_COPY_FROM_PARENT,
0,
NULL);
xcb_generic_error_t *error;
if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardProc - Could not create an X window.\n");
free(error);
goto winClipboardProc_Done;
}
xcb_icccm_set_wm_name(conn, iWindow, XCB_ATOM_STRING, 8, strlen("xwinclip"), "xwinclip");
/* Select event types to watch */
const static uint32_t values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
cookie = xcb_change_window_attributes_checked(conn, iWindow, XCB_CW_EVENT_MASK, values);
if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardProc - Could not set event mask on messaging window\n");
free(error);
}
xcb_xfixes_select_selection_input(conn,
iWindow,
XCB_ATOM_PRIMARY,
XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE);
xcb_xfixes_select_selection_input(conn,
iWindow,
atoms.atomClipboard,
XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE);
/* Initialize monitored selection state */
winClipboardInitMonitoredSelections();
/* Create Windows messaging window */
hwnd = winClipboardCreateMessagingWindow(conn, iWindow, &atoms);
/* Save copy of HWND */
g_hwndClipboard = hwnd;
/* Assert ownership of selections if Win32 clipboard is owned */
if (NULL != GetClipboardOwner()) {
/* PRIMARY */
cookie = xcb_set_selection_owner_checked(conn, iWindow, XCB_ATOM_PRIMARY, XCB_CURRENT_TIME);
if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardProc - Could not set PRIMARY owner\n");
free(error);
goto winClipboardProc_Done;
}
/* CLIPBOARD */
cookie = xcb_set_selection_owner_checked(conn, iWindow, atoms.atomClipboard, XCB_CURRENT_TIME);
if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardProc - Could not set CLIPBOARD owner\n");
free(error);
goto winClipboardProc_Done;
}
}
data.incr = NULL;
data.incrsize = 0;
/* Loop for events */
while (1) {
/* Process X events */
winClipboardFlushXEvents(hwnd, iWindow, conn, &data, &atoms);
/* Process Windows messages */
if (!winClipboardFlushWindowsMessageQueue(hwnd)) {
ErrorF("winClipboardProc - winClipboardFlushWindowsMessageQueue trapped "
"WM_QUIT message, exiting main loop.\n");
break;
}
/* We need to ensure that all pending requests are sent */
xcb_flush(conn);
/* Setup the file descriptor set */
/*
* NOTE: You have to do this before every call to select
* because select modifies the mask to indicate
* which descriptors are ready.
*/
FD_ZERO(&fdsRead);
FD_SET(iConnectionNumber, &fdsRead);
#ifdef HAS_DEVWINDOWS
FD_SET(fdMessageQueue, &fdsRead);
#else
tvTimeout.tv_sec = 0;
tvTimeout.tv_usec = 100;
#endif
/* Wait for a Windows event or an X event */
iReturn = select(iMaxDescriptor, /* Highest fds number */
&fdsRead, /* Read mask */
NULL, /* No write mask */
NULL, /* No exception mask */
#ifdef HAS_DEVWINDOWS
NULL /* No timeout */
#else
&tvTimeout /* Set timeout */
#endif
);
#ifndef HAS_WINSOCK
iSelectError = errno;
#else
iSelectError = WSAGetLastError();
#endif
if (iReturn < 0) {
#ifndef HAS_WINSOCK
if (iSelectError == EINTR)
#else
if (iSelectError == WSAEINTR)
#endif
continue;
ErrorF("winClipboardProc - Call to select () failed: %d. "
"Bailing.\n", iReturn);
break;
}
if (FD_ISSET(iConnectionNumber, &fdsRead)) {
winDebug
("winClipboardProc - X connection ready, pumping X event queue\n");
}
#ifdef HAS_DEVWINDOWS
/* Check for Windows event ready */
if (FD_ISSET(fdMessageQueue, &fdsRead))
#else
if (1)
#endif
{
winDebug
("winClipboardProc - /dev/windows ready, pumping Windows message queue\n");
}
#ifdef HAS_DEVWINDOWS
if (!(FD_ISSET(iConnectionNumber, &fdsRead)) &&
!(FD_ISSET(fdMessageQueue, &fdsRead))) {
winDebug("winClipboardProc - Spurious wake, select() returned %d\n", iReturn);
}
#endif
}
/* broke out of while loop on a shutdown message */
fShutdown = TRUE;
winClipboardProc_Done:
/* Close our Windows window */
if (g_hwndClipboard) {
DestroyWindow(g_hwndClipboard);
}
/* Close our X window */
if (!xcb_connection_has_error(conn) && iWindow) {
cookie = xcb_destroy_window_checked(conn, iWindow);
if ((error = xcb_request_check(conn, cookie)))
ErrorF("winClipboardProc - XDestroyWindow failed.\n");
else
ErrorF("winClipboardProc - XDestroyWindow succeeded.\n");
free(error);
}
#ifdef HAS_DEVWINDOWS
/* Close our Win32 message handle */
if (fdMessageQueue)
close(fdMessageQueue);
#endif
/*
* xcb_disconnect() does not sync, so is safe to call even when we are built
* into the server. Unlike XCloseDisplay() there will be no deadlock if the
* server is in the process of exiting and waiting for this thread to exit.
*/
if (!xcb_connection_has_error(conn)) {
/* Close our X display */
xcb_disconnect(conn);
}
/* global clipboard variable reset */
g_hwndClipboard = NULL;
return fShutdown;
}
/*
* Create the Windows window that we use to receive Windows messages
*/
static HWND
winClipboardCreateMessagingWindow(xcb_connection_t *conn, xcb_window_t iWindow, ClipboardAtoms *atoms)
{
WNDCLASSEX wc;
ClipboardWindowCreationParams cwcp;
HWND hwnd;
/* Setup our window class */
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = winClipboardWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = 0;
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = WIN_CLIPBOARD_WINDOW_CLASS;
wc.hIconSm = 0;
RegisterClassEx(&wc);
/* Information to be passed to WM_CREATE */
cwcp.pClipboardDisplay = conn;
cwcp.iClipboardWindow = iWindow;
cwcp.atoms = atoms;
/* Create the window */
hwnd = CreateWindowExA(0, /* Extended styles */
WIN_CLIPBOARD_WINDOW_CLASS, /* Class name */
WIN_CLIPBOARD_WINDOW_TITLE, /* Window name */
WS_OVERLAPPED, /* Not visible anyway */
CW_USEDEFAULT, /* Horizontal position */
CW_USEDEFAULT, /* Vertical position */
CW_USEDEFAULT, /* Right edge */
CW_USEDEFAULT, /* Bottom edge */
(HWND) NULL, /* No parent or owner window */
(HMENU) NULL, /* No menu */
GetModuleHandle(NULL), /* Instance handle */
&cwcp); /* Creation data */
assert(hwnd != NULL);
/* I'm not sure, but we may need to call this to start message processing */
ShowWindow(hwnd, SW_HIDE);
/* Similarly, we may need a call to this even though we don't paint */
UpdateWindow(hwnd);
return hwnd;
}
void
winClipboardWindowDestroy(void)
{
if (g_hwndClipboard) {
SendMessage(g_hwndClipboard, WM_WM_QUIT, 0, 0);
}
}

View file

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

View file

@ -0,0 +1,462 @@
/*
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
*Copyright (C) Colin Harrison 2005-2008
*
*Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
*"Software"), to deal in the Software without restriction, including
*without limitation the rights to use, copy, modify, merge, publish,
*distribute, sublicense, and/or sell copies of the Software, and to
*permit persons to whom the Software is furnished to do so, subject to
*the following conditions:
*
*The above copyright notice and this permission notice shall be
*included in all copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*Except as contained in this notice, the name of the copyright holder(s)
*and author(s) shall not be used in advertising or otherwise to promote
*the sale, use or other dealings in this Software without prior written
*authorization from the copyright holder(s) and author(s).
*
* Authors: Harold L Hunt II
* Colin Harrison
*/
#define WINVER 0x0600
#ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <limits.h>
#include <xcb/xproto.h>
#include <xcb/xcb_aux.h>
#include "internal.h"
#include "winclipboard.h"
/*
* Constants
*/
#define WIN_POLL_TIMEOUT 1
/*
* Process X events up to specified timeout
*/
static int
winProcessXEventsTimeout(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn,
ClipboardConversionData *data, ClipboardAtoms *atoms, int iTimeoutSec)
{
int iConnNumber;
struct timeval tv;
int iReturn;
winDebug("winProcessXEventsTimeout () - pumping X events, timeout %d seconds\n",
iTimeoutSec);
/* Get our connection number */
iConnNumber = xcb_get_file_descriptor(conn);
/* Loop for X events */
while (1) {
fd_set fdsRead;
long remainingTime;
/* Process X events */
iReturn = winClipboardFlushXEvents(hwnd, iWindow, conn, data, atoms);
winDebug("winProcessXEventsTimeout () - winClipboardFlushXEvents returned %d\n", iReturn);
if ((WIN_XEVENTS_NOTIFY_DATA == iReturn) || (WIN_XEVENTS_NOTIFY_TARGETS == iReturn) || (WIN_XEVENTS_FAILED == iReturn)) {
/* Bail out */
return iReturn;
}
/* We need to ensure that all pending requests are sent */
xcb_flush(conn);
/* Setup the file descriptor set */
FD_ZERO(&fdsRead);
FD_SET(iConnNumber, &fdsRead);
/* Adjust timeout */
remainingTime = iTimeoutSec * 1000;
tv.tv_sec = remainingTime / 1000;
tv.tv_usec = (remainingTime % 1000) * 1000;
/* Break out if no time left */
if (remainingTime <= 0)
return WIN_XEVENTS_SUCCESS;
/* Wait for an X event */
iReturn = select(iConnNumber + 1, /* Highest fds number */
&fdsRead, /* Read mask */
NULL, /* No write mask */
NULL, /* No exception mask */
&tv); /* Timeout */
if (iReturn < 0) {
ErrorF("winProcessXEventsTimeout - Call to select () failed: %d. "
"Bailing.\n", iReturn);
break;
}
if (!FD_ISSET(iConnNumber, &fdsRead)) {
winDebug("winProcessXEventsTimeout - Spurious wake, select() returned %d\n", iReturn);
}
}
return WIN_XEVENTS_SUCCESS;
}
/*
* Process a given Windows message
*/
LRESULT CALLBACK
winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static xcb_connection_t *conn;
static xcb_window_t iWindow;
static ClipboardAtoms *atoms;
static BOOL fRunning;
/* Branch on message type */
switch (message) {
case WM_DESTROY:
{
winDebug("winClipboardWindowProc - WM_DESTROY\n");
/* Remove clipboard listener */
RemoveClipboardFormatListener(hwnd);
}
return 0;
case WM_WM_QUIT:
{
winDebug("winClipboardWindowProc - WM_WM_QUIT\n");
fRunning = FALSE;
PostQuitMessage(0);
}
return 0;
case WM_CREATE:
{
ClipboardWindowCreationParams *cwcp = (ClipboardWindowCreationParams *)((CREATESTRUCT *)lParam)->lpCreateParams;
winDebug("winClipboardWindowProc - WM_CREATE\n");
conn = cwcp->pClipboardDisplay;
iWindow = cwcp->iClipboardWindow;
atoms = cwcp->atoms;
fRunning = TRUE;
AddClipboardFormatListener(hwnd);
}
return 0;
case WM_CLIPBOARDUPDATE:
{
xcb_generic_error_t *error;
xcb_void_cookie_t cookie_set;
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Enter\n");
/*
* 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("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"We own the clipboard, returning.\n");
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Exit\n");
return 0;
}
/* Bail when shutting down */
if (!fRunning)
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)) {
xcb_get_selection_owner_cookie_t cookie_get;
xcb_get_selection_owner_reply_t *reply;
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"Clipboard does not contain CF_TEXT nor "
"CF_UNICODETEXT.\n");
/*
* We need to make sure that the X Server has processed
* previous XSetSelectionOwner messages.
*/
xcb_aux_sync(conn);
winDebug("winClipboardWindowProc - XSync done.\n");
/* Release PRIMARY selection if owned */
cookie_get = xcb_get_selection_owner(conn, XCB_ATOM_PRIMARY);
reply = xcb_get_selection_owner_reply(conn, cookie_get, NULL);
if (reply) {
if (reply->owner == iWindow) {
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"PRIMARY selection is owned by us, releasing.\n");
xcb_set_selection_owner(conn, XCB_NONE, XCB_ATOM_PRIMARY, XCB_CURRENT_TIME);
}
free(reply);
}
/* Release CLIPBOARD selection if owned */
cookie_get = xcb_get_selection_owner(conn, atoms->atomClipboard);
reply = xcb_get_selection_owner_reply(conn, cookie_get, NULL);
if (reply) {
if (reply->owner == iWindow) {
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"CLIPBOARD selection is owned by us, releasing\n");
xcb_set_selection_owner(conn, XCB_NONE, atoms->atomClipboard, XCB_CURRENT_TIME);
}
free(reply);
}
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Exit\n");
return 0;
}
/* Reassert ownership of PRIMARY */
cookie_set = xcb_set_selection_owner_checked(conn, iWindow, XCB_ATOM_PRIMARY, XCB_CURRENT_TIME);
error = xcb_request_check(conn, cookie_set);
if (error) {
ErrorF("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"Could not reassert ownership of PRIMARY\n");
free(error);
} else {
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"Reasserted ownership of PRIMARY\n");
}
/* Reassert ownership of the CLIPBOARD */
cookie_set = xcb_set_selection_owner_checked(conn, iWindow, atoms->atomClipboard, XCB_CURRENT_TIME);
error = xcb_request_check(conn, cookie_set);
if (error) {
ErrorF("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"Could not reassert ownership of CLIPBOARD\n");
free(error);
}
else {
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"Reasserted ownership of CLIPBOARD\n");
}
/* Flush the pending SetSelectionOwner event now */
xcb_flush(conn);
}
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Exit\n");
return 0;
case WM_DESTROYCLIPBOARD:
/*
* NOTE: Intentionally do nothing.
* Changes in the Win32 clipboard are handled by WM_CLIPBOARDUPDATE
* 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_CLIPBOARDUPDATE message will closely
* follow this message and reassert ownership of the X11
* selections, handling the issue for us.
*/
winDebug("winClipboardWindowProc - WM_DESTROYCLIPBOARD - Ignored.\n");
return 0;
case WM_RENDERALLFORMATS:
winDebug("winClipboardWindowProc - WM_RENDERALLFORMATS - Hello.\n");
/*
WM_RENDERALLFORMATS is sent as we are shutting down, to render the
clipboard so its contents remains available to other applications.
Unfortunately, this can't work without major changes. The server is
already waiting for us to stop, so we can't ask for the rendering of
clipboard text now.
*/
return 0;
case WM_RENDERFORMAT:
{
int iReturn;
BOOL pasted = FALSE;
xcb_atom_t selection;
ClipboardConversionData data;
int best_target = 0;
winDebug("winClipboardWindowProc - WM_RENDERFORMAT %d - Hello.\n",
(int)wParam);
selection = winClipboardGetLastOwnedSelectionAtom(atoms);
if (selection == XCB_NONE) {
ErrorF("winClipboardWindowProc - no monitored selection is owned\n");
goto fake_paste;
}
winDebug("winClipboardWindowProc - requesting targets for selection from owner\n");
/* Request the selection's supported conversion targets */
xcb_convert_selection(conn, iWindow, selection, atoms->atomTargets,
atoms->atomLocalProperty, XCB_CURRENT_TIME);
/* Process X events */
data.incr = NULL;
data.incrsize = 0;
iReturn = winProcessXEventsTimeout(hwnd,
iWindow,
conn,
&data,
atoms,
WIN_POLL_TIMEOUT);
if (WIN_XEVENTS_NOTIFY_TARGETS != iReturn) {
ErrorF
("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY_TARGETS\n");
goto fake_paste;
}
/* Choose the most preferred target */
{
struct target_priority
{
xcb_atom_t target;
unsigned int priority;
};
struct target_priority target_priority_table[] =
{
{ atoms->atomUTF8String, 0 },
// { atoms->atomCompoundText, 1 }, not implemented (yet?)
{ XCB_ATOM_STRING, 2 },
};
int best_priority = INT_MAX;
int i,j;
for (i = 0 ; data.targetList[i] != 0; i++)
{
for (j = 0; j < ARRAY_SIZE(target_priority_table); j ++)
{
if ((data.targetList[i] == target_priority_table[j].target) &&
(target_priority_table[j].priority < best_priority))
{
best_target = target_priority_table[j].target;
best_priority = target_priority_table[j].priority;
}
}
}
}
free(data.targetList);
data.targetList = 0;
winDebug("winClipboardWindowProc - best target is %d\n", best_target);
/* No useful targets found */
if (best_target == 0)
goto fake_paste;
winDebug("winClipboardWindowProc - requesting selection from owner\n");
/* Request the selection contents */
xcb_convert_selection(conn, iWindow, selection, best_target,
atoms->atomLocalProperty, XCB_CURRENT_TIME);
/* Process X events */
iReturn = winProcessXEventsTimeout(hwnd,
iWindow,
conn,
&data,
atoms,
WIN_POLL_TIMEOUT);
/*
* winProcessXEventsTimeout had better have seen a notify event,
* or else we are dealing with a buggy or old X11 app.
*/
if (WIN_XEVENTS_NOTIFY_DATA != iReturn) {
ErrorF
("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY_DATA\n");
}
else {
pasted = TRUE;
}
/*
* If we couldn't get the data from the X clipboard, we
* have to paste some fake data to the Win32 clipboard to
* satisfy the requirement that we write something to it.
*/
fake_paste:
if (!pasted)
{
/* Paste no data, to satisfy required call to SetClipboardData */
SetClipboardData(CF_UNICODETEXT, NULL);
SetClipboardData(CF_TEXT, NULL);
}
winDebug("winClipboardWindowProc - WM_RENDERFORMAT - Returning.\n");
return 0;
}
}
/* Let Windows perform default processing for unhandled messages */
return DefWindowProc(hwnd, message, wParam, lParam);
}
/*
* Process any pending Windows messages
*/
BOOL
winClipboardFlushWindowsMessageQueue(HWND hwnd)
{
MSG msg;
/* Flush the messaging window queue */
/* NOTE: Do not pass the hwnd of our messaging window to PeekMessage,
* as this will filter out many non-window-specific messages that
* are sent to our thread, such as WM_QUIT.
*/
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
/* Dispatch the message if not WM_QUIT */
if (msg.message == WM_QUIT)
return FALSE;
else
DispatchMessage(&msg);
}
return TRUE;
}

View file

@ -0,0 +1,829 @@
/*
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
*Copyright (C) Colin Harrison 2005-2008
*
*Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
*"Software"), to deal in the Software without restriction, including
*without limitation the rights to use, copy, modify, merge, publish,
*distribute, sublicense, and/or sell copies of the Software, and to
*permit persons to whom the Software is furnished to do so, subject to
*the following conditions:
*
*The above copyright notice and this permission notice shall be
*included in all copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*Except as contained in this notice, the name of the copyright holder(s)
*and author(s) shall not be used in advertising or otherwise to promote
*the sale, use or other dealings in this Software without prior written
*authorization from the copyright holder(s) and author(s).
*
* Authors: Harold L Hunt II
* Colin Harrison
*/
#ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h>
#endif
#include <limits.h>
#include <wchar.h>
#include <xcb/xcb.h>
#include <xcb/xfixes.h>
#include "winclipboard.h"
#include "internal.h"
/*
* Constants
*/
#define CLIP_NUM_SELECTIONS 2
#define CLIP_OWN_NONE -1
#define CLIP_OWN_PRIMARY 0
#define CLIP_OWN_CLIPBOARD 1
#define CP_ISO_8559_1 28591
/*
* Global variables
*/
extern int xfixes_event_base;
BOOL fPrimarySelection = TRUE;
/*
* Local variables
*/
static xcb_window_t s_iOwners[CLIP_NUM_SELECTIONS] = { XCB_NONE, XCB_NONE };
static const char *szSelectionNames[CLIP_NUM_SELECTIONS] =
{ "PRIMARY", "CLIPBOARD" };
static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE;
static void
MonitorSelection(xcb_xfixes_selection_notify_event_t * e, unsigned int i)
{
/* Look for owned -> not owned transition */
if ((XCB_NONE == e->owner) && (XCB_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 (XCB_NONE != s_iOwners[other_index])
lastOwnedSelectionIndex = other_index;
else
lastOwnedSelectionIndex = CLIP_OWN_NONE;
}
/* Save last owned selection */
if (XCB_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);
}
xcb_atom_t
winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms)
{
if (lastOwnedSelectionIndex == CLIP_OWN_NONE)
return XCB_NONE;
if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY)
return XCB_ATOM_PRIMARY;
if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD)
return atoms->atomClipboard;
return XCB_NONE;
}
void
winClipboardInitMonitoredSelections(void)
{
/* Initialize static variables */
int i;
for (i = 0; i < CLIP_NUM_SELECTIONS; ++i)
s_iOwners[i] = XCB_NONE;
lastOwnedSelectionIndex = CLIP_OWN_NONE;
}
static char *get_atom_name(xcb_connection_t *conn, xcb_atom_t atom)
{
char *ret;
xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(conn, atom);
xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(conn, cookie, NULL);
if (!reply)
return NULL;
ret = malloc(xcb_get_atom_name_name_length(reply) + 1);
if (ret) {
memcpy(ret, xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply));
ret[xcb_get_atom_name_name_length(reply)] = '\0';
}
free(reply);
return ret;
}
static int
winClipboardSelectionNotifyTargets(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn, ClipboardConversionData *data, ClipboardAtoms *atoms)
{
/* Retrieve the selection data and delete the property */
xcb_get_property_cookie_t cookie = xcb_get_property(conn,
TRUE,
iWindow,
atoms->atomLocalProperty,
XCB_GET_PROPERTY_TYPE_ANY,
0,
INT_MAX);
xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
if (!reply) {
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
"XGetWindowProperty () failed\n");
} else {
xcb_atom_t *prop = xcb_get_property_value(reply);
int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t);
int i;
data->targetList = malloc((nitems+1)*sizeof(xcb_atom_t));
for (i = 0; i < nitems; i++)
{
xcb_atom_t atom = prop[i];
char *pszAtomName = get_atom_name(conn, atom);
data->targetList[i] = atom;
winDebug("winClipboardFlushXEvents - SelectionNotify - target[%d] %d = %s\n", i, atom, pszAtomName);
free(pszAtomName);
}
data->targetList[nitems] = 0;
free(reply);
}
return WIN_XEVENTS_NOTIFY_TARGETS;
}
static int
winClipboardSelectionNotifyData(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn, ClipboardConversionData *data, ClipboardAtoms *atoms)
{
xcb_atom_t encoding;
int format;
unsigned long int nitems;
unsigned long int after;
unsigned char *value;
unsigned char *xtpText_value;
xcb_atom_t xtpText_encoding;
int xtpText_nitems;
BOOL fSetClipboardData = TRUE;
char *pszReturnData = NULL;
UINT codepage;
wchar_t *pwszUnicodeStr = NULL;
HGLOBAL hGlobal = NULL;
char *pszGlobalData = NULL;
/* Retrieve the selection data and delete the property */
xcb_get_property_cookie_t cookie = xcb_get_property(conn,
TRUE,
iWindow,
atoms->atomLocalProperty,
XCB_GET_PROPERTY_TYPE_ANY,
0,
INT_MAX);
xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
if (!reply) {
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
"XGetWindowProperty () failed\n");
goto winClipboardFlushXEvents_SelectionNotify_Done;
} else {
nitems = xcb_get_property_value_length(reply);
value = xcb_get_property_value(reply);
after = reply->bytes_after;
encoding = reply->type;
format = reply->format;
// We assume format == 8 (i.e. data is a sequence of bytes). It's not
// clear how anything else should be handled.
if (format != 8)
ErrorF("SelectionNotify: format is %d, proceeding as if it was 8\n", format);
}
{
char *pszAtomName;
winDebug("SelectionNotify - returned data %lu left %lu\n", nitems, after);
pszAtomName = get_atom_name(conn, encoding);
winDebug("Notify atom name %s\n", pszAtomName);
free(pszAtomName);
}
/* INCR reply indicates the start of a incremental transfer */
if (encoding == atoms->atomIncr) {
winDebug("winClipboardSelectionNotifyData: starting INCR, anticipated size %d\n", *(int *)value);
data->incrsize = 0;
data->incr = malloc(*(int *)value);
// XXX: if malloc failed, we have an error
return WIN_XEVENTS_SUCCESS;
}
else if (data->incr) {
/* If an INCR transfer is in progress ... */
if (nitems == 0) {
winDebug("winClipboardSelectionNotifyData: ending INCR, actual size %ld\n", data->incrsize);
/* a zero-length property indicates the end of the data */
xtpText_value = data->incr;
xtpText_encoding = encoding;
// XXX: The type of the converted selection is the type of the first
// partial property. The remaining partial properties must have the
// same type.
xtpText_nitems = data->incrsize;
}
else {
/* Otherwise, continue appending the INCR data */
winDebug("winClipboardSelectionNotifyData: INCR, %ld bytes\n", nitems);
data->incr = realloc(data->incr, data->incrsize + nitems);
memcpy(data->incr + data->incrsize, value, nitems);
data->incrsize = data->incrsize + nitems;
return WIN_XEVENTS_SUCCESS;
}
}
else {
/* Otherwise, the data is just contained in the property */
winDebug("winClipboardSelectionNotifyData: non-INCR, %ld bytes\n", nitems);
xtpText_value = value;
xtpText_encoding = encoding;
xtpText_nitems = nitems;
}
if (xtpText_encoding == atoms->atomUTF8String) {
pszReturnData = malloc(xtpText_nitems + 1);
memcpy(pszReturnData, xtpText_value, xtpText_nitems);
pszReturnData[xtpText_nitems] = 0;
codepage = CP_UTF8; // code page identifier for utf8
} else if (xtpText_encoding == XCB_ATOM_STRING) {
// STRING encoding is Latin1 (ISO8859-1) plus tab and newline
pszReturnData = malloc(xtpText_nitems + 1);
memcpy(pszReturnData, xtpText_value, xtpText_nitems);
pszReturnData[xtpText_nitems] = 0;
codepage = CP_ISO_8559_1; // code page identifier for iso-8559-1
} else if (xtpText_encoding == atoms->atomCompoundText) {
// COMPOUND_TEXT is complex, based on ISO 2022
ErrorF("SelectionNotify: data in COMPOUND_TEXT encoding which is not implemented, discarding\n");
pszReturnData = malloc(1);
pszReturnData[0] = '\0';
} else { // shouldn't happen as we accept no other encodings
pszReturnData = malloc(1);
pszReturnData[0] = '\0';
}
/* Free the data returned from xcb_get_property */
free(reply);
/* Free any INCR data */
if (data->incr) {
free(data->incr);
data->incr = NULL;
data->incrsize = 0;
}
/* Convert the X clipboard string to DOS format */
winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData));
/* Find out how much space needed when converted to UTF-16 */
int iUnicodeLen = MultiByteToWideChar(codepage, 0,
pszReturnData, -1, NULL, 0);
/* NOTE: iUnicodeLen includes space for null terminator */
pwszUnicodeStr = malloc(sizeof(wchar_t) * iUnicodeLen);
if (!pwszUnicodeStr) {
ErrorF("winClipboardFlushXEvents - SelectionNotify "
"malloc failed for pwszUnicodeStr, aborting.\n");
/* Abort */
goto winClipboardFlushXEvents_SelectionNotify_Done;
}
/* Do the actual conversion */
MultiByteToWideChar(codepage, 0,
pszReturnData, -1, pwszUnicodeStr, iUnicodeLen);
/* Allocate global memory for the X clipboard data */
hGlobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * iUnicodeLen);
free(pszReturnData);
/* Check that global memory was allocated */
if (!hGlobal) {
ErrorF("winClipboardFlushXEvents - SelectionNotify "
"GlobalAlloc failed, aborting: %08x\n", (unsigned int)GetLastError());
/* Abort */
goto winClipboardFlushXEvents_SelectionNotify_Done;
}
/* Obtain a pointer to the global memory */
pszGlobalData = GlobalLock(hGlobal);
if (pszGlobalData == NULL) {
ErrorF("winClipboardFlushXEvents - Could not lock global "
"memory for clipboard transfer\n");
/* Abort */
goto winClipboardFlushXEvents_SelectionNotify_Done;
}
/* Copy the returned string into the global memory */
wcscpy((wchar_t *)pszGlobalData, pwszUnicodeStr);
free(pwszUnicodeStr);
pwszUnicodeStr = NULL;
/* Release the pointer to the global memory */
GlobalUnlock(hGlobal);
pszGlobalData = NULL;
/* Push the selection data to the Windows clipboard */
SetClipboardData(CF_UNICODETEXT, hGlobal);
/* Flag that SetClipboardData has been called */
fSetClipboardData = FALSE;
/*
* NOTE: Do not try to free pszGlobalData, it is owned by
* Windows after the call to SetClipboardData ().
*/
winClipboardFlushXEvents_SelectionNotify_Done:
/* Free allocated resources */
free(pwszUnicodeStr);
if (hGlobal && pszGlobalData)
GlobalUnlock(hGlobal);
if (fSetClipboardData) {
SetClipboardData(CF_UNICODETEXT, NULL);
SetClipboardData(CF_TEXT, NULL);
}
return WIN_XEVENTS_NOTIFY_DATA;
}
/*
* Process any pending X events
*/
int
winClipboardFlushXEvents(HWND hwnd,
xcb_window_t iWindow, xcb_connection_t *conn,
ClipboardConversionData *data, ClipboardAtoms *atoms)
{
xcb_atom_t atomClipboard = atoms->atomClipboard;
xcb_atom_t atomUTF8String = atoms->atomUTF8String;
xcb_atom_t atomCompoundText = atoms->atomCompoundText;
xcb_atom_t atomTargets = atoms->atomTargets;
/* Process all pending events */
xcb_generic_event_t *event;
while ((event = xcb_poll_for_event(conn))) {
const char *pszGlobalData = NULL;
HGLOBAL hGlobal = NULL;
char *pszConvertData = NULL;
BOOL fAbort = FALSE;
BOOL fCloseClipboard = FALSE;
/* Branch on the event type */
switch (event->response_type & ~0x80) {
case XCB_SELECTION_REQUEST:
{
char *xtpText_value = NULL;
int xtpText_nitems;
UINT codepage;
xcb_selection_request_event_t *selection_request = (xcb_selection_request_event_t *)event;
{
char *pszAtomName = NULL;
winDebug("SelectionRequest - target %d\n", selection_request->target);
pszAtomName = get_atom_name(conn, selection_request->target);
winDebug("SelectionRequest - Target atom name %s\n", pszAtomName);
free(pszAtomName);
}
/* Abort if invalid target type */
if (selection_request->target != XCB_ATOM_STRING
&& selection_request->target != atomUTF8String
&& selection_request->target != atomCompoundText
&& selection_request->target != atomTargets) {
/* Abort */
fAbort = TRUE;
goto winClipboardFlushXEvents_SelectionRequest_Done;
}
/* Handle targets type of request */
if (selection_request->target == atomTargets) {
xcb_atom_t atomTargetArr[] =
{
atomTargets,
atomUTF8String,
XCB_ATOM_STRING,
// atomCompoundText, not implemented (yet?)
};
/* Try to change the property */
xcb_void_cookie_t cookie = xcb_change_property_checked(conn,
XCB_PROP_MODE_REPLACE,
selection_request->requestor,
selection_request->property,
XCB_ATOM_ATOM,
32,
ARRAY_SIZE(atomTargetArr),
(unsigned char *) atomTargetArr);
xcb_generic_error_t *error;
if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"xcb_change_property failed");
free(error);
}
/* Setup selection notify xevent */
xcb_selection_notify_event_t eventSelection;
eventSelection.response_type = XCB_SELECTION_NOTIFY;
eventSelection.requestor = selection_request->requestor;
eventSelection.selection = selection_request->selection;
eventSelection.target = selection_request->target;
eventSelection.property = selection_request->property;
eventSelection.time = selection_request->time;
/*
* Notify the requesting window that
* the operation has completed
*/
cookie = xcb_send_event_checked(conn, FALSE,
eventSelection.requestor,
0, (char *) &eventSelection);
if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"xcb_send_event() failed\n");
}
break;
}
/* Close clipboard if we have it open already */
if (GetOpenClipboardWindow() == hwnd) {
CloseClipboard();
}
/* Access the clipboard */
if (!OpenClipboard(hwnd)) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"OpenClipboard () failed: %08x\n", (unsigned int)GetLastError());
/* Abort */
fAbort = TRUE;
goto winClipboardFlushXEvents_SelectionRequest_Done;
}
/* Indicate that clipboard was opened */
fCloseClipboard = TRUE;
/* Check that clipboard format is available */
if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) {
static int count; /* Hack to stop acroread spamming the log */
static HWND lasthwnd; /* I've not seen any other client get here repeatedly? */
if (hwnd != lasthwnd)
count = 0;
count++;
if (count < 6)
ErrorF("winClipboardFlushXEvents - CF_UNICODETEXT is not "
"available from Win32 clipboard. Aborting %d.\n",
count);
lasthwnd = hwnd;
/* Abort */
fAbort = TRUE;
goto winClipboardFlushXEvents_SelectionRequest_Done;
}
/* Get a pointer to the clipboard text, in desired format */
/* Retrieve clipboard data */
hGlobal = GetClipboardData(CF_UNICODETEXT);
if (!hGlobal) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"GetClipboardData () failed: %08x\n", (unsigned int)GetLastError());
/* Abort */
fAbort = TRUE;
goto winClipboardFlushXEvents_SelectionRequest_Done;
}
pszGlobalData = (char *) GlobalLock(hGlobal);
/* Convert to target string style */
if (selection_request->target == XCB_ATOM_STRING) {
codepage = CP_ISO_8559_1; // code page identifier for iso-8559-1
} else if (selection_request->target == atomUTF8String) {
codepage = CP_UTF8; // code page identifier for utf8
} else if (selection_request->target == atomCompoundText) {
// COMPOUND_TEXT is complex, not (yet) implemented
pszGlobalData = "COMPOUND_TEXT not implemented";
codepage = CP_UTF8; // code page identifier for utf8
}
/* Convert the UTF16 string to required encoding */
int iConvertDataLen = WideCharToMultiByte(codepage, 0,
(LPCWSTR) pszGlobalData, -1,
NULL, 0, NULL, NULL);
/* NOTE: iConvertDataLen includes space for null terminator */
pszConvertData = malloc(iConvertDataLen);
WideCharToMultiByte(codepage, 0,
(LPCWSTR) pszGlobalData, -1,
pszConvertData, iConvertDataLen, NULL, NULL);
/* Convert DOS string to UNIX string */
winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData));
xtpText_value = strdup(pszConvertData);
xtpText_nitems = strlen(pszConvertData);
/* data will fit into a single X request? (INCR not yet supported) */
{
uint32_t maxreqsize = xcb_get_maximum_request_length(conn);
/* covert to bytes and allow for allow for X_ChangeProperty request */
maxreqsize = maxreqsize*4 - 24;
if (xtpText_nitems > maxreqsize) {
ErrorF("winClipboardFlushXEvents - clipboard data size %d greater than maximum %u\n", xtpText_nitems, maxreqsize);
/* Abort */
fAbort = TRUE;
goto winClipboardFlushXEvents_SelectionRequest_Done;
}
}
/* Copy the clipboard text to the requesting window */
xcb_void_cookie_t cookie = xcb_change_property_checked(conn,
XCB_PROP_MODE_REPLACE,
selection_request->requestor,
selection_request->property,
selection_request->target,
8,
xtpText_nitems, xtpText_value);
xcb_generic_error_t *error;
if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"xcb_change_property failed\n");
/* Abort */
fAbort = TRUE;
goto winClipboardFlushXEvents_SelectionRequest_Done;
}
/* Free the converted string */
free(pszConvertData);
pszConvertData = NULL;
/* Release the clipboard data */
GlobalUnlock(hGlobal);
pszGlobalData = NULL;
fCloseClipboard = FALSE;
CloseClipboard();
/* Clean up */
free(xtpText_value);
xtpText_value = NULL;
/* Setup selection notify event */
xcb_selection_notify_event_t eventSelection;
eventSelection.response_type = XCB_SELECTION_NOTIFY;
eventSelection.requestor = selection_request->requestor;
eventSelection.selection = selection_request->selection;
eventSelection.target = selection_request->target;
eventSelection.property = selection_request->property;
eventSelection.time = selection_request->time;
/* Notify the requesting window that the operation has completed */
cookie = xcb_send_event_checked(conn, FALSE,
eventSelection.requestor,
0, (char *) &eventSelection);
if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"xcb_send_event() failed\n");
/* Abort */
fAbort = TRUE;
goto winClipboardFlushXEvents_SelectionRequest_Done;
}
winClipboardFlushXEvents_SelectionRequest_Done:
/* Free allocated resources */
if (xtpText_value) {
free(xtpText_value);
}
if (pszConvertData)
free(pszConvertData);
if (hGlobal && pszGlobalData)
GlobalUnlock(hGlobal);
/*
* Send a SelectionNotify event to the requesting
* client when we abort.
*/
if (fAbort) {
/* Setup selection notify event */
eventSelection.response_type = XCB_SELECTION_NOTIFY;
eventSelection.requestor = selection_request->requestor;
eventSelection.selection = selection_request->selection;
eventSelection.target = selection_request->target;
eventSelection.property = XCB_NONE;
eventSelection.time = selection_request->time;
/* Notify the requesting window that the operation is complete */
cookie = xcb_send_event_checked(conn, FALSE,
eventSelection.requestor,
0, (char *) &eventSelection);
if ((error = xcb_request_check(conn, cookie))) {
/*
* Should not be a problem if XSendEvent fails because
* the client may simply have exited.
*/
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"xcb_send_event() failed for abort event.\n");
}
}
/* Close clipboard if it was opened */
if (fCloseClipboard) {
fCloseClipboard = FALSE;
CloseClipboard();
}
break;
}
case XCB_SELECTION_NOTIFY:
{
xcb_selection_notify_event_t *selection_notify = (xcb_selection_notify_event_t *)event;
winDebug("winClipboardFlushXEvents - SelectionNotify\n");
{
char *pszAtomName;
pszAtomName = get_atom_name(conn, selection_notify->selection);
winDebug("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n", pszAtomName);
free(pszAtomName);
}
/*
SelectionNotify with property of XCB_NONE indicates either:
(i) Generated by the X server if no owner for the specified selection exists
(perhaps it's disappeared on us mid-transaction), or
(ii) Sent by the selection owner when the requested selection conversion could
not be performed or server errors prevented the conversion data being returned
*/
if (selection_notify->property == XCB_NONE) {
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
"Conversion to format %d refused.\n",
selection_notify->target);
return WIN_XEVENTS_FAILED;
}
if (selection_notify->target == atomTargets) {
return winClipboardSelectionNotifyTargets(hwnd, iWindow, conn, data, atoms);
}
return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms);
}
case XCB_SELECTION_CLEAR:
winDebug("SelectionClear - doing nothing\n");
break;
case XCB_PROPERTY_NOTIFY:
{
xcb_property_notify_event_t *property_notify = (xcb_property_notify_event_t *)event;
/* If INCR is in progress, collect the data */
if (data->incr &&
(property_notify->atom == atoms->atomLocalProperty) &&
(property_notify->state == XCB_PROPERTY_NEW_VALUE))
return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms);
break;
}
case XCB_MAPPING_NOTIFY:
break;
case 0:
/* This is just laziness rather than making sure we used _checked everywhere */
{
xcb_generic_error_t *err = (xcb_generic_error_t *)event;
ErrorF("winClipboardFlushXEvents - Error code: %i, ID: 0x%08x, "
"Major opcode: %i, Minor opcode: %i\n",
err->error_code, err->resource_id,
err->major_code, err->minor_code);
}
break;
default:
if ((event->response_type & ~0x80) == XCB_XFIXES_SELECTION_EVENT_SET_SELECTION_OWNER + xfixes_event_base) {
xcb_xfixes_selection_notify_event_t *e = (xcb_xfixes_selection_notify_event_t *)event;
winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n");
/* Save selection owners for monitored selections, ignore other selections */
if ((e->selection == XCB_ATOM_PRIMARY) && fPrimarySelection) {
MonitorSelection(e, CLIP_OWN_PRIMARY);
}
else if (e->selection == atomClipboard) {
MonitorSelection(e, CLIP_OWN_CLIPBOARD);
}
else
break;
/* Selection is being disowned */
if (e->owner == XCB_NONE) {
winDebug("winClipboardFlushXEvents - No window, returning.\n");
break;
}
/*
XXX: there are all kinds of wacky edge cases we might need here:
- we own windows clipboard, but neither PRIMARY nor CLIPBOARD have an owner, so we should disown it?
- root window is taking ownership?
*/
/* If we are the owner of the most recently owned selection, don't go all recursive :) */
if ((lastOwnedSelectionIndex != CLIP_OWN_NONE) &&
(s_iOwners[lastOwnedSelectionIndex] == iWindow)) {
winDebug("winClipboardFlushXEvents - Ownership changed to us, aborting.\n");
break;
}
/* Close clipboard if we have it open already (possible? correct??) */
if (GetOpenClipboardWindow() == hwnd) {
CloseClipboard();
}
/* Access the Windows clipboard */
if (!OpenClipboard(hwnd)) {
ErrorF("winClipboardFlushXEvents - OpenClipboard () failed: %08x\n",
(int) GetLastError());
break;
}
/* Take ownership of the Windows clipboard */
if (!EmptyClipboard()) {
ErrorF("winClipboardFlushXEvents - EmptyClipboard () failed: %08x\n",
(int) GetLastError());
break;
}
/* Advertise regular text and unicode */
SetClipboardData(CF_UNICODETEXT, NULL);
SetClipboardData(CF_TEXT, NULL);
/* Release the clipboard */
if (!CloseClipboard()) {
ErrorF("winClipboardFlushXEvents - CloseClipboard () failed: %08x\n",
(int) GetLastError());
break;
}
}
/* XCB_XFIXES_SELECTION_EVENT_SELECTION_WINDOW_DESTROY */
/* XCB_XFIXES_SELECTION_EVENT_SELECTION_CLIENT_CLOSE */
else {
ErrorF("winClipboardFlushXEvents - unexpected event type %d\n",
event->response_type);
}
break;
}
/* I/O errors etc. */
{
int e = xcb_connection_has_error(conn);
if (e) {
ErrorF("winClipboardFlushXEvents - Fatal error %d on xcb connection\n", e);
break;
}
}
}
return WIN_XEVENTS_SUCCESS;
}

View file

@ -0,0 +1,85 @@
/*
*Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
*Copyright (C) Colin Harrison 2005-2008
*
*Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
*"Software"), to deal in the Software without restriction, including
*without limitation the rights to use, copy, modify, merge, publish,
*distribute, sublicense, and/or sell copies of the Software, and to
*permit persons to whom the Software is furnished to do so, subject to
*the following conditions:
*
*The above copyright notice and this permission notice shall be
*included in all copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*Except as contained in this notice, the name of the copyright holder(s)
*and author(s) shall not be used in advertising or otherwise to promote
*the sale, use or other dealings in this Software without prior written
*authorization from the copyright holder(s) and author(s).
*
* Authors: Harold L Hunt II
* Colin Harrison
*/
#ifdef HAVE_XWIN_CONFIG_H
#include <xwin-config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "winclipboard.h"
/*
* Main function
*/
int
main (int argc, char *argv[])
{
int i;
char *pszDisplay = NULL;
/* Parse command-line parameters */
for (i = 1; i < argc; ++i)
{
/* Look for -display "display_name" or --display "display_name" */
if (i < argc - 1
&& (!strcmp (argv[i], "-display")
|| !strcmp (argv[i], "--display")))
{
/* Grab a pointer to the display parameter */
pszDisplay = argv[i + 1];
/* Skip the display argument */
i++;
continue;
}
/* Look for -noprimary */
if (!strcmp (argv[i], "-noprimary"))
{
fPrimarySelection = 0;
continue;
}
/* Yack when we find a parameter that we don't know about */
printf ("Unknown parameter: %s\nExiting.\n", argv[i]);
exit (1);
}
winClipboardProc(pszDisplay, NULL /* Use XAUTHORITY for auth data */);
return 0;
}

View file

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