hw/xwin: xcbify clipboard integration

Convert clipboard integration code from libX11 to xcb

This drops support for COMPOUND_TEXT.  Presumably some ancient
(pre-2000) clients exist which support that, but not UTF8_STRING, but we
don't have an example to test with. (Given the nature of the thing, the
users of those clients probably work in CJK languages)

Supporting COMPOUND_TEXT would also involve writing (or extracting from
Xlib) support for the ISO 2022 encoding.

v2:
Fix the length of text property set by a SelectionRequest

The length of the text property is not neccessarily the same as the
length of the clipboard text before it is d2u converted (specifically,
if that contains any '\r\n' sequences, it will be shorter as they are
now just '\n')
This commit is contained in:
Jon Turney 2018-06-30 16:00:16 +01:00
parent f4936de73c
commit 9e02e023b0
10 changed files with 490 additions and 656 deletions

View File

@ -2081,7 +2081,7 @@ if test "x$XWIN" = xyes; then
AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support])
AC_CHECK_TOOL(WINDRES, windres)
PKG_CHECK_MODULES([XWINMODULES],[x11 xau xdmcp xfixes x11-xcb xcb-aux xcb-composite xcb-image xcb-ewmh xcb-icccm])
PKG_CHECK_MODULES([XWINMODULES],[x11 xau xdmcp x11-xcb xcb-aux xcb-composite xcb-image xcb-ewmh xcb-icccm xcb-xfixes])
if test "x$WINDOWSDRI" = xauto; then
PKG_CHECK_EXISTS([windowsdriproto], [WINDOWSDRI=yes], [WINDOWSDRI=no])

View File

