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_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support])
AC_CHECK_TOOL(WINDRES, windres) 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 if test "x$WINDOWSDRI" = xauto; then
PKG_CHECK_EXISTS([windowsdriproto], [WINDOWSDRI=yes], [WINDOWSDRI=no]) PKG_CHECK_EXISTS([windowsdriproto], [WINDOWSDRI=yes], [WINDOWSDRI=no])

View File

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

View File

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

View File

@ -32,15 +32,6 @@
#include <xwin-config.h> #include <xwin-config.h>
#endif #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 <stdlib.h>
#include "internal.h" #include "internal.h"

View File

@ -36,19 +36,9 @@
#define HAS_WINSOCK 1 #define HAS_WINSOCK 1
#endif #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 <assert.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <setjmp.h>
#include <pthread.h> #include <pthread.h>
#include <sys/param.h> // for MAX() macro #include <sys/param.h> // for MAX() macro
@ -58,8 +48,11 @@
#include <errno.h> #include <errno.h>
#endif #endif
#include <X11/Xatom.h> #include <xcb/xcb.h>
#include <X11/extensions/Xfixes.h> #include <xcb/xcb_aux.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xfixes.h>
#include "winclipboard.h" #include "winclipboard.h"
#include "internal.h" #include "internal.h"
@ -77,9 +70,6 @@
*/ */
static HWND g_hwndClipboard = NULL; 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_event_base;
int xfixes_error_base; int xfixes_error_base;
@ -89,13 +79,23 @@ int xfixes_error_base;
*/ */
static HWND static HWND
winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAtoms *atoms); winClipboardCreateMessagingWindow(xcb_connection_t *conn, xcb_window_t iWindow, ClipboardAtoms *atoms);
static int static xcb_atom_t
winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr); 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 atom_cookie = xcb_intern_atom(conn, 0, strlen(atomName), atomName);
winClipboardIOErrorHandler(Display * pDisplay); 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 * Create X11 and Win32 messaging windows, and run message processing loop
@ -104,13 +104,12 @@ static int
*/ */
Bool Bool
winClipboardProc(char *szDisplay) winClipboardProc(char *szDisplay, xcb_auth_info_t *auth_info)
{ {
ClipboardAtoms atoms; ClipboardAtoms atoms;
int iReturn; int iReturn;
HWND hwnd = NULL; HWND hwnd = NULL;
int iConnectionNumber = 0; int iConnectionNumber = 0;
#ifdef HAS_DEVWINDOWS #ifdef HAS_DEVWINDOWS
int fdMessageQueue = 0; int fdMessageQueue = 0;
#else #else
@ -118,54 +117,27 @@ winClipboardProc(char *szDisplay)
#endif #endif
fd_set fdsRead; fd_set fdsRead;
int iMaxDescriptor; int iMaxDescriptor;
Display *pDisplay = NULL; xcb_connection_t *conn;
Window iWindow = None; xcb_window_t iWindow = XCB_NONE;
int iSelectError; int iSelectError;
Bool fShutdown = FALSE; Bool fShutdown = FALSE;
static Bool fErrorHandlerSet = FALSE;
ClipboardConversionData data; ClipboardConversionData data;
int screen;
winDebug("winClipboardProc - Hello\n"); 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 */ /* Make sure that the display opened */
pDisplay = XOpenDisplay(szDisplay); conn = xcb_connect_to_display_with_auth_info(szDisplay, auth_info, &screen);
if (pDisplay == NULL) { if (xcb_connection_has_error(conn)) {
ErrorF("winClipboardProc - Failed opening the display, giving up\n"); ErrorF("winClipboardProc - Failed opening the display, giving up\n");
goto winClipboardProc_Done; goto winClipboardProc_Done;
} }
ErrorF("winClipboardProc - XOpenDisplay () returned and " ErrorF("winClipboardProc - xcb_connect () returned and "
"successfully opened the display.\n"); "successfully opened the display.\n");
/* Get our connection number */ /* Get our connection number */
iConnectionNumber = ConnectionNumber(pDisplay); iConnectionNumber = xcb_get_file_descriptor(conn);
#ifdef HAS_DEVWINDOWS #ifdef HAS_DEVWINDOWS
/* Open a file descriptor for the windows message queue */ /* Open a file descriptor for the windows message queue */
@ -181,56 +153,75 @@ winClipboardProc(char *szDisplay)
iMaxDescriptor = iConnectionNumber + 1; iMaxDescriptor = iConnectionNumber + 1;
#endif #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"); 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 */ /* Create atoms */
atoms.atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False); atoms.atomClipboard = intern_atom(conn, "CLIPBOARD");
atoms.atomLocalProperty = XInternAtom (pDisplay, "CYGX_CUT_BUFFER", False); atoms.atomLocalProperty = intern_atom(conn, "CYGX_CUT_BUFFER");
atoms.atomUTF8String = XInternAtom (pDisplay, "UTF8_STRING", False); atoms.atomUTF8String = intern_atom(conn, "UTF8_STRING");
atoms.atomCompoundText = XInternAtom (pDisplay, "COMPOUND_TEXT", False); atoms.atomCompoundText = intern_atom(conn, "COMPOUND_TEXT");
atoms.atomTargets = XInternAtom (pDisplay, "TARGETS", False); atoms.atomTargets = intern_atom(conn, "TARGETS");
atoms.atomIncr = XInternAtom (pDisplay, "INCR", False); 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 */ /* Create a messaging window */
iWindow = XCreateSimpleWindow(pDisplay, iWindow = xcb_generate_id(conn);
DefaultRootWindow(pDisplay), xcb_void_cookie_t cookie = xcb_create_window_checked(conn,
1, 1, XCB_COPY_FROM_PARENT,
500, 500, iWindow,
0, root_window_id,
BlackPixel(pDisplay, 0), 1, 1,
BlackPixel(pDisplay, 0)); 500, 500,
if (iWindow == 0) { 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"); ErrorF("winClipboardProc - Could not create an X window.\n");
free(error);
goto winClipboardProc_Done; 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 */ /* Select event types to watch */
if (XSelectInput(pDisplay, iWindow, PropertyChangeMask) == BadWindow) const static uint32_t values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
ErrorF("winClipboardProc - XSelectInput generated BadWindow " cookie = xcb_change_window_attributes_checked(conn, iWindow, XCB_CW_EVENT_MASK, values);
"on messaging window\n"); if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardProc - Could not set event mask on messaging window\n");
free(error);
}
XFixesSelectSelectionInput (pDisplay, xcb_xfixes_select_selection_input(conn,
iWindow, iWindow,
XA_PRIMARY, XCB_ATOM_PRIMARY,
XFixesSetSelectionOwnerNotifyMask | XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
XFixesSelectionWindowDestroyNotifyMask | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
XFixesSelectionClientCloseNotifyMask); XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE);
XFixesSelectSelectionInput (pDisplay,
iWindow,
atoms.atomClipboard,
XFixesSetSelectionOwnerNotifyMask |
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask);
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 */ /* Initialize monitored selection state */
winClipboardInitMonitoredSelections(); winClipboardInitMonitoredSelections();
/* Create Windows messaging window */ /* Create Windows messaging window */
hwnd = winClipboardCreateMessagingWindow(pDisplay, iWindow, &atoms); hwnd = winClipboardCreateMessagingWindow(conn, iWindow, &atoms);
/* Save copy of HWND */ /* Save copy of HWND */
g_hwndClipboard = hwnd; g_hwndClipboard = hwnd;
@ -238,20 +229,18 @@ winClipboardProc(char *szDisplay)
/* Assert ownership of selections if Win32 clipboard is owned */ /* Assert ownership of selections if Win32 clipboard is owned */
if (NULL != GetClipboardOwner()) { if (NULL != GetClipboardOwner()) {
/* PRIMARY */ /* PRIMARY */
iReturn = XSetSelectionOwner(pDisplay, XA_PRIMARY, cookie = xcb_set_selection_owner_checked(conn, iWindow, XCB_ATOM_PRIMARY, XCB_CURRENT_TIME);
iWindow, CurrentTime); if ((error = xcb_request_check(conn, cookie))) {
if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) {
ErrorF("winClipboardProc - Could not set PRIMARY owner\n"); ErrorF("winClipboardProc - Could not set PRIMARY owner\n");
free(error);
goto winClipboardProc_Done; goto winClipboardProc_Done;
} }
/* CLIPBOARD */ /* CLIPBOARD */
iReturn = XSetSelectionOwner(pDisplay, atoms.atomClipboard, cookie = xcb_set_selection_owner_checked(conn, iWindow, atoms.atomClipboard, XCB_CURRENT_TIME);
iWindow, CurrentTime); if ((error = xcb_request_check(conn, cookie))) {
if (iReturn == BadAtom || iReturn == BadWindow ||
XGetSelectionOwner(pDisplay, atoms.atomClipboard) != iWindow) {
ErrorF("winClipboardProc - Could not set CLIPBOARD owner\n"); ErrorF("winClipboardProc - Could not set CLIPBOARD owner\n");
free(error);
goto winClipboardProc_Done; goto winClipboardProc_Done;
} }
} }
@ -263,8 +252,7 @@ winClipboardProc(char *szDisplay)
while (1) { while (1) {
/* Process X events */ /* Process X events */
winClipboardFlushXEvents(hwnd, winClipboardFlushXEvents(hwnd, iWindow, conn, &data, &atoms);
iWindow, pDisplay, &data, &atoms);
/* Process Windows messages */ /* Process Windows messages */
if (!winClipboardFlushWindowsMessageQueue(hwnd)) { if (!winClipboardFlushWindowsMessageQueue(hwnd)) {
@ -274,7 +262,7 @@ winClipboardProc(char *szDisplay)
} }
/* We need to ensure that all pending requests are sent */ /* We need to ensure that all pending requests are sent */
XFlush(pDisplay); xcb_flush(conn);
/* Setup the file descriptor set */ /* Setup the file descriptor set */
/* /*
@ -346,7 +334,6 @@ winClipboardProc(char *szDisplay)
#endif #endif
} }
winClipboardProc_Exit:
/* broke out of while loop on a shutdown message */ /* broke out of while loop on a shutdown message */
fShutdown = TRUE; fShutdown = TRUE;
@ -357,12 +344,13 @@ winClipboardProc(char *szDisplay)
} }
/* Close our X window */ /* Close our X window */
if (pDisplay && iWindow) { if (!xcb_connection_has_error(conn) && iWindow) {
iReturn = XDestroyWindow(pDisplay, iWindow); cookie = xcb_destroy_window_checked(conn, iWindow);
if (iReturn == BadWindow) if ((error = xcb_request_check(conn, cookie)))
ErrorF("winClipboardProc - XDestroyWindow returned BadWindow.\n"); ErrorF("winClipboardProc - XDestroyWindow failed.\n");
else else
ErrorF("winClipboardProc - XDestroyWindow succeeded.\n"); ErrorF("winClipboardProc - XDestroyWindow succeeded.\n");
free(error);
} }
#ifdef HAS_DEVWINDOWS #ifdef HAS_DEVWINDOWS
@ -371,26 +359,15 @@ winClipboardProc(char *szDisplay)
close(fdMessageQueue); close(fdMessageQueue);
#endif #endif
#if 0
/* /*
* FIXME: XCloseDisplay hangs if we call it * 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
* XCloseDisplay() calls XSync(), so any outstanding errors are reported. * server is in the process of exiting and waiting for this thread to exit.
* 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.
*/ */
if (!xcb_connection_has_error(conn)) {
/* Discard any remaining events */ /* Close our X display */
XSync(pDisplay, TRUE); xcb_disconnect(conn);
/* Select event types to watch */
XSelectInput(pDisplay, DefaultRootWindow(pDisplay), None);
/* Close our X display */
if (pDisplay) {
XCloseDisplay(pDisplay);
} }
#endif
/* global clipboard variable reset */ /* global clipboard variable reset */
g_hwndClipboard = NULL; g_hwndClipboard = NULL;
@ -403,7 +380,7 @@ winClipboardProc(char *szDisplay)
*/ */
static HWND static HWND
winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAtoms *atoms) winClipboardCreateMessagingWindow(xcb_connection_t *conn, xcb_window_t iWindow, ClipboardAtoms *atoms)
{ {
WNDCLASSEX wc; WNDCLASSEX wc;
ClipboardWindowCreationParams cwcp; ClipboardWindowCreationParams cwcp;
@ -425,7 +402,7 @@ winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAt
RegisterClassEx(&wc); RegisterClassEx(&wc);
/* Information to be passed to WM_CREATE */ /* Information to be passed to WM_CREATE */
cwcp.pClipboardDisplay = pDisplay; cwcp.pClipboardDisplay = conn;
cwcp.iClipboardWindow = iWindow; cwcp.iClipboardWindow = iWindow;
cwcp.atoms = atoms; cwcp.atoms = atoms;
@ -453,42 +430,6 @@ winClipboardCreateMessagingWindow(Display *pDisplay, Window iWindow, ClipboardAt
return hwnd; 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 void
winClipboardWindowDestroy(void) winClipboardWindowDestroy(void)
{ {

View File

@ -27,7 +27,10 @@
#ifndef WINCLIPBOARD_H #ifndef WINCLIPBOARD_H
#define 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); void winFixClipboardChain(void);

View File

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

View File

@ -34,20 +34,11 @@
#include <xwin-config.h> #include <xwin-config.h>
#endif #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 <limits.h>
#include <wchar.h> #include <wchar.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h> #include <xcb/xcb.h>
#include <X11/extensions/Xfixes.h> #include <xcb/xfixes.h>
#include "winclipboard.h" #include "winclipboard.h"
#include "internal.h" #include "internal.h"
@ -57,10 +48,12 @@
*/ */
#define CLIP_NUM_SELECTIONS 2 #define CLIP_NUM_SELECTIONS 2
#define CLIP_OWN_NONE -1 #define CLIP_OWN_NONE -1
#define CLIP_OWN_PRIMARY 0 #define CLIP_OWN_PRIMARY 0
#define CLIP_OWN_CLIPBOARD 1 #define CLIP_OWN_CLIPBOARD 1
#define CP_ISO_8559_1 28591
/* /*
* Global variables * Global variables
*/ */
@ -72,17 +65,17 @@ Bool fPrimarySelection = TRUE;
* Local variables * 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] = static const char *szSelectionNames[CLIP_NUM_SELECTIONS] =
{ "PRIMARY", "CLIPBOARD" }; { "PRIMARY", "CLIPBOARD" };
static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE; static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE;
static void 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 */ /* 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; unsigned int other_index;
winDebug("MonitorSelection - %s - Going from owned to not owned.\n", 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; other_index = CLIP_OWN_CLIPBOARD;
if (i == CLIP_OWN_CLIPBOARD) if (i == CLIP_OWN_CLIPBOARD)
other_index = CLIP_OWN_PRIMARY; other_index = CLIP_OWN_PRIMARY;
if (None != s_iOwners[other_index]) if (XCB_NONE != s_iOwners[other_index])
lastOwnedSelectionIndex = other_index; lastOwnedSelectionIndex = other_index;
else else
lastOwnedSelectionIndex = CLIP_OWN_NONE; lastOwnedSelectionIndex = CLIP_OWN_NONE;
} }
/* Save last owned selection */ /* Save last owned selection */
if (None != e->owner) { if (XCB_NONE != e->owner) {
lastOwnedSelectionIndex = i; lastOwnedSelectionIndex = i;
} }
/* Save new selection owner or None */ /* Save new selection owner or None */
s_iOwners[i] = e->owner; 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); szSelectionNames[i], e->owner);
} }
Atom xcb_atom_t
winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms) winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms)
{ {
if (lastOwnedSelectionIndex == CLIP_OWN_NONE) if (lastOwnedSelectionIndex == CLIP_OWN_NONE)
return None; return XCB_NONE;
if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY) if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY)
return XA_PRIMARY; return XCB_ATOM_PRIMARY;
if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD) if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD)
return atoms->atomClipboard; return atoms->atomClipboard;
return None; return XCB_NONE;
} }
@ -133,102 +126,116 @@ winClipboardInitMonitoredSelections(void)
/* Initialize static variables */ /* Initialize static variables */
int i; int i;
for (i = 0; i < CLIP_NUM_SELECTIONS; ++i) for (i = 0; i < CLIP_NUM_SELECTIONS; ++i)
s_iOwners[i] = None; s_iOwners[i] = XCB_NONE;
lastOwnedSelectionIndex = CLIP_OWN_NONE; lastOwnedSelectionIndex = CLIP_OWN_NONE;
} }
static int static char *get_atom_name(xcb_connection_t *conn, xcb_atom_t atom)
winClipboardSelectionNotifyTargets(HWND hwnd, Window iWindow, Display *pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms)
{ {
Atom type; char *ret;
int format; xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(conn, atom);
unsigned long nitems; xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(conn, cookie, NULL);
unsigned long after; if (!reply)
Atom *prop; 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 */ /* Retrieve the selection data and delete the property */
int iReturn = XGetWindowProperty(pDisplay, xcb_get_property_cookie_t cookie = xcb_get_property(conn,
iWindow, TRUE,
atoms->atomLocalProperty, iWindow,
0, atoms->atomLocalProperty,
INT_MAX, XCB_GET_PROPERTY_TYPE_ANY,
True, 0,
AnyPropertyType, INT_MAX);
&type, xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
&format, if (!reply) {
&nitems, ErrorF("winClipboardFlushXEvents - SelectionNotify - "
&after, "XGetWindowProperty () failed\n");
(unsigned char **)&prop);
if (iReturn != Success) {
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
"XGetWindowProperty () failed, aborting: %d\n", iReturn);
} else { } else {
int i; xcb_atom_t *prop = xcb_get_property_value(reply);
data->targetList = malloc((nitems+1)*sizeof(Atom)); 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++) for (i = 0; i < nitems; i++)
{ {
Atom atom = prop[i]; xcb_atom_t atom = prop[i];
char *pszAtomName = XGetAtomName(pDisplay, atom); char *pszAtomName = get_atom_name(conn, atom);
data->targetList[i] = atom; data->targetList[i] = atom;
winDebug("winClipboardFlushXEvents - SelectionNotify - target[%d] %ld = %s\n", i, atom, pszAtomName); winDebug("winClipboardFlushXEvents - SelectionNotify - target[%d] %d = %s\n", i, atom, pszAtomName);
XFree(pszAtomName); free(pszAtomName);
} }
data->targetList[nitems] = 0; data->targetList[nitems] = 0;
XFree(prop); free(reply);
} }
return WIN_XEVENTS_NOTIFY_TARGETS; return WIN_XEVENTS_NOTIFY_TARGETS;
} }
static int 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; int format;
unsigned long int nitems; unsigned long int nitems;
unsigned long int after; unsigned long int after;
unsigned char *value; unsigned char *value;
XTextProperty xtpText = { 0 };
unsigned char *xtpText_value;
xcb_atom_t xtpText_encoding;
int xtpText_nitems;
Bool fSetClipboardData = TRUE; Bool fSetClipboardData = TRUE;
int iReturn;
char **ppszTextList = NULL;
int iCount;
char *pszReturnData = NULL; char *pszReturnData = NULL;
UINT codepage;
wchar_t *pwszUnicodeStr = NULL; wchar_t *pwszUnicodeStr = NULL;
HGLOBAL hGlobal = NULL; HGLOBAL hGlobal = NULL;
char *pszGlobalData = NULL; char *pszGlobalData = NULL;
/* Retrieve the selection data and delete the property */ /* Retrieve the selection data and delete the property */
iReturn = XGetWindowProperty(pDisplay, xcb_get_property_cookie_t cookie = xcb_get_property(conn,
iWindow, TRUE,
atoms->atomLocalProperty, iWindow,
0, atoms->atomLocalProperty,
INT_MAX, XCB_GET_PROPERTY_TYPE_ANY,
True, 0,
AnyPropertyType, INT_MAX);
&encoding, xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
&format, if (!reply) {
&nitems,
&after,
&value);
if (iReturn != Success) {
ErrorF("winClipboardFlushXEvents - SelectionNotify - " ErrorF("winClipboardFlushXEvents - SelectionNotify - "
"XGetWindowProperty () failed, aborting: %d\n", iReturn); "XGetWindowProperty () failed\n");
goto winClipboardFlushXEvents_SelectionNotify_Done; 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); 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); winDebug("Notify atom name %s\n", pszAtomName);
XFree(pszAtomName); free(pszAtomName);
pszAtomName = NULL;
} }
/* INCR reply indicates the start of a incremental transfer */ /* INCR reply indicates the start of a incremental transfer */
@ -244,10 +251,12 @@ winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, Cl
if (nitems == 0) { if (nitems == 0) {
winDebug("winClipboardSelectionNotifyData: ending INCR, actual size %ld\n", data->incrsize); winDebug("winClipboardSelectionNotifyData: ending INCR, actual size %ld\n", data->incrsize);
/* a zero-length property indicates the end of the data */ /* a zero-length property indicates the end of the data */
xtpText.value = data->incr; xtpText_value = data->incr;
xtpText.encoding = encoding; 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. // XXX: The type of the converted selection is the type of the first
xtpText.nitems = data->incrsize; // partial property. The remaining partial properties must have the
// same type.
xtpText_nitems = data->incrsize;
} }
else { else {
/* Otherwise, continue appending the INCR data */ /* Otherwise, continue appending the INCR data */
@ -261,70 +270,34 @@ winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, Cl
else { else {
/* Otherwise, the data is just contained in the property */ /* Otherwise, the data is just contained in the property */
winDebug("winClipboardSelectionNotifyData: non-INCR, %ld bytes\n", nitems); winDebug("winClipboardSelectionNotifyData: non-INCR, %ld bytes\n", nitems);
xtpText.value = value; xtpText_value = value;
xtpText.encoding = encoding; xtpText_encoding = encoding;
xtpText.format = format; xtpText_nitems = nitems;
xtpText.nitems = nitems;
} }
#ifdef X_HAVE_UTF8_STRING if (xtpText_encoding == atoms->atomUTF8String) {
/* Convert the text property to a text list */ pszReturnData = malloc(xtpText_nitems + 1);
iReturn = Xutf8TextPropertyToTextList(pDisplay, memcpy(pszReturnData, xtpText_value, xtpText_nitems);
&xtpText, pszReturnData[xtpText_nitems] = 0;
&ppszTextList, &iCount); codepage = CP_UTF8; // code page identifier for utf8
#endif } else if (xtpText_encoding == XCB_ATOM_STRING) {
// STRING encoding is Latin1 (ISO8859-1) plus tab and newline
if (iReturn == Success || iReturn > 0) { pszReturnData = malloc(xtpText_nitems + 1);
/* Conversion succeeded or some unconvertible characters */ memcpy(pszReturnData, xtpText_value, xtpText_nitems);
if (ppszTextList != NULL) { pszReturnData[xtpText_nitems] = 0;
int i; codepage = CP_ISO_8559_1; // code page identifier for iso-8559-1
int iReturnDataLen = 0; } else if (xtpText_encoding == atoms->atomCompoundText) {
for (i = 0; i < iCount; i++) { // COMPOUND_TEXT is complex, based on ISO 2022
iReturnDataLen += strlen(ppszTextList[i]); ErrorF("SelectionNotify: data in COMPOUND_TEXT encoding which is not implemented, discarding\n");
} pszReturnData = malloc(1);
pszReturnData = malloc(iReturnDataLen + 1); pszReturnData[0] = '\0';
pszReturnData[0] = '\0'; } else { // shouldn't happen as we accept no other encodings
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;
}
pszReturnData = malloc(1); pszReturnData = malloc(1);
pszReturnData[0] = '\0'; pszReturnData[0] = '\0';
} }
/* Free the data returned from xcb_get_property */
if (ppszTextList) free(reply);
XFreeStringList(ppszTextList);
ppszTextList = NULL;
/* Free the data returned from XGetWindowProperty */
XFree(value);
value = NULL;
nitems = 0;
/* Free any INCR data */ /* Free any INCR data */
if (data->incr) { if (data->incr) {
@ -336,9 +309,8 @@ winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, Cl
/* Convert the X clipboard string to DOS format */ /* Convert the X clipboard string to DOS format */
winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData)); winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData));
/* Find out how much space needed to convert MBCS to Unicode */ /* Find out how much space needed when converted to UTF-16 */
int iUnicodeLen = MultiByteToWideChar(CP_UTF8, int iUnicodeLen = MultiByteToWideChar(codepage, 0,
0,
pszReturnData, -1, NULL, 0); pszReturnData, -1, NULL, 0);
/* NOTE: iUnicodeLen includes space for null terminator */ /* NOTE: iUnicodeLen includes space for null terminator */
@ -352,15 +324,12 @@ winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, Cl
} }
/* Do the actual conversion */ /* Do the actual conversion */
MultiByteToWideChar(CP_UTF8, MultiByteToWideChar(codepage, 0,
0, pszReturnData, -1, pwszUnicodeStr, iUnicodeLen);
pszReturnData,
-1, pwszUnicodeStr, iUnicodeLen);
/* Allocate global memory for the X clipboard data */ /* Allocate global memory for the X clipboard data */
hGlobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * iUnicodeLen); hGlobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * iUnicodeLen);
free(pszReturnData); free(pszReturnData);
/* Check that global memory was allocated */ /* Check that global memory was allocated */
@ -404,13 +373,6 @@ winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, Cl
winClipboardFlushXEvents_SelectionNotify_Done: winClipboardFlushXEvents_SelectionNotify_Done:
/* Free allocated resources */ /* Free allocated resources */
if (ppszTextList)
XFreeStringList(ppszTextList);
if (value) {
XFree(value);
value = NULL;
nitems = 0;
}
free(pwszUnicodeStr); free(pwszUnicodeStr);
if (hGlobal && pszGlobalData) if (hGlobal && pszGlobalData)
GlobalUnlock(hGlobal); GlobalUnlock(hGlobal);
@ -427,105 +389,97 @@ winClipboardSelectionNotifyData(HWND hwnd, Window iWindow, Display *pDisplay, Cl
int int
winClipboardFlushXEvents(HWND hwnd, 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; xcb_atom_t atomClipboard = atoms->atomClipboard;
Atom atomUTF8String = atoms->atomUTF8String; xcb_atom_t atomUTF8String = atoms->atomUTF8String;
Atom atomCompoundText = atoms->atomCompoundText; xcb_atom_t atomCompoundText = atoms->atomCompoundText;
Atom atomTargets = atoms->atomTargets; xcb_atom_t atomTargets = atoms->atomTargets;
/* Process all pending events */ /* Process all pending events */
while (XPending(pDisplay)) { xcb_generic_event_t *event;
XTextProperty xtpText = { 0 }; while ((event = xcb_poll_for_event(conn))) {
XEvent event; const char *pszGlobalData = NULL;
XSelectionEvent eventSelection;
char *pszGlobalData = NULL;
int iReturn;
HGLOBAL hGlobal = NULL; HGLOBAL hGlobal = NULL;
XICCEncodingStyle xiccesStyle;
char *pszConvertData = NULL; char *pszConvertData = NULL;
char *pszTextList[2] = { NULL };
Bool fAbort = FALSE; Bool fAbort = FALSE;
Bool fCloseClipboard = FALSE; Bool fCloseClipboard = FALSE;
/* Get the next event - will not block because one is ready */
XNextEvent(pDisplay, &event);
/* Branch on the event type */ /* Branch on the event type */
switch (event.type) { switch (event->response_type & ~0x80) {
/* case XCB_SELECTION_REQUEST:
* SelectionRequest {
*/ 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; char *pszAtomName = NULL;
winDebug("SelectionRequest - target %ld\n", winDebug("SelectionRequest - target %d\n", selection_request->target);
event.xselectionrequest.target);
pszAtomName = XGetAtomName(pDisplay, pszAtomName = get_atom_name(conn, selection_request->target);
event.xselectionrequest.target);
winDebug("SelectionRequest - Target atom name %s\n", pszAtomName); winDebug("SelectionRequest - Target atom name %s\n", pszAtomName);
XFree(pszAtomName); free(pszAtomName);
pszAtomName = NULL;
} }
/* Abort if invalid target type */ /* Abort if invalid target type */
if (event.xselectionrequest.target != XA_STRING if (selection_request->target != XCB_ATOM_STRING
&& event.xselectionrequest.target != atomUTF8String && selection_request->target != atomUTF8String
&& event.xselectionrequest.target != atomCompoundText && selection_request->target != atomCompoundText
&& event.xselectionrequest.target != atomTargets) { && selection_request->target != atomTargets) {
/* Abort */ /* Abort */
fAbort = TRUE; fAbort = TRUE;
goto winClipboardFlushXEvents_SelectionRequest_Done; goto winClipboardFlushXEvents_SelectionRequest_Done;
} }
/* Handle targets type of request */ /* Handle targets type of request */
if (event.xselectionrequest.target == atomTargets) { if (selection_request->target == atomTargets) {
Atom atomTargetArr[] = { atomTargets, xcb_atom_t atomTargetArr[] =
atomCompoundText, {
atomUTF8String, atomTargets,
XA_STRING atomUTF8String,
}; XCB_ATOM_STRING,
// atomCompoundText, not implemented (yet?)
};
/* Try to change the property */ /* Try to change the property */
iReturn = XChangeProperty(pDisplay, xcb_void_cookie_t cookie = xcb_change_property_checked(conn,
event.xselectionrequest.requestor, XCB_PROP_MODE_REPLACE,
event.xselectionrequest.property, selection_request->requestor,
XA_ATOM, selection_request->property,
XCB_ATOM_ATOM,
32, 32,
PropModeReplace, ARRAY_SIZE(atomTargetArr),
(unsigned char *) atomTargetArr, (unsigned char *) atomTargetArr);
ARRAY_SIZE(atomTargetArr)); xcb_generic_error_t *error;
if (iReturn == BadAlloc if ((error = xcb_request_check(conn, cookie))) {
|| iReturn == BadAtom
|| iReturn == BadMatch
|| iReturn == BadValue || iReturn == BadWindow) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - " ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"XChangeProperty failed: %d\n", iReturn); "xcb_change_property failed");
free(error);
} }
/* Setup selection notify xevent */ /* Setup selection notify xevent */
eventSelection.type = SelectionNotify; xcb_selection_notify_event_t eventSelection;
eventSelection.send_event = True; eventSelection.response_type = XCB_SELECTION_NOTIFY;
eventSelection.display = pDisplay; eventSelection.requestor = selection_request->requestor;
eventSelection.requestor = event.xselectionrequest.requestor; eventSelection.selection = selection_request->selection;
eventSelection.selection = event.xselectionrequest.selection; eventSelection.target = selection_request->target;
eventSelection.target = event.xselectionrequest.target; eventSelection.property = selection_request->property;
eventSelection.property = event.xselectionrequest.property; eventSelection.time = selection_request->time;
eventSelection.time = event.xselectionrequest.time;
/* /*
* Notify the requesting window that * Notify the requesting window that
* the operation has completed * the operation has completed
*/ */
iReturn = XSendEvent(pDisplay, cookie = xcb_send_event_checked(conn, FALSE,
eventSelection.requestor, eventSelection.requestor,
False, 0L, (XEvent *) &eventSelection); 0, (char *) &eventSelection);
if (iReturn == BadValue || iReturn == BadWindow) { if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - " ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"XSendEvent () failed\n"); "xcb_send_event() failed\n");
} }
break; break;
} }
@ -567,18 +521,6 @@ winClipboardFlushXEvents(HWND hwnd,
goto winClipboardFlushXEvents_SelectionRequest_Done; 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 */ /* Get a pointer to the clipboard text, in desired format */
/* Retrieve clipboard data */ /* Retrieve clipboard data */
hGlobal = GetClipboardData(CF_UNICODETEXT); hGlobal = GetClipboardData(CF_UNICODETEXT);
@ -593,41 +535,61 @@ winClipboardFlushXEvents(HWND hwnd,
} }
pszGlobalData = (char *) GlobalLock(hGlobal); pszGlobalData = (char *) GlobalLock(hGlobal);
/* Convert the Unicode string to UTF8 (MBCS) */ /* Convert to target string style */
int iConvertDataLen = WideCharToMultiByte(CP_UTF8, if (selection_request->target == XCB_ATOM_STRING) {
0, codepage = CP_ISO_8559_1; // code page identifier for iso-8559-1
(LPCWSTR) pszGlobalData, } else if (selection_request->target == atomUTF8String) {
-1, NULL, 0, NULL, NULL); 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 */ /* NOTE: iConvertDataLen includes space for null terminator */
pszConvertData = malloc(iConvertDataLen); pszConvertData = malloc(iConvertDataLen);
WideCharToMultiByte(CP_UTF8, WideCharToMultiByte(codepage, 0,
0, (LPCWSTR) pszGlobalData, -1,
(LPCWSTR) pszGlobalData, pszConvertData, iConvertDataLen, NULL, NULL);
-1,
pszConvertData,
iConvertDataLen, NULL, NULL);
/* Convert DOS string to UNIX string */ /* Convert DOS string to UNIX string */
winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData)); winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData));
/* Setup our text list */ xtpText_value = strdup(pszConvertData);
pszTextList[0] = pszConvertData; xtpText_nitems = strlen(pszConvertData);
pszTextList[1] = NULL;
/* Initialize the text property */ /* data will fit into a single X request? (INCR not yet supported) */
xtpText.value = NULL; {
xtpText.nitems = 0; uint32_t maxreqsize = xcb_get_maximum_request_length(conn);
/* Create the text property from the text list */ /* covert to bytes and allow for allow for X_ChangeProperty request */
#ifdef X_HAVE_UTF8_STRING maxreqsize = maxreqsize*4 - 24;
iReturn = Xutf8TextListToTextProperty(pDisplay,
pszTextList,
1, xiccesStyle, &xtpText);
#endif
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 - " ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"X*TextListToTextProperty failed: %d\n", iReturn); "xcb_change_property failed\n");
/* Abort */ /* Abort */
fAbort = TRUE; fAbort = TRUE;
@ -638,43 +600,6 @@ winClipboardFlushXEvents(HWND hwnd,
free(pszConvertData); free(pszConvertData);
pszConvertData = NULL; 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 */ /* Release the clipboard data */
GlobalUnlock(hGlobal); GlobalUnlock(hGlobal);
pszGlobalData = NULL; pszGlobalData = NULL;
@ -682,27 +607,25 @@ winClipboardFlushXEvents(HWND hwnd,
CloseClipboard(); CloseClipboard();
/* Clean up */ /* Clean up */
XFree(xtpText.value); free(xtpText_value);
xtpText.value = NULL; xtpText_value = NULL;
xtpText.nitems = 0;
/* Setup selection notify event */ /* Setup selection notify event */
eventSelection.type = SelectionNotify; xcb_selection_notify_event_t eventSelection;
eventSelection.send_event = True; eventSelection.response_type = XCB_SELECTION_NOTIFY;
eventSelection.display = pDisplay; eventSelection.requestor = selection_request->requestor;
eventSelection.requestor = event.xselectionrequest.requestor; eventSelection.selection = selection_request->selection;
eventSelection.selection = event.xselectionrequest.selection; eventSelection.target = selection_request->target;
eventSelection.target = event.xselectionrequest.target; eventSelection.property = selection_request->property;
eventSelection.property = event.xselectionrequest.property; eventSelection.time = selection_request->time;
eventSelection.time = event.xselectionrequest.time;
/* Notify the requesting window that the operation has completed */ /* Notify the requesting window that the operation has completed */
iReturn = XSendEvent(pDisplay, cookie = xcb_send_event_checked(conn, FALSE,
eventSelection.requestor, eventSelection.requestor,
False, 0L, (XEvent *) &eventSelection); 0, (char *) &eventSelection);
if (iReturn == BadValue || iReturn == BadWindow) { if ((error = xcb_request_check(conn, cookie))) {
ErrorF("winClipboardFlushXEvents - SelectionRequest - " ErrorF("winClipboardFlushXEvents - SelectionRequest - "
"XSendEvent () failed\n"); "xcb_send_event() failed\n");
/* Abort */ /* Abort */
fAbort = TRUE; fAbort = TRUE;
@ -711,12 +634,11 @@ winClipboardFlushXEvents(HWND hwnd,
winClipboardFlushXEvents_SelectionRequest_Done: winClipboardFlushXEvents_SelectionRequest_Done:
/* Free allocated resources */ /* Free allocated resources */
if (xtpText.value) { if (xtpText_value) {
XFree(xtpText.value); free(xtpText_value);
xtpText.value = NULL;
xtpText.nitems = 0;
} }
free(pszConvertData); if (pszConvertData)
free(pszConvertData);
if (hGlobal && pszGlobalData) if (hGlobal && pszGlobalData)
GlobalUnlock(hGlobal); GlobalUnlock(hGlobal);
@ -726,26 +648,24 @@ winClipboardFlushXEvents(HWND hwnd,
*/ */
if (fAbort) { if (fAbort) {
/* Setup selection notify event */ /* Setup selection notify event */
eventSelection.type = SelectionNotify; eventSelection.response_type = XCB_SELECTION_NOTIFY;
eventSelection.send_event = True; eventSelection.requestor = selection_request->requestor;
eventSelection.display = pDisplay; eventSelection.selection = selection_request->selection;
eventSelection.requestor = event.xselectionrequest.requestor; eventSelection.target = selection_request->target;
eventSelection.selection = event.xselectionrequest.selection; eventSelection.property = XCB_NONE;
eventSelection.target = event.xselectionrequest.target; eventSelection.time = selection_request->time;
eventSelection.property = None;
eventSelection.time = event.xselectionrequest.time;
/* Notify the requesting window that the operation is complete */ /* Notify the requesting window that the operation is complete */
iReturn = XSendEvent(pDisplay, cookie = xcb_send_event_checked(conn, FALSE,
eventSelection.requestor, eventSelection.requestor,
False, 0L, (XEvent *) &eventSelection); 0, (char *) &eventSelection);
if (iReturn == BadValue || iReturn == BadWindow) { if ((error = xcb_request_check(conn, cookie))) {
/* /*
* Should not be a problem if XSendEvent fails because * Should not be a problem if XSendEvent fails because
* the client may simply have exited. * the client may simply have exited.
*/ */
ErrorF("winClipboardFlushXEvents - SelectionRequest - " 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(); CloseClipboard();
} }
break; break;
}
/* case XCB_SELECTION_NOTIFY:
* SelectionNotify {
*/ xcb_selection_notify_event_t *selection_notify = (xcb_selection_notify_event_t *)event;
case SelectionNotify:
winDebug("winClipboardFlushXEvents - SelectionNotify\n"); winDebug("winClipboardFlushXEvents - SelectionNotify\n");
{ {
char *pszAtomName; char *pszAtomName;
pszAtomName = get_atom_name(conn, selection_notify->selection);
pszAtomName = XGetAtomName(pDisplay, winDebug("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n", pszAtomName);
event.xselection.selection); free(pszAtomName);
winDebug
("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n",
pszAtomName);
XFree(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 (i) Generated by the X server if no owner for the specified selection exists
(perhaps it's disappeared on us mid-transaction), or (perhaps it's disappeared on us mid-transaction), or
(ii) Sent by the selection owner when the requested selection conversion could (ii) Sent by the selection owner when the requested selection conversion could
not be performed or server errors prevented the conversion data being returned 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 - " ErrorF("winClipboardFlushXEvents - SelectionNotify - "
"Conversion to format %ld refused.\n", "Conversion to format %d refused.\n",
event.xselection.target); selection_notify->target);
return WIN_XEVENTS_FAILED; return WIN_XEVENTS_FAILED;
} }
if (event.xselection.target == atomTargets) { if (selection_notify->target == atomTargets) {
return winClipboardSelectionNotifyTargets(hwnd, iWindow, pDisplay, data, atoms); 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"); winDebug("SelectionClear - doing nothing\n");
break; 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 INCR is in progress, collect the data */
if (data->incr && if (data->incr &&
(event.xproperty.atom == atoms->atomLocalProperty) && (property_notify->atom == atoms->atomLocalProperty) &&
(event.xproperty.state == PropertyNewValue)) (property_notify->state == XCB_PROPERTY_NEW_VALUE))
return winClipboardSelectionNotifyData(hwnd, iWindow, pDisplay, data, atoms); return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms);
break; 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; break;
default: default:
if (event.type == XFixesSetSelectionOwnerNotify + xfixes_event_base) { if ((event->response_type & ~0x80) == XCB_XFIXES_SELECTION_EVENT_SET_SELECTION_OWNER + xfixes_event_base) {
XFixesSelectionNotifyEvent *e = xcb_xfixes_selection_notify_event_t *e = (xcb_xfixes_selection_notify_event_t *)event;
(XFixesSelectionNotifyEvent *) & event;
winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n"); winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n");
/* Save selection owners for monitored selections, ignore other selections */ /* 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); MonitorSelection(e, CLIP_OWN_PRIMARY);
} }
else if (e->selection == atomClipboard) { else if (e->selection == atomClipboard) {
@ -829,9 +757,8 @@ winClipboardFlushXEvents(HWND hwnd,
break; break;
/* Selection is being disowned */ /* Selection is being disowned */
if (e->owner == None) { if (e->owner == XCB_NONE) {
winDebug winDebug("winClipboardFlushXEvents - No window, returning.\n");
("winClipboardFlushXEvents - No window, returning.\n");
break; break;
} }
@ -878,15 +805,25 @@ winClipboardFlushXEvents(HWND hwnd,
break; break;
} }
} }
/* XFixesSelectionWindowDestroyNotifyMask */ /* XCB_XFIXES_SELECTION_EVENT_SELECTION_WINDOW_DESTROY */
/* XFixesSelectionClientCloseNotifyMask */ /* XCB_XFIXES_SELECTION_EVENT_SELECTION_CLIENT_CLOSE */
else { else {
ErrorF("winClipboardFlushXEvents - unexpected event type %d\n", ErrorF("winClipboardFlushXEvents - unexpected event type %d\n",
event.type); event->response_type);
} }
break; 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; return WIN_XEVENTS_SUCCESS;
} }

View File

@ -35,27 +35,10 @@
#include <xwin-config.h> #include <xwin-config.h>
#endif #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 <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.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" #include "winclipboard.h"
/* /*
@ -87,7 +70,7 @@ main (int argc, char *argv[])
/* Look for -noprimary */ /* Look for -noprimary */
if (!strcmp (argv[i], "-noprimary")) if (!strcmp (argv[i], "-noprimary"))
{ {
fPrimarySelection = False; fPrimarySelection = 0;
continue; continue;
} }
@ -96,21 +79,7 @@ main (int argc, char *argv[])
exit (1); exit (1);
} }
/* Apply locale specified in the LANG environment variable */ winClipboardProc(pszDisplay, NULL /* Use XAUTHORITY for auth data */);
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);
return 0; return 0;
} }

View File

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