@ -31,8 +31,9 @@
#ifndef WINCLIPBOARD_INTERNAL_H
#define WINCLIPBOARD_INTERNAL_H
/* X headers */
#include <X11/Xlib.h>
#include <xcb/xproto.h>
#include <X11/Xfuncproto.h> // for _X_ATTRIBUTE_PRINTF
#include <X11/Xdefs.h> // for Bool type
/* Windows headers */
#include <X11/Xwindows.h>
@ -67,15 +68,14 @@ void
* winclipboardthread.c
*/
typedef struct
{
Atom atomClipboard;
Atom atomLocalProperty;
Atom atomUTF8String;
Atom atomCompoundText;
Atom atomTargets;
Atom atomIncr;
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;
/*
@ -89,8 +89,8 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
typedef struct
{
Display *pClipboardDisplay;
Window iClipboardWindow;
xcb_connection_t *pClipboardDisplay;
xcb_window_t iClipboardWindow;
ClipboardAtoms *atoms;
} ClipboardWindowCreationParams;
@ -100,17 +100,17 @@ typedef struct
typedef struct
{
Atom *targetList;
xcb_atom_t *targetList;
unsigned char *incr;
unsigned long int incrsize;
} ClipboardConversionData;
int
winClipboardFlushXEvents(HWND hwnd,
Window iWindow, Display * pDisplay, ClipboardConversionData *data, ClipboardAtoms *atom);
xcb_window_t iWindow, xcb_connection_t * pDisplay,
ClipboardConversionData *data, ClipboardAtoms *atoms);
Atom
xcb_atom_t
winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms);
void

View File

@ -12,8 +12,10 @@ xwin_clipboard = static_library(
include_directories: inc,
c_args: '-DHAVE_XWIN_CONFIG_H',
dependencies: [
dependency('x11'),
dependency('xfixes'),
dependency('xcb'),
dependency('xcb-aux'),
dependency('xcb-icccm'),
dependency('xcb-xfixes'),
socket_dep,
],
)
@ -28,7 +30,6 @@ executable(
srcs_xwinclip,
link_with: xwin_clipboard,
link_args: ['-lgdi32', '-lpthread'],
dependencies: [dependency('x11')],
install: true,
)

View File

@ -32,15 +32,6 @@
#include <xwin-config.h>
#endif
/*
* Including any server header might define the macro _XSERVER64 on 64 bit machines.
* That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
* So let's undef that macro if necessary.
*/
#ifdef _XSERVER64
#undef _XSERVER64
#endif
#include <stdlib.h>
#include "internal.h"

View File

@ -36,19 +36,9 @@
#define HAS_WINSOCK 1
#endif
/*
* Including any server header might define the macro _XSERVER64 on 64 bit machines.
* That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
* So let's undef that macro if necessary.
*/
#ifdef _XSERVER64
#undef _XSERVER64
#endif
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <setjmp.h>
#include <pthread.h>
#include <sys/param.h> // for MAX() macro
@ -58,8 +48,11 @@
#include <errno.h>
#endif
#include <X11/Xatom.h>
#include <X11/extensions/Xfixes.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xfixes.h>
#include "winclipboard.h"
#include "internal.h"
@ -77,9 +70,6 @@
*/
static HWND g_hwndClipboard = NULL;
static jmp_buf g_jmpEntry;
static XIOErrorHandler g_winClipboardOldIOErrorHandler;
static pthread_t g_winClipboardProcThread;
int xfixes_event_base;
int xfixes_error_base;
@ -89,13 +79,23 @@ int xfixes_error_base;
*/
static HWND
winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAtoms *atoms);
winClipboardCreateMessagingWindow(xcb_connection_t *conn, xcb_window_t iWindow, ClipboardAtoms *atoms);
static int
winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr);
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;
static int
winClipboardIOErrorHandler(Display * pDisplay);
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
@ -104,13 +104,12 @@ static int
*/
Bool
winClipboardProc(char *szDisplay)
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
@ -118,54 +117,27 @@ winClipboardProc(char *szDisplay)
#endif
fd_set fdsRead;
int iMaxDescriptor;
Display *pDisplay = NULL;
Window iWindow = None;
xcb_connection_t *conn;
xcb_window_t iWindow = XCB_NONE;
int iSelectError;
Bool fShutdown = FALSE;
static Bool fErrorHandlerSet = FALSE;
ClipboardConversionData data;
int screen;
winDebug("winClipboardProc - Hello\n");
/* Allow multiple threads to access Xlib */
if (XInitThreads() == 0) {
ErrorF("winClipboardProc - XInitThreads failed.\n");
goto winClipboardProc_Exit;
}
/* See if X supports the current locale */
if (XSupportsLocale() == False) {
ErrorF("winClipboardProc - Warning: Locale not supported by X.\n");
}
g_winClipboardProcThread = pthread_self();
/* Set error handler */
if (!fErrorHandlerSet) {
XSetErrorHandler(winClipboardErrorHandler);
g_winClipboardOldIOErrorHandler =
XSetIOErrorHandler(winClipboardIOErrorHandler);
fErrorHandlerSet = TRUE;
}
/* Set jump point for Error exits */
if (setjmp(g_jmpEntry)) {
ErrorF("winClipboardProc - setjmp returned for IO Error Handler.\n");
goto winClipboardProc_Done;
}
/* Make sure that the display opened */
pDisplay = XOpenDisplay(szDisplay);
if (pDisplay == NULL) {
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 - XOpenDisplay () returned and "
ErrorF("winClipboardProc - xcb_connect () returned and "
"successfully opened the display.\n");
/* Get our connection number */
iConnectionNumber = ConnectionNumber(pDisplay);
iConnectionNumber = xcb_get_file_descriptor(conn);
#ifdef HAS_DEVWINDOWS
/* Open a file descriptor for the windows message queue */
@ -181,56 +153,75 @@ winClipboardProc(char *szDisplay)
iMaxDescriptor = iConnectionNumber + 1;
#endif
if (!XFixesQueryExtension(pDisplay, &xfixes_event_base, &xfixes_error_base))
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 = XInternAtom(pDisplay, "CLIPBOARD", False);
atoms.atomLocalProperty = XInternAtom (pDisplay, "CYGX_CUT_BUFFER", False);
atoms.atomUTF8String = XInternAtom (pDisplay, "UTF8_STRING", False);
atoms.atomCompoundText = XInternAtom (pDisplay, "COMPOUND_TEXT", False);
atoms.atomTargets = XInternAtom (pDisplay, "TARGETS", False);
atoms.atomIncr = XInternAtom (pDisplay, "INCR", False);
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 = XCreateSimpleWindow(pDisplay,
DefaultRootWindow(pDisplay),
1, 1,
500, 500,
0,
BlackPixel(pDisplay, 0),
BlackPixel(pDisplay, 0));
if (iWindow == 0) {
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;
}
XStoreName(pDisplay, iWindow, "xwinclip");
xcb_icccm_set_wm_name(conn, iWindow, XCB_ATOM_STRING, 8, strlen("xwinclip"), "xwinclip");
/* Select event types to watch */
if (XSelectInput(pDisplay, iWindow, PropertyChangeMask) == BadWindow)
ErrorF("winClipboardProc - XSelectInput generated BadWindow "
"on messaging window\n");
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);
}
XFixesSelectSelectionInput (pDisplay,
iWindow,
XA_PRIMARY,
XFixesSetSelectionOwnerNotifyMask |
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask);
XFixesSelectSelectionInput (pDisplay,
iWindow,
atoms.atomClipboard,
XFixesSetSelectionOwnerNotifyMask |
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask);
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(pDisplay, iWindow, &atoms);
hwnd = winClipboardCreateMessagingWindow(conn, iWindow, &atoms);
/* Save copy of HWND */
g_hwndClipboard = hwnd;
@ -238,20 +229,18 @@ winClipboardProc(char *szDisplay)
/* 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) {
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 */
iReturn = XSetSelectionOwner(pDisplay, atoms.atomClipboard,
iWindow, CurrentTime);
if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, atoms.atomClipboard) != iWindow) {
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;
}
}
@ -263,8 +252,7 @@ winClipboardProc(char *szDisplay)
while (1) {
/* Process X events */
winClipboardFlushXEvents(hwnd,
iWindow, pDisplay, &data, &atoms);
winClipboardFlushXEvents(hwnd, iWindow, conn, &data, &atoms);
/* Process Windows messages */
if (!winClipboardFlushWindowsMessageQueue(hwnd)) {
@ -274,7 +262,7 @@ winClipboardProc(char *szDisplay)
}
/* We need to ensure that all pending requests are sent */
XFlush(pDisplay);
xcb_flush(conn);
/* Setup the file descriptor set */
/*
@ -346,7 +334,6 @@ winClipboardProc(char *szDisplay)
#endif
}
winClipboardProc_Exit:
/* broke out of while loop on a shutdown message */
fShutdown = TRUE;
@ -357,12 +344,13 @@ winClipboardProc(char *szDisplay)
}
/* Close our X window */
if (pDisplay && iWindow) {
iReturn = XDestroyWindow(pDisplay, iWindow);
if (iReturn == BadWindow)
ErrorF("winClipboardProc - XDestroyWindow returned BadWindow.\n");
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
@ -371,26 +359,15 @@ winClipboardProc(char *szDisplay)
close(fdMessageQueue);
#endif
#if 0
/*
* FIXME: XCloseDisplay hangs if we call it
*
* XCloseDisplay() calls XSync(), so any outstanding errors are reported.
* If we are built into the server, this can deadlock if the server is
* in the process of exiting and waiting for this thread to exit.
* 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.
*/
/* Discard any remaining events */
XSync(pDisplay, TRUE);
/* Select event types to watch */
XSelectInput(pDisplay, DefaultRootWindow(pDisplay), None);
/* Close our X display */
if (pDisplay) {
XCloseDisplay(pDisplay);
if (!xcb_connection_has_error(conn)) {
/* Close our X display */
xcb_disconnect(conn);
}
#endif
/* global clipboard variable reset */
g_hwndClipboard = NULL;
@ -403,7 +380,7 @@ winClipboardProc(char *szDisplay)
*/
static HWND
winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAtoms *atoms)
winClipboardCreateMessagingWindow(xcb_connection_t *conn, xcb_window_t iWindow, ClipboardAtoms *atoms)
{
WNDCLASSEX wc;
ClipboardWindowCreationParams cwcp;
@ -425,7 +402,7 @@ winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAt
RegisterClassEx(&wc);
/* Information to be passed to WM_CREATE */
cwcp.pClipboardDisplay = pDisplay;
cwcp.pClipboardDisplay = conn;
cwcp.iClipboardWindow = iWindow;
cwcp.atoms = atoms;
@ -453,42 +430,6 @@ winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAt
return hwnd;
}
/*
* winClipboardErrorHandler - Our application specific error handler
*/
static int
winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr)
{
char pszErrorMsg[100];
XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg));
ErrorF("winClipboardErrorHandler - ERROR: \n\t%s\n"
"\tSerial: %lu, Request Code: %d, Minor Code: %d\n",
pszErrorMsg, pErr->serial, pErr->request_code, pErr->minor_code);
return 0;
}
/*
* winClipboardIOErrorHandler - Our application specific IO error handler
*/
static int
winClipboardIOErrorHandler(Display * pDisplay)
{
ErrorF("winClipboardIOErrorHandler!\n");
if (pthread_equal(pthread_self(), g_winClipboardProcThread)) {
/* Restart at the main entry point */
longjmp(g_jmpEntry, 2);
}
if (g_winClipboardOldIOErrorHandler)
g_winClipboardOldIOErrorHandler(pDisplay);
return 0;
}
void
winClipboardWindowDestroy(void)
{

View File

@ -27,7 +27,10 @@
#ifndef WINCLIPBOARD_H
#define WINCLIPBOARD_H
Bool winClipboardProc(char *szDisplay);
#include <X11/Xdefs.h> // for Bool type
#include <xcb/xcb.h>
Bool winClipboardProc(char *szDisplay, xcb_auth_info_t *auth_info);
void winFixClipboardChain(void);

View File

@ -36,20 +36,12 @@
#include <xwin-config.h>
#endif
/*
* Including any server header might define the macro _XSERVER64 on 64 bit machines.
* That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
* So let's undef that macro if necessary.
*/
#ifdef _XSERVER64
#undef _XSERVER64
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <limits.h>
#include <X11/Xatom.h>
#include <xcb/xproto.h>
#include <xcb/xcb_aux.h>
#include "internal.h"
#include "winclipboard.h"
@ -65,7 +57,7 @@
*/
static int
winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay,
winProcessXEventsTimeout(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn,
ClipboardConversionData *data, ClipboardAtoms *atoms, int iTimeoutSec)
{
int iConnNumber;
@ -76,7 +68,7 @@ winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay,
iTimeoutSec);
/* Get our connection number */
iConnNumber = ConnectionNumber(pDisplay);
iConnNumber = xcb_get_file_descriptor(conn);
/* Loop for X events */
while (1) {
@ -84,7 +76,7 @@ winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay,
long remainingTime;
/* Process X events */
iReturn = winClipboardFlushXEvents(hwnd, iWindow, pDisplay, data, atoms);
iReturn = winClipboardFlushXEvents(hwnd, iWindow, conn, data, atoms);
winDebug("winProcessXEventsTimeout () - winClipboardFlushXEvents returned %d\n", iReturn);
@ -94,7 +86,7 @@ winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay,
}
/* We need to ensure that all pending requests are sent */
XFlush(pDisplay);
xcb_flush(conn);
/* Setup the file descriptor set */
FD_ZERO(&fdsRead);
@ -136,8 +128,8 @@ winProcessXEventsTimeout(HWND hwnd, Window iWindow, Display * pDisplay,
LRESULT CALLBACK
winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static Display *pDisplay;
static Window iWindow;
static xcb_connection_t *conn;
static xcb_window_t iWindow;
static ClipboardAtoms *atoms;
static Bool fRunning;
@ -166,7 +158,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
winDebug("winClipboardWindowProc - WM_CREATE\n");
pDisplay = cwcp->pClipboardDisplay;
conn = cwcp->pClipboardDisplay;
iWindow = cwcp->iClipboardWindow;
atoms = cwcp->atoms;
fRunning = TRUE;
@ -177,7 +169,8 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_CLIPBOARDUPDATE:
{
int iReturn;
xcb_generic_error_t *error;
xcb_void_cookie_t cookie_set;
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Enter\n");
@ -211,6 +204,9 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
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");
@ -219,33 +215,33 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
* We need to make sure that the X Server has processed
* previous XSetSelectionOwner messages.
*/
XSync(pDisplay, FALSE);
xcb_aux_sync(conn);
winDebug("winClipboardWindowProc - XSync done.\n");
/* Release PRIMARY selection if owned */
iReturn = XGetSelectionOwner(pDisplay, XA_PRIMARY);
if (iReturn == iWindow) {
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"PRIMARY selection is owned by us.\n");
XSetSelectionOwner(pDisplay, XA_PRIMARY, None, CurrentTime);
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);
}
else if (BadWindow == iReturn || BadAtom == iReturn)
ErrorF("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"XGetSelectionOwner failed for PRIMARY: %d\n",
iReturn);
/* Release CLIPBOARD selection if owned */
iReturn = XGetSelectionOwner(pDisplay, atoms->atomClipboard);
if (iReturn == iWindow) {
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"CLIPBOARD selection is owned by us, releasing\n");
XSetSelectionOwner(pDisplay, atoms->atomClipboard, None, CurrentTime);
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);
}
else if (BadWindow == iReturn || BadAtom == iReturn)
ErrorF("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"XGetSelectionOwner failed for CLIPBOARD: %d\n",
iReturn);
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Exit\n");
@ -253,26 +249,24 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
}
/* Reassert ownership of PRIMARY */
iReturn = XSetSelectionOwner(pDisplay,
XA_PRIMARY, iWindow, CurrentTime);
if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) {
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");
}
else {
free(error);
} else {
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
"Reasserted ownership of PRIMARY\n");
}
/* Reassert ownership of the CLIPBOARD */
iReturn = XSetSelectionOwner(pDisplay,
atoms->atomClipboard, iWindow, CurrentTime);
if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, atoms->atomClipboard) != iWindow) {
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 - "
@ -280,7 +274,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
}
/* Flush the pending SetSelectionOwner event now */
XFlush(pDisplay);
xcb_flush(conn);
}
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Exit\n");
return 0;
@ -317,7 +311,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int iReturn;
Bool pasted = FALSE;
Atom selection;
xcb_atom_t selection;
ClipboardConversionData data;
int best_target = 0;
@ -325,7 +319,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
(int)wParam);
selection = winClipboardGetLastOwnedSelectionAtom(atoms);
if (selection == None) {
if (selection == XCB_NONE) {
ErrorF("winClipboardWindowProc - no monitored selection is owned\n");
goto fake_paste;
}
@ -333,11 +327,8 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
winDebug("winClipboardWindowProc - requesting targets for selection from owner\n");
/* Request the selection's supported conversion targets */
XConvertSelection(pDisplay,
selection,
atoms->atomTargets,
atoms->atomLocalProperty,
iWindow, CurrentTime);
xcb_convert_selection(conn, iWindow, selection, atoms->atomTargets,
atoms->atomLocalProperty, XCB_CURRENT_TIME);
/* Process X events */
data.incr = NULL;
@ -345,7 +336,7 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
iReturn = winProcessXEventsTimeout(hwnd,
iWindow,
pDisplay,
conn,
&data,
atoms,
WIN_POLL_TIMEOUT);
@ -360,17 +351,15 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
struct target_priority
{
Atom target;
xcb_atom_t target;
unsigned int priority;
};
struct target_priority target_priority_table[] =
{
#ifdef X_HAVE_UTF8_STRING
{ atoms->atomUTF8String, 0 },
#endif
{ atoms->atomCompoundText, 1 },
{ XA_STRING, 2 },
// { atoms->atomCompoundText, 1 }, not implemented (yet?)
{ XCB_ATOM_STRING, 2 },
};
int best_priority = INT_MAX;
@ -402,16 +391,13 @@ winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
winDebug("winClipboardWindowProc - requesting selection from owner\n");
/* Request the selection contents */
XConvertSelection(pDisplay,
selection,
best_target,
atoms->atomLocalProperty,
iWindow, CurrentTime);
xcb_convert_selection(conn, iWindow, selection, best_target,
atoms->atomLocalProperty, XCB_CURRENT_TIME);
/* Process X events */
iReturn = winProcessXEventsTimeout(hwnd,
iWindow,
pDisplay,
conn,
&data,
atoms,
WIN_POLL_TIMEOUT);

View File

@ -34,20 +34,11 @@
#include <xwin-config.h>
#endif
/*
* Including any server header might define the macro _XSERVER64 on 64 bit machines.
* That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
* So let's undef that macro if necessary.
*/
#ifdef _XSERVER64
#undef _XSERVER64
#endif
#include <limits.h>
#include <wchar.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xfixes.h>
#include <xcb/xcb.h>
#include <xcb/xfixes.h>
#include "winclipboard.h"
#include "internal.h"
@ -57,10 +48,12 @@
*/
#define CLIP_NUM_SELECTIONS 2
#define CLIP_OWN_NONE -1
#define CLIP_OWN_NONE -1
#define CLIP_OWN_PRIMARY 0
#define CLIP_OWN_CLIPBOARD 1
#define CP_ISO_8559_1 28591
/*
* Global variables
*/
@ -72,17 +65,17 @@ Bool fPrimarySelection = TRUE;
* Local variables
*/
static Window s_iOwners[CLIP_NUM_SELECTIONS] = { None, None };
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(XFixesSelectionNotifyEvent * e, unsigned int i)
MonitorSelection(xcb_xfixes_selection_notify_event_t * e, unsigned int i)
{
/* Look for owned -> not owned transition */
if (None == e->owner && None != s_iOwners[i]) {
if ((XCB_NONE == e->owner) && (XCB_NONE != s_iOwners[i])) {
unsigned int other_index;
winDebug("MonitorSelection - %s - Going from owned to not owned.\n",
@ -94,36 +87,36 @@ MonitorSelection(XFixesSelectionNotifyEvent * e, unsigned int i)
other_index = CLIP_OWN_CLIPBOARD;
if (i == CLIP_OWN_CLIPBOARD)
other_index = CLIP_OWN_PRIMARY;
if (None != s_iOwners[other_index])
if (XCB_NONE != s_iOwners[other_index])
lastOwnedSelectionIndex = other_index;
else
lastOwnedSelectionIndex = CLIP_OWN_NONE;
}
/* Save last owned selection */
if (None != e->owner) {
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 %lx\n",
winDebug("MonitorSelection - %s - Now owned by XID %x\n",
szSelectionNames[i], e->owner);
}
Atom
xcb_atom_t
winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms)
{
if (lastOwnedSelectionIndex == CLIP_OWN_NONE)
return None;
return XCB_NONE;
if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY)
return XA_PRIMARY;
return XCB_ATOM_PRIMARY;
if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD)
return atoms->atomClipboard;
return None;
return XCB_NONE;
}
@ -133,102 +126,116 @@ winClipboardInitMonitoredSelections(void)
/* Initialize static variables */
int i;
for (i = 0; i < CLIP_NUM_SELECTIONS; ++i)
s_iOwners[i] = None;
s_iOwners[i] = XCB_NONE;
lastOwnedSelectionIndex = CLIP_OWN_NONE;
}
static int
winClipboardSelectionNotifyTargets(HWND hwnd, Window iWindow, Display *pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms)
static char *get_atom_name(xcb_connection_t *conn, xcb_atom_t atom)
{
Atom type;
int format;
unsigned long nitems;
unsigned long after;
Atom *prop;
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 */
int iReturn = XGetWindowProperty(pDisplay,
iWindow,
atoms->atomLocalProperty,
0,
INT_MAX,
True,
AnyPropertyType,
&type,
&format,
&nitems,
&after,
(unsigned char **)&prop);
if (iReturn != Success) {
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
"XGetWindowProperty () failed, aborting: %d\n", iReturn);
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 {
int i;
data->targetList = malloc((nitems+1)*sizeof(Atom));
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++)
{
Atom atom = prop[i];
char *pszAtomName = XGetAtomName(pDisplay, atom);
data->targetList[i] = atom;
winDebug("winClipboardFlushXEvents - SelectionNotify - target[%d] %ld = %s\n", i, atom, pszAtomName);
XFree(pszAtomName);
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;
XFree(prop);
free(reply);
}
return WIN_XEVENTS_NOTIFY_TARGETS;
}
static int
winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms)
winClipboardSelectionNotifyData(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn, ClipboardConversionData *data, ClipboardAtoms *atoms)
{
Atom encoding;
xcb_atom_t encoding;
int format;
unsigned long int nitems;
unsigned long int after;
unsigned char *value;
XTextProperty xtpText = { 0 };
unsigned char *xtpText_value;
xcb_atom_t xtpText_encoding;
int xtpText_nitems;
Bool fSetClipboardData = TRUE;
int iReturn;
char **ppszTextList = NULL;
int iCount;
char *pszReturnData = NULL;
UINT codepage;
wchar_t *pwszUnicodeStr = NULL;
HGLOBAL hGlobal = NULL;
char *pszGlobalData = NULL;
/* Retrieve the selection data and delete the property */
iReturn = XGetWindowProperty(pDisplay,
iWindow,
atoms->atomLocalProperty,
0,
INT_MAX,
True,
AnyPropertyType,
&encoding,
&format,
&nitems,
&after,
&value);
if (iReturn != Success) {
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, aborting: %d\n", iReturn);
"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 = NULL;
char *pszAtomName;
winDebug("SelectionNotify - returned data %lu left %lu\n", nitems, after);
pszAtomName = XGetAtomName(pDisplay, encoding);
pszAtomName = get_atom_name(conn, encoding);
winDebug("Notify atom name %s\n", pszAtomName);
XFree(pszAtomName);
pszAtomName = NULL;
free(pszAtomName);
}
/* INCR reply indicates the start of a incremental transfer */
@ -244,10 +251,12 @@ winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, Cl
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;
xtpText.format = format; // 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;
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 */
@ -261,70 +270,34 @@ winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, Cl
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.format = format;
xtpText.nitems = nitems;
xtpText_value = value;
xtpText_encoding = encoding;
xtpText_nitems = nitems;
}
#ifdef X_HAVE_UTF8_STRING
/* Convert the text property to a text list */
iReturn = Xutf8TextPropertyToTextList(pDisplay,
&xtpText,
&ppszTextList, &iCount);
#endif
if (iReturn == Success || iReturn > 0) {
/* Conversion succeeded or some unconvertible characters */
if (ppszTextList != NULL) {
int i;
int 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 {
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
"X*TextPropertyToTextList list_return is NULL.\n");
pszReturnData = malloc(1);
pszReturnData[0] = '\0';
}
}
else {
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
"X*TextPropertyToTextList returned: ");
switch (iReturn) {
case XNoMemory:
ErrorF("XNoMemory\n");
break;
case XLocaleNotSupported:
ErrorF("XLocaleNotSupported\n");
break;
case XConverterNotFound:
ErrorF("XConverterNotFound\n");
break;
default:
ErrorF("%d\n", iReturn);
break;
}
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';
}
if (ppszTextList)
XFreeStringList(ppszTextList);
ppszTextList = NULL;
/* Free the data returned from XGetWindowProperty */
XFree(value);
value = NULL;
nitems = 0;
/* Free the data returned from xcb_get_property */
free(reply);
/* Free any INCR data */
if (data->incr) {
@ -336,9 +309,8 @@ winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, Cl
/* Convert the X clipboard string to DOS format */
winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData));
/* Find out how much space needed to convert MBCS to Unicode */
int iUnicodeLen = MultiByteToWideChar(CP_UTF8,
0,
/* 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 */
@ -352,15 +324,12 @@ winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, Cl
}
/* Do the actual conversion */
MultiByteToWideChar(CP_UTF8,
0,
pszReturnData,
-1, pwszUnicodeStr, iUnicodeLen);
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 */
@ -404,13 +373,6 @@ winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, Cl
winClipboardFlushXEvents_SelectionNotify_Done:
/* Free allocated resources */
if (ppszTextList)
XFreeStringList(ppszTextList);
if (value) {
XFree(value);
value = NULL;
nitems = 0;
}
free(pwszUnicodeStr);
if (hGlobal && pszGlobalData)
GlobalUnlock(hGlobal);
@ -427,105 +389,97 @@ winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, Cl
int
winClipboardFlushXEvents(HWND hwnd,
Window iWindow, Display * pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms)
xcb_window_t iWindow, xcb_connection_t *conn,
ClipboardConversionData *data, ClipboardAtoms *atoms)
{
Atom atomClipboard = atoms->atomClipboard;
Atom atomUTF8String = atoms->atomUTF8String;
Atom atomCompoundText = atoms->atomCompoundText;
Atom atomTargets = atoms->atomTargets;
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 */
while (XPending(pDisplay)) {
XTextProperty xtpText = { 0 };
XEvent event;
XSelectionEvent eventSelection;
char *pszGlobalData = NULL;
int iReturn;
xcb_generic_event_t *event;
while ((event = xcb_poll_for_event(conn))) {
const char *pszGlobalData = NULL;
HGLOBAL hGlobal = NULL;
XICCEncodingStyle xiccesStyle;
char *pszConvertData = NULL;
char *pszTextList[2] = { NULL };
Bool fAbort = FALSE;
Bool fCloseClipboard = FALSE;
/* Get the next event - will not block because one is ready */
XNextEvent(pDisplay, &event);
/* Branch on the event type */
switch (event.type) {
/*
* SelectionRequest
*/
switch (event->response_type & ~0x80) {
case XCB_SELECTION_REQUEST:
{
char *xtpText_value = NULL;
int xtpText_nitems;
UINT codepage;
case SelectionRequest:
xcb_selection_request_event_t *selection_request = (xcb_selection_request_event_t *)event;
{
char *pszAtomName = NULL;
winDebug("SelectionRequest - target %ld\n",
event.xselectionrequest.target);
winDebug("SelectionRequest - target %d\n", selection_request->target);
pszAtomName = XGetAtomName(pDisplay,
event.xselectionrequest.target);
pszAtomName = get_atom_name(conn, selection_request->target);
winDebug("SelectionRequest - Target atom name %s\n", pszAtomName);
XFree(pszAtomName);
pszAtomName = NULL;
free(pszAtomName);
}
/* Abort if invalid target type */
if (event.xselectionrequest.target != XA_STRING
&& event.xselectionrequest.target != atomUTF8String
&& event.xselectionrequest.target != atomCompoundText
&& event.xselectionrequest.target != atomTargets) {
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 (event.xselectionrequest.target == atomTargets) {
Atom atomTargetArr[] = { atomTargets,
atomCompoundText,
atomUTF8String,
XA_STRING
};
if (selection_request->target == atomTargets) {
xcb_atom_t atomTargetArr[] =
{
atomTargets,
atomUTF8String,
XCB_ATOM_STRING,
// atomCompoundText, not implemented (yet?)
};
/* Try to change the property */
iReturn = XChangeProperty(pDisplay,
event.xselectionrequest.requestor,
event.xselectionrequest.property,
XA_ATOM,
xcb_void_cookie_t cookie = xcb_change_property_checked(conn,
XCB_PROP_MODE_REPLACE,
selection_request->requestor,
selection_request->property,
XCB_ATOM_ATOM,
32,
PropModeReplace,
(unsigned char *) atomTargetArr,
ARRAY_SIZE(atomTargetArr));
if (iReturn == BadAlloc
|| iReturn == BadAtom
|| iReturn == BadMatch
|| iReturn == BadValue || iReturn == BadWindow) {
ARRAY_SIZE(atomTargetArr),
(unsigned char *) atomTargetArr);
xcb_generic_error_t *error;
if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"XChangeProperty failed: %d\n", iReturn);
"xcb_change_property failed");
free(error);
}
/* 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;
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
*/
iReturn = XSendEvent(pDisplay,
eventSelection.requestor,
False, 0L, (XEvent *) &eventSelection);
if (iReturn == BadValue || iReturn == BadWindow) {
cookie = xcb_send_event_checked(conn, FALSE,
eventSelection.requestor,
0, (char *) &eventSelection);
if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"XSendEvent () failed\n");
"xcb_send_event() failed\n");
}
break;
}
@ -567,18 +521,6 @@ winClipboardFlushXEvents(HWND hwnd,
goto winClipboardFlushXEvents_SelectionRequest_Done;
}
/* Setup the string style */
if (event.xselectionrequest.target == XA_STRING)
xiccesStyle = XStringStyle;
#ifdef X_HAVE_UTF8_STRING
else if (event.xselectionrequest.target == atomUTF8String)
xiccesStyle = XUTF8StringStyle;
#endif
else if (event.xselectionrequest.target == atomCompoundText)
xiccesStyle = XCompoundTextStyle;
else
xiccesStyle = XStringStyle;
/* Get a pointer to the clipboard text, in desired format */
/* Retrieve clipboard data */
hGlobal = GetClipboardData(CF_UNICODETEXT);
@ -593,41 +535,61 @@ winClipboardFlushXEvents(HWND hwnd,
}
pszGlobalData = (char *) GlobalLock(hGlobal);
/* Convert the Unicode string to UTF8 (MBCS) */
int iConvertDataLen = WideCharToMultiByte(CP_UTF8,
0,
(LPCWSTR) pszGlobalData,
-1, NULL, 0, NULL, NULL);
/* 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(CP_UTF8,
0,
(LPCWSTR) pszGlobalData,
-1,
pszConvertData,
iConvertDataLen, NULL, NULL);
WideCharToMultiByte(codepage, 0,
(LPCWSTR) pszGlobalData, -1,
pszConvertData, iConvertDataLen, NULL, NULL);
/* Convert DOS string to UNIX string */
winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData));
/* Setup our text list */
pszTextList[0] = pszConvertData;
pszTextList[1] = NULL;
xtpText_value = strdup(pszConvertData);
xtpText_nitems = strlen(pszConvertData);
/* Initialize the text property */
xtpText.value = NULL;
xtpText.nitems = 0;
/* data will fit into a single X request? (INCR not yet supported) */
{
uint32_t maxreqsize = xcb_get_maximum_request_length(conn);
/* Create the text property from the text list */
#ifdef X_HAVE_UTF8_STRING
iReturn = Xutf8TextListToTextProperty(pDisplay,
pszTextList,
1, xiccesStyle, &xtpText);
#endif
/* covert to bytes and allow for allow for X_ChangeProperty request */
maxreqsize = maxreqsize*4 - 24;
if (iReturn == XNoMemory || iReturn == XLocaleNotSupported) {
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 - "
"X*TextListToTextProperty failed: %d\n", iReturn);
"xcb_change_property failed\n");
/* Abort */
fAbort = TRUE;
@ -638,43 +600,6 @@ winClipboardFlushXEvents(HWND hwnd,
free(pszConvertData);
pszConvertData = NULL;
/* data will fit into a single X request (INCR not yet supported) */
{
long unsigned int maxreqsize = XExtendedMaxRequestSize(pDisplay);
if (maxreqsize == 0)
maxreqsize = XMaxRequestSize(pDisplay);
/* covert to bytes and allow for allow for X_ChangeProperty request */
maxreqsize = maxreqsize*4 - 24;
if (xtpText.nitems > maxreqsize) {
ErrorF("winClipboardFlushXEvents - clipboard data size %lu greater than maximum %lu\n", xtpText.nitems, maxreqsize);
/* Abort */
fAbort = TRUE;
goto winClipboardFlushXEvents_SelectionRequest_Done;
}
}
/* Copy the clipboard text to the requesting window */
iReturn = XChangeProperty(pDisplay,
event.xselectionrequest.requestor,
event.xselectionrequest.property,
event.xselectionrequest.target,
8,
PropModeReplace,
xtpText.value, xtpText.nitems);
if (iReturn == BadAlloc || iReturn == BadAtom
|| iReturn == BadMatch || iReturn == BadValue
|| iReturn == BadWindow) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"XChangeProperty failed: %d\n", iReturn);
/* Abort */
fAbort = TRUE;
goto winClipboardFlushXEvents_SelectionRequest_Done;
}
/* Release the clipboard data */
GlobalUnlock(hGlobal);
pszGlobalData = NULL;
@ -682,27 +607,25 @@ winClipboardFlushXEvents(HWND hwnd,
CloseClipboard();
/* Clean up */
XFree(xtpText.value);
xtpText.value = NULL;
xtpText.nitems = 0;
free(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;
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 */
iReturn = XSendEvent(pDisplay,
eventSelection.requestor,
False, 0L, (XEvent *) &eventSelection);
if (iReturn == BadValue || iReturn == BadWindow) {
cookie = xcb_send_event_checked(conn, FALSE,
eventSelection.requestor,
0, (char *) &eventSelection);
if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"XSendEvent () failed\n");
"xcb_send_event() failed\n");
/* Abort */
fAbort = TRUE;
@ -711,12 +634,11 @@ winClipboardFlushXEvents(HWND hwnd,
winClipboardFlushXEvents_SelectionRequest_Done:
/* Free allocated resources */
if (xtpText.value) {
XFree(xtpText.value);
xtpText.value = NULL;
xtpText.nitems = 0;
if (xtpText_value) {
free(xtpText_value);
}
free(pszConvertData);
if (pszConvertData)
free(pszConvertData);
if (hGlobal && pszGlobalData)
GlobalUnlock(hGlobal);
@ -726,26 +648,24 @@ winClipboardFlushXEvents(HWND hwnd,
*/
if (fAbort) {
/* Setup selection notify event */
eventSelection.type = SelectionNotify;
eventSelection.send_event = True;
eventSelection.display = pDisplay;
eventSelection.requestor = event.xselectionrequest.requestor;
eventSelection.selection = event.xselectionrequest.selection;
eventSelection.target = event.xselectionrequest.target;
eventSelection.property = None;
eventSelection.time = event.xselectionrequest.time;
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 */
iReturn = XSendEvent(pDisplay,
eventSelection.requestor,
False, 0L, (XEvent *) &eventSelection);
if (iReturn == BadValue || iReturn == BadWindow) {
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 - "
"XSendEvent () failed for abort event.\n");
"xcb_send_event() failed for abort event.\n");
}
}
@ -755,71 +675,79 @@ winClipboardFlushXEvents(HWND hwnd,
CloseClipboard();
}
break;
}
/*
* SelectionNotify
*/
case SelectionNotify:
case XCB_SELECTION_NOTIFY:
{
xcb_selection_notify_event_t *selection_notify = (xcb_selection_notify_event_t *)event;
winDebug("winClipboardFlushXEvents - SelectionNotify\n");
{
char *pszAtomName;
pszAtomName = XGetAtomName(pDisplay,
event.xselection.selection);
winDebug
("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n",
pszAtomName);
XFree(pszAtomName);
pszAtomName = get_atom_name(conn, selection_notify->selection);
winDebug("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n", pszAtomName);
free(pszAtomName);
}
/*
SelectionNotify with property of None indicates either:
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 (event.xselection.property == None) {
if (selection_notify->property == XCB_NONE) {
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
"Conversion to format %ld refused.\n",
event.xselection.target);
"Conversion to format %d refused.\n",
selection_notify->target);
return WIN_XEVENTS_FAILED;
}
if (event.xselection.target == atomTargets) {
return winClipboardSelectionNotifyTargets(hwnd, iWindow, pDisplay, data, atoms);
if (selection_notify->target == atomTargets) {
return winClipboardSelectionNotifyTargets(hwnd, iWindow, conn, data, atoms);
}
return winClipboardSelectionNotifyData(hwnd, iWindow, pDisplay, data, atoms);
return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms);
}
case SelectionClear:
case XCB_SELECTION_CLEAR:
winDebug("SelectionClear - doing nothing\n");
break;
case PropertyNotify:
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 &&
(event.xproperty.atom == atoms->atomLocalProperty) &&
(event.xproperty.state == PropertyNewValue))
return winClipboardSelectionNotifyData(hwnd, iWindow, pDisplay, data, atoms);
(property_notify->atom == atoms->atomLocalProperty) &&
(property_notify->state == XCB_PROPERTY_NEW_VALUE))
return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms);
break;
}
case MappingNotify:
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.type == XFixesSetSelectionOwnerNotify + xfixes_event_base) {
XFixesSelectionNotifyEvent *e =
(XFixesSelectionNotifyEvent *) & event;
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 == XA_PRIMARY) && fPrimarySelection) {
if ((e->selection == XCB_ATOM_PRIMARY) && fPrimarySelection) {
MonitorSelection(e, CLIP_OWN_PRIMARY);
}
else if (e->selection == atomClipboard) {
@ -829,9 +757,8 @@ winClipboardFlushXEvents(HWND hwnd,
break;
/* Selection is being disowned */
if (e->owner == None) {
winDebug
("winClipboardFlushXEvents - No window, returning.\n");
if (e->owner == XCB_NONE) {
winDebug("winClipboardFlushXEvents - No window, returning.\n");
break;
}
@ -878,15 +805,25 @@ winClipboardFlushXEvents(HWND hwnd,
break;
}
}
/* XFixesSelectionWindowDestroyNotifyMask */
/* XFixesSelectionClientCloseNotifyMask */
/* XCB_XFIXES_SELECTION_EVENT_SELECTION_WINDOW_DESTROY */
/* XCB_XFIXES_SELECTION_EVENT_SELECTION_CLIENT_CLOSE */
else {
ErrorF("winClipboardFlushXEvents - unexpected event type %d\n",
event.type);
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

@ -35,27 +35,10 @@
#include <xwin-config.h>
#endif
/*
* Including any server header might define the macro _XSERVER64 on 64 bit machines.
* That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
* So let's undef that macro if necessary.
*/
#ifdef _XSERVER64
#undef _XSERVER64
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* X headers */
#include <X11/Xlib.h>
#ifdef X_LOCALE
#include <X11/Xlocale.h>
#else /* X_LOCALE */
#include <locale.h>
#endif /* X_LOCALE */
#include "winclipboard.h"
/*
@ -87,7 +70,7 @@ main (int argc, char *argv[])
/* Look for -noprimary */
if (!strcmp (argv[i], "-noprimary"))
{
fPrimarySelection = False;
fPrimarySelection = 0;
continue;
}
@ -96,21 +79,7 @@ main (int argc, char *argv[])
exit (1);
}
/* Apply locale specified in the LANG environment variable */
if (!setlocale (LC_ALL, ""))
{
printf ("setlocale() error\n");
exit (1);
}
/* See if X supports the current locale */
if (XSupportsLocale () == False)
{
printf ("Locale not supported by X, falling back to 'C' locale.\n");
setlocale(LC_ALL, "C");
}
winClipboardProc(pszDisplay);
winClipboardProc(pszDisplay, NULL /* Use XAUTHORITY for auth data */);
return 0;
}

View File

@ -42,6 +42,8 @@
#define WIN_CLIPBOARD_RETRIES 40
#define WIN_CLIPBOARD_DELAY 1
extern xcb_auth_info_t *winGetXcbAuthInfo(void);
/*
* Local variables
*/
@ -55,6 +57,7 @@ static void *
winClipboardThreadProc(void *arg)
{
char szDisplay[512];
xcb_auth_info_t *auth_info;
int clipboardRestarts = 0;
while (1)
@ -82,7 +85,10 @@ winClipboardThreadProc(void *arg)
/* Flag that clipboard client has been launched */
g_fClipboardStarted = TRUE;
fShutdown = winClipboardProc(szDisplay);
/* Use our generated cookie for authentication */
auth_info = winGetXcbAuthInfo();
fShutdown = winClipboardProc(szDisplay, auth_info);
/* Flag that clipboard client has stopped */
g_fClipboardStarted = FALSE;