sync code with last improvements from OpenBSD
This commit is contained in:
commit
88965415ff
26235 changed files with 29195616 additions and 0 deletions
26
xserver/hw/xwin/winclipboard/Makefile.am
Normal file
26
xserver/hw/xwin/winclipboard/Makefile.am
Normal file
|
@ -0,0 +1,26 @@
|
|||
noinst_LTLIBRARIES = libXWinclipboard.la
|
||||
|
||||
libXWinclipboard_la_SOURCES = \
|
||||
internal.h \
|
||||
winclipboard.h \
|
||||
textconv.c \
|
||||
thread.c \
|
||||
wndproc.c \
|
||||
xevents.c
|
||||
|
||||
libXWinclipboard_la_CFLAGS = -DHAVE_XWIN_CONFIG_H \
|
||||
$(DIX_CFLAGS) \
|
||||
$(XWINMODULES_CFLAGS)
|
||||
|
||||
libXWinclipboard_la_LDFLAGS = -static -no-undefined
|
||||
|
||||
bin_PROGRAMS = xwinclip
|
||||
|
||||
xwinclip_SOURCES = xwinclip.c debug.c
|
||||
|
||||
xwinclip_CFLAGS = $(XWINMODULES_CFLAGS)
|
||||
|
||||
xwinclip_LDADD = libXWinclipboard.la $(XWINMODULES_LIBS) -lgdi32 -lpthread
|
||||
|
||||
include $(top_srcdir)/manpages.am
|
||||
appman_PRE = xwinclip.man
|
1057
xserver/hw/xwin/winclipboard/Makefile.in
Normal file
1057
xserver/hw/xwin/winclipboard/Makefile.in
Normal file
File diff suppressed because it is too large
Load diff
52
xserver/hw/xwin/winclipboard/debug.c
Normal file
52
xserver/hw/xwin/winclipboard/debug.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// Copyright © Jon TURNEY 2013
|
||||
//
|
||||
// This file is part of xwinclip.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice (including the next
|
||||
// paragraph) shall be included in all copies or substantial portions of the
|
||||
// Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if 1
|
||||
int
|
||||
winDebug(const char *format, ...)
|
||||
{
|
||||
int count;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
count = fprintf(stderr, "xwinclip: ");
|
||||
count += vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
ErrorF(const char *format, ...)
|
||||
{
|
||||
int count;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
count = vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
return count;
|
||||
}
|
119
xserver/hw/xwin/winclipboard/internal.h
Normal file
119
xserver/hw/xwin/winclipboard/internal.h
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
|
||||
*
|
||||
*Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
*"Software"), to deal in the Software without restriction, including
|
||||
*without limitation the rights to use, copy, modify, merge, publish,
|
||||
*distribute, sublicense, and/or sell copies of the Software, and to
|
||||
*permit persons to whom the Software is furnished to do so, subject to
|
||||
*the following conditions:
|
||||
*
|
||||
*The above copyright notice and this permission notice shall be
|
||||
*included in all copies or substantial portions of the Software.
|
||||
*
|
||||
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
*NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
|
||||
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*Except as contained in this notice, the name of Harold L Hunt II
|
||||
*shall not be used in advertising or otherwise to promote the sale, use
|
||||
*or other dealings in this Software without prior written authorization
|
||||
*from Harold L Hunt II.
|
||||
*
|
||||
* Authors: Harold L Hunt II
|
||||
*/
|
||||
|
||||
#ifndef WINCLIPBOARD_INTERNAL_H
|
||||
#define WINCLIPBOARD_INTERNAL_H
|
||||
|
||||
#include <xcb/xproto.h>
|
||||
#include <X11/Xfuncproto.h> // for _X_ATTRIBUTE_PRINTF
|
||||
#include <X11/Xmd.h> // for BOOL
|
||||
|
||||
/* Windows headers */
|
||||
#include <X11/Xwindows.h>
|
||||
|
||||
#define WIN_XEVENTS_SUCCESS 0 // more like 'CONTINUE'
|
||||
#define WIN_XEVENTS_FAILED 1
|
||||
#define WIN_XEVENTS_NOTIFY_DATA 3
|
||||
#define WIN_XEVENTS_NOTIFY_TARGETS 4
|
||||
|
||||
#define WM_WM_QUIT (WM_USER + 2)
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
|
||||
|
||||
/*
|
||||
* References to external symbols
|
||||
*/
|
||||
|
||||
extern void winDebug(const char *format, ...) _X_ATTRIBUTE_PRINTF(1, 2);
|
||||
extern void ErrorF(const char *format, ...) _X_ATTRIBUTE_PRINTF(1, 2);
|
||||
|
||||
/*
|
||||
* winclipboardtextconv.c
|
||||
*/
|
||||
|
||||
void
|
||||
winClipboardDOStoUNIX(char *pszData, int iLength);
|
||||
|
||||
void
|
||||
winClipboardUNIXtoDOS(char **ppszData, int iLength);
|
||||
|
||||
/*
|
||||
* winclipboardthread.c
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
xcb_atom_t atomClipboard;
|
||||
xcb_atom_t atomLocalProperty;
|
||||
xcb_atom_t atomUTF8String;
|
||||
xcb_atom_t atomCompoundText;
|
||||
xcb_atom_t atomTargets;
|
||||
xcb_atom_t atomIncr;
|
||||
} ClipboardAtoms;
|
||||
|
||||
/*
|
||||
* winclipboardwndproc.c
|
||||
*/
|
||||
|
||||
BOOL winClipboardFlushWindowsMessageQueue(HWND hwnd);
|
||||
|
||||
LRESULT CALLBACK
|
||||
winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
xcb_connection_t *pClipboardDisplay;
|
||||
xcb_window_t iClipboardWindow;
|
||||
ClipboardAtoms *atoms;
|
||||
} ClipboardWindowCreationParams;
|
||||
|
||||
/*
|
||||
* winclipboardxevents.c
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
xcb_atom_t *targetList;
|
||||
unsigned char *incr;
|
||||
unsigned long int incrsize;
|
||||
} ClipboardConversionData;
|
||||
|
||||
int
|
||||
winClipboardFlushXEvents(HWND hwnd,
|
||||
xcb_window_t iWindow, xcb_connection_t * pDisplay,
|
||||
ClipboardConversionData *data, ClipboardAtoms *atoms);
|
||||
|
||||
xcb_atom_t
|
||||
winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms);
|
||||
|
||||
void
|
||||
winClipboardInitMonitoredSelections(void);
|
||||
|
||||
#endif
|
41
xserver/hw/xwin/winclipboard/meson.build
Normal file
41
xserver/hw/xwin/winclipboard/meson.build
Normal file
|
@ -0,0 +1,41 @@
|
|||
srcs_windows_clipboard = [
|
||||
'winclipboard.h',
|
||||
'textconv.c',
|
||||
'thread.c',
|
||||
'wndproc.c',
|
||||
'xevents.c',
|
||||
]
|
||||
|
||||
xwin_clipboard = static_library(
|
||||
'XWinclipboard',
|
||||
srcs_windows_clipboard,
|
||||
include_directories: inc,
|
||||
c_args: '-DHAVE_XWIN_CONFIG_H',
|
||||
dependencies: [
|
||||
dependency('xcb'),
|
||||
dependency('xcb-aux'),
|
||||
dependency('xcb-icccm'),
|
||||
dependency('xcb-xfixes'),
|
||||
socket_dep,
|
||||
],
|
||||
)
|
||||
|
||||
srcs_xwinclip = [
|
||||
'xwinclip.c',
|
||||
'debug.c',
|
||||
]
|
||||
|
||||
executable(
|
||||
'xwinclip',
|
||||
srcs_xwinclip,
|
||||
link_with: xwin_clipboard,
|
||||
link_args: ['-lgdi32', '-lpthread'],
|
||||
install: true,
|
||||
)
|
||||
|
||||
xwinclip_man = configure_file(
|
||||
input: 'xwinclip.man',
|
||||
output: 'xwinclip.1',
|
||||
configuration: manpage_config,
|
||||
)
|
||||
install_man(xwinclip_man)
|
142
xserver/hw/xwin/winclipboard/textconv.c
Normal file
142
xserver/hw/xwin/winclipboard/textconv.c
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
|
||||
*
|
||||
*Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
*"Software"), to deal in the Software without restriction, including
|
||||
*without limitation the rights to use, copy, modify, merge, publish,
|
||||
*distribute, sublicense, and/or sell copies of the Software, and to
|
||||
*permit persons to whom the Software is furnished to do so, subject to
|
||||
*the following conditions:
|
||||
*
|
||||
*The above copyright notice and this permission notice shall be
|
||||
*included in all copies or substantial portions of the Software.
|
||||
*
|
||||
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
*NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
|
||||
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*Except as contained in this notice, the name of Harold L Hunt II
|
||||
*shall not be used in advertising or otherwise to promote the sale, use
|
||||
*or other dealings in this Software without prior written authorization
|
||||
*from Harold L Hunt II.
|
||||
*
|
||||
* Authors: Harold L Hunt II
|
||||
*/
|
||||
|
||||
#ifdef HAVE_XWIN_CONFIG_H
|
||||
#include <xwin-config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Convert \r\n to \n
|
||||
*
|
||||
* NOTE: This was heavily inspired by, Cygwin's
|
||||
* winsup/cygwin/fhandler.cc/fhandler_base::read ()
|
||||
*/
|
||||
|
||||
void
|
||||
winClipboardDOStoUNIX(char *pszSrc, int iLength)
|
||||
{
|
||||
char *pszDest = pszSrc;
|
||||
char *pszEnd = pszSrc + iLength;
|
||||
|
||||
/* Loop until the last character */
|
||||
while (pszSrc < pszEnd) {
|
||||
/* Copy the current source character to current destination character */
|
||||
*pszDest = *pszSrc;
|
||||
|
||||
/* Advance to the next source character */
|
||||
pszSrc++;
|
||||
|
||||
/* Don't advance the destination character if we need to drop an \r */
|
||||
if (*pszDest != '\r' || *pszSrc != '\n')
|
||||
pszDest++;
|
||||
}
|
||||
|
||||
/* Move the terminating null */
|
||||
*pszDest = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert \n to \r\n
|
||||
*/
|
||||
|
||||
void
|
||||
winClipboardUNIXtoDOS(char **ppszData, int iLength)
|
||||
{
|
||||
int iNewlineCount = 0;
|
||||
char *pszSrc = *ppszData;
|
||||
char *pszEnd = pszSrc + iLength;
|
||||
char *pszDest = NULL, *pszDestBegin = NULL;
|
||||
|
||||
winDebug("UNIXtoDOS () - Original data:'%s'\n", *ppszData);
|
||||
|
||||
/* Count \n characters without leading \r */
|
||||
while (pszSrc < pszEnd) {
|
||||
/* Skip ahead two character if found set of \r\n */
|
||||
if (*pszSrc == '\r' && pszSrc + 1 < pszEnd && *(pszSrc + 1) == '\n') {
|
||||
pszSrc += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Increment the count if found naked \n */
|
||||
if (*pszSrc == '\n') {
|
||||
iNewlineCount++;
|
||||
}
|
||||
|
||||
pszSrc++;
|
||||
}
|
||||
|
||||
/* Return if no naked \n's */
|
||||
if (iNewlineCount == 0)
|
||||
return;
|
||||
|
||||
/* Allocate a new string */
|
||||
pszDestBegin = pszDest = malloc(iLength + iNewlineCount + 1);
|
||||
|
||||
/* Set source pointer to beginning of data string */
|
||||
pszSrc = *ppszData;
|
||||
|
||||
/* Loop through all characters in source string */
|
||||
while (pszSrc < pszEnd) {
|
||||
/* Copy line endings that are already valid */
|
||||
if (*pszSrc == '\r' && pszSrc + 1 < pszEnd && *(pszSrc + 1) == '\n') {
|
||||
*pszDest = *pszSrc;
|
||||
*(pszDest + 1) = *(pszSrc + 1);
|
||||
pszDest += 2;
|
||||
pszSrc += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add \r to naked \n's */
|
||||
if (*pszSrc == '\n') {
|
||||
*pszDest = '\r';
|
||||
*(pszDest + 1) = *pszSrc;
|
||||
pszDest += 2;
|
||||
pszSrc += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Copy normal characters */
|
||||
*pszDest = *pszSrc;
|
||||
pszSrc++;
|
||||
pszDest++;
|
||||
}
|
||||
|
||||
/* Put terminating null at end of new string */
|
||||
*pszDest = '\0';
|
||||
|
||||
/* Swap string pointers */
|
||||
free(*ppszData);
|
||||
*ppszData = pszDestBegin;
|
||||
|
||||
winDebug("UNIXtoDOS () - Final string:'%s'\n", pszDestBegin);
|
||||
}
|
439
xserver/hw/xwin/winclipboard/thread.c
Normal file
439
xserver/hw/xwin/winclipboard/thread.c
Normal file
|
@ -0,0 +1,439 @@
|
|||
/*
|
||||
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
|
||||
*Copyright (C) Colin Harrison 2005-2008
|
||||
*
|
||||
*Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
*"Software"), to deal in the Software without restriction, including
|
||||
*without limitation the rights to use, copy, modify, merge, publish,
|
||||
*distribute, sublicense, and/or sell copies of the Software, and to
|
||||
*permit persons to whom the Software is furnished to do so, subject to
|
||||
*the following conditions:
|
||||
*
|
||||
*The above copyright notice and this permission notice shall be
|
||||
*included in all copies or substantial portions of the Software.
|
||||
*
|
||||
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
*NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
|
||||
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*Except as contained in this notice, the name of the copyright holder(s)
|
||||
*and author(s) shall not be used in advertising or otherwise to promote
|
||||
*the sale, use or other dealings in this Software without prior written
|
||||
*authorization from the copyright holder(s) and author(s).
|
||||
*
|
||||
* Authors: Harold L Hunt II
|
||||
* Colin Harrison
|
||||
*/
|
||||
|
||||
#ifdef HAVE_XWIN_CONFIG_H
|
||||
#include <xwin-config.h>
|
||||
#else
|
||||
#define HAS_WINSOCK 1
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/param.h> // for MAX() macro
|
||||
|
||||
#ifdef HAS_WINSOCK
|
||||
#include <X11/Xwinsock.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_aux.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#include <xcb/xfixes.h>
|
||||
|
||||
#include "winclipboard.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define WIN_CONNECT_RETRIES 40
|
||||
#define WIN_CONNECT_DELAY 4
|
||||
|
||||
#define WIN_CLIPBOARD_WINDOW_CLASS "xwinclip"
|
||||
#define WIN_CLIPBOARD_WINDOW_TITLE "xwinclip"
|
||||
#ifdef HAS_DEVWINDOWS
|
||||
#define WIN_MSG_QUEUE_FNAME "/dev/windows"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
|
||||
static HWND g_hwndClipboard = NULL;
|
||||
|
||||
int xfixes_event_base;
|
||||
int xfixes_error_base;
|
||||
|
||||
/*
|
||||
* Local function prototypes
|
||||
*/
|
||||
|
||||
static HWND
|
||||
winClipboardCreateMessagingWindow(xcb_connection_t *conn, xcb_window_t iWindow, ClipboardAtoms *atoms);
|
||||
|
||||
static xcb_atom_t
|
||||
intern_atom(xcb_connection_t *conn, const char *atomName)
|
||||
{
|
||||
xcb_intern_atom_reply_t *atom_reply;
|
||||
xcb_intern_atom_cookie_t atom_cookie;
|
||||
xcb_atom_t atom = XCB_ATOM_NONE;
|
||||
|
||||
atom_cookie = xcb_intern_atom(conn, 0, strlen(atomName), atomName);
|
||||
atom_reply = xcb_intern_atom_reply(conn, atom_cookie, NULL);
|
||||
if (atom_reply) {
|
||||
atom = atom_reply->atom;
|
||||
free(atom_reply);
|
||||
}
|
||||
return atom;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create X11 and Win32 messaging windows, and run message processing loop
|
||||
*
|
||||
* returns TRUE if shutdown was signalled to loop, FALSE if some error occurred
|
||||
*/
|
||||
|
||||
BOOL
|
||||
winClipboardProc(char *szDisplay, xcb_auth_info_t *auth_info)
|
||||
{
|
||||
ClipboardAtoms atoms;
|
||||
int iReturn;
|
||||
HWND hwnd = NULL;
|
||||
int iConnectionNumber = 0;
|
||||
#ifdef HAS_DEVWINDOWS
|
||||
int fdMessageQueue = 0;
|
||||
#else
|
||||
struct timeval tvTimeout;
|
||||
#endif
|
||||
fd_set fdsRead;
|
||||
int iMaxDescriptor;
|
||||
xcb_connection_t *conn;
|
||||
xcb_window_t iWindow = XCB_NONE;
|
||||
int iSelectError;
|
||||
BOOL fShutdown = FALSE;
|
||||
ClipboardConversionData data;
|
||||
int screen;
|
||||
|
||||
winDebug("winClipboardProc - Hello\n");
|
||||
|
||||
/* Make sure that the display opened */
|
||||
conn = xcb_connect_to_display_with_auth_info(szDisplay, auth_info, &screen);
|
||||
if (xcb_connection_has_error(conn)) {
|
||||
ErrorF("winClipboardProc - Failed opening the display, giving up\n");
|
||||
goto winClipboardProc_Done;
|
||||
}
|
||||
|
||||
ErrorF("winClipboardProc - xcb_connect () returned and "
|
||||
"successfully opened the display.\n");
|
||||
|
||||
/* Get our connection number */
|
||||
iConnectionNumber = xcb_get_file_descriptor(conn);
|
||||
|
||||
#ifdef HAS_DEVWINDOWS
|
||||
/* Open a file descriptor for the windows message queue */
|
||||
fdMessageQueue = open(WIN_MSG_QUEUE_FNAME, O_RDONLY);
|
||||
if (fdMessageQueue == -1) {
|
||||
ErrorF("winClipboardProc - Failed opening %s\n", WIN_MSG_QUEUE_FNAME);
|
||||
goto winClipboardProc_Done;
|
||||
}
|
||||
|
||||
/* Find max of our file descriptors */
|
||||
iMaxDescriptor = MAX(fdMessageQueue, iConnectionNumber) + 1;
|
||||
#else
|
||||
iMaxDescriptor = iConnectionNumber + 1;
|
||||
#endif
|
||||
|
||||
const xcb_query_extension_reply_t *xfixes_query;
|
||||
xfixes_query = xcb_get_extension_data(conn, &xcb_xfixes_id);
|
||||
if (!xfixes_query->present)
|
||||
ErrorF ("winClipboardProc - XFixes extension not present\n");
|
||||
xfixes_event_base = xfixes_query->first_event;
|
||||
xfixes_error_base = xfixes_query->first_error;
|
||||
/* Must advise server of XFIXES version we require */
|
||||
xcb_xfixes_query_version_unchecked(conn, 1, 0);
|
||||
|
||||
/* Create atoms */
|
||||
atoms.atomClipboard = intern_atom(conn, "CLIPBOARD");
|
||||
atoms.atomLocalProperty = intern_atom(conn, "CYGX_CUT_BUFFER");
|
||||
atoms.atomUTF8String = intern_atom(conn, "UTF8_STRING");
|
||||
atoms.atomCompoundText = intern_atom(conn, "COMPOUND_TEXT");
|
||||
atoms.atomTargets = intern_atom(conn, "TARGETS");
|
||||
atoms.atomIncr = intern_atom(conn, "INCR");
|
||||
|
||||
xcb_screen_t *root_screen = xcb_aux_get_screen(conn, screen);
|
||||
xcb_window_t root_window_id = root_screen->root;
|
||||
|
||||
/* Create a messaging window */
|
||||
iWindow = xcb_generate_id(conn);
|
||||
xcb_void_cookie_t cookie = xcb_create_window_checked(conn,
|
||||
XCB_COPY_FROM_PARENT,
|
||||
iWindow,
|
||||
root_window_id,
|
||||
1, 1,
|
||||
500, 500,
|
||||
0,
|
||||
XCB_WINDOW_CLASS_INPUT_ONLY,
|
||||
XCB_COPY_FROM_PARENT,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
xcb_generic_error_t *error;
|
||||
if ((error = xcb_request_check(conn, cookie))) {
|
||||
ErrorF("winClipboardProc - Could not create an X window.\n");
|
||||
free(error);
|
||||
goto winClipboardProc_Done;
|
||||
}
|
||||
|
||||
xcb_icccm_set_wm_name(conn, iWindow, XCB_ATOM_STRING, 8, strlen("xwinclip"), "xwinclip");
|
||||
|
||||
/* Select event types to watch */
|
||||
const static uint32_t values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
|
||||
cookie = xcb_change_window_attributes_checked(conn, iWindow, XCB_CW_EVENT_MASK, values);
|
||||
if ((error = xcb_request_check(conn, cookie))) {
|
||||
ErrorF("winClipboardProc - Could not set event mask on messaging window\n");
|
||||
free(error);
|
||||
}
|
||||
|
||||
xcb_xfixes_select_selection_input(conn,
|
||||
iWindow,
|
||||
XCB_ATOM_PRIMARY,
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE);
|
||||
|
||||
xcb_xfixes_select_selection_input(conn,
|
||||
iWindow,
|
||||
atoms.atomClipboard,
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE);
|
||||
|
||||
/* Initialize monitored selection state */
|
||||
winClipboardInitMonitoredSelections();
|
||||
/* Create Windows messaging window */
|
||||
hwnd = winClipboardCreateMessagingWindow(conn, iWindow, &atoms);
|
||||
|
||||
/* Save copy of HWND */
|
||||
g_hwndClipboard = hwnd;
|
||||
|
||||
/* Assert ownership of selections if Win32 clipboard is owned */
|
||||
if (NULL != GetClipboardOwner()) {
|
||||
/* PRIMARY */
|
||||
cookie = xcb_set_selection_owner_checked(conn, iWindow, XCB_ATOM_PRIMARY, XCB_CURRENT_TIME);
|
||||
if ((error = xcb_request_check(conn, cookie))) {
|
||||
ErrorF("winClipboardProc - Could not set PRIMARY owner\n");
|
||||
free(error);
|
||||
goto winClipboardProc_Done;
|
||||
}
|
||||
|
||||
/* CLIPBOARD */
|
||||
cookie = xcb_set_selection_owner_checked(conn, iWindow, atoms.atomClipboard, XCB_CURRENT_TIME);
|
||||
if ((error = xcb_request_check(conn, cookie))) {
|
||||
ErrorF("winClipboardProc - Could not set CLIPBOARD owner\n");
|
||||
free(error);
|
||||
goto winClipboardProc_Done;
|
||||
}
|
||||
}
|
||||
|
||||
data.incr = NULL;
|
||||
data.incrsize = 0;
|
||||
|
||||
/* Loop for events */
|
||||
while (1) {
|
||||
|
||||
/* Process X events */
|
||||
winClipboardFlushXEvents(hwnd, iWindow, conn, &data, &atoms);
|
||||
|
||||
/* Process Windows messages */
|
||||
if (!winClipboardFlushWindowsMessageQueue(hwnd)) {
|
||||
ErrorF("winClipboardProc - winClipboardFlushWindowsMessageQueue trapped "
|
||||
"WM_QUIT message, exiting main loop.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* We need to ensure that all pending requests are sent */
|
||||
xcb_flush(conn);
|
||||
|
||||
/* Setup the file descriptor set */
|
||||
/*
|
||||
* NOTE: You have to do this before every call to select
|
||||
* because select modifies the mask to indicate
|
||||
* which descriptors are ready.
|
||||
*/
|
||||
FD_ZERO(&fdsRead);
|
||||
FD_SET(iConnectionNumber, &fdsRead);
|
||||
#ifdef HAS_DEVWINDOWS
|
||||
FD_SET(fdMessageQueue, &fdsRead);
|
||||
#else
|
||||
tvTimeout.tv_sec = 0;
|
||||
tvTimeout.tv_usec = 100;
|
||||
#endif
|
||||
|
||||
/* Wait for a Windows event or an X event */
|
||||
iReturn = select(iMaxDescriptor, /* Highest fds number */
|
||||
&fdsRead, /* Read mask */
|
||||
NULL, /* No write mask */
|
||||
NULL, /* No exception mask */
|
||||
#ifdef HAS_DEVWINDOWS
|
||||
NULL /* No timeout */
|
||||
#else
|
||||
&tvTimeout /* Set timeout */
|
||||
#endif
|
||||
);
|
||||
|
||||
#ifndef HAS_WINSOCK
|
||||
iSelectError = errno;
|
||||
#else
|
||||
iSelectError = WSAGetLastError();
|
||||
#endif
|
||||
|
||||
if (iReturn < 0) {
|
||||
#ifndef HAS_WINSOCK
|
||||
if (iSelectError == EINTR)
|
||||
#else
|
||||
if (iSelectError == WSAEINTR)
|
||||
#endif
|
||||
continue;
|
||||
|
||||
ErrorF("winClipboardProc - Call to select () failed: %d. "
|
||||
"Bailing.\n", iReturn);
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(iConnectionNumber, &fdsRead)) {
|
||||
winDebug
|
||||
("winClipboardProc - X connection ready, pumping X event queue\n");
|
||||
}
|
||||
|
||||
#ifdef HAS_DEVWINDOWS
|
||||
/* Check for Windows event ready */
|
||||
if (FD_ISSET(fdMessageQueue, &fdsRead))
|
||||
#else
|
||||
if (1)
|
||||
#endif
|
||||
{
|
||||
winDebug
|
||||
("winClipboardProc - /dev/windows ready, pumping Windows message queue\n");
|
||||
}
|
||||
|
||||
#ifdef HAS_DEVWINDOWS
|
||||
if (!(FD_ISSET(iConnectionNumber, &fdsRead)) &&
|
||||
!(FD_ISSET(fdMessageQueue, &fdsRead))) {
|
||||
winDebug("winClipboardProc - Spurious wake, select() returned %d\n", iReturn);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* broke out of while loop on a shutdown message */
|
||||
fShutdown = TRUE;
|
||||
|
||||
winClipboardProc_Done:
|
||||
/* Close our Windows window */
|
||||
if (g_hwndClipboard) {
|
||||
DestroyWindow(g_hwndClipboard);
|
||||
}
|
||||
|
||||
/* Close our X window */
|
||||
if (!xcb_connection_has_error(conn) && iWindow) {
|
||||
cookie = xcb_destroy_window_checked(conn, iWindow);
|
||||
if ((error = xcb_request_check(conn, cookie)))
|
||||
ErrorF("winClipboardProc - XDestroyWindow failed.\n");
|
||||
else
|
||||
ErrorF("winClipboardProc - XDestroyWindow succeeded.\n");
|
||||
free(error);
|
||||
}
|
||||
|
||||
#ifdef HAS_DEVWINDOWS
|
||||
/* Close our Win32 message handle */
|
||||
if (fdMessageQueue)
|
||||
close(fdMessageQueue);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* xcb_disconnect() does not sync, so is safe to call even when we are built
|
||||
* into the server. Unlike XCloseDisplay() there will be no deadlock if the
|
||||
* server is in the process of exiting and waiting for this thread to exit.
|
||||
*/
|
||||
if (!xcb_connection_has_error(conn)) {
|
||||
/* Close our X display */
|
||||
xcb_disconnect(conn);
|
||||
}
|
||||
|
||||
/* global clipboard variable reset */
|
||||
g_hwndClipboard = NULL;
|
||||
|
||||
return fShutdown;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the Windows window that we use to receive Windows messages
|
||||
*/
|
||||
|
||||
static HWND
|
||||
winClipboardCreateMessagingWindow(xcb_connection_t *conn, xcb_window_t iWindow, ClipboardAtoms *atoms)
|
||||
{
|
||||
WNDCLASSEX wc;
|
||||
ClipboardWindowCreationParams cwcp;
|
||||
HWND hwnd;
|
||||
|
||||
/* Setup our window class */
|
||||
wc.cbSize = sizeof(WNDCLASSEX);
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = winClipboardWindowProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = GetModuleHandle(NULL);
|
||||
wc.hIcon = 0;
|
||||
wc.hCursor = 0;
|
||||
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = WIN_CLIPBOARD_WINDOW_CLASS;
|
||||
wc.hIconSm = 0;
|
||||
RegisterClassEx(&wc);
|
||||
|
||||
/* Information to be passed to WM_CREATE */
|
||||
cwcp.pClipboardDisplay = conn;
|
||||
cwcp.iClipboardWindow = iWindow;
|
||||
cwcp.atoms = atoms;
|
||||
|
||||
/* Create the window */
|
||||
hwnd = CreateWindowExA(0, /* Extended styles */
|
||||
WIN_CLIPBOARD_WINDOW_CLASS, /* Class name */
|
||||
WIN_CLIPBOARD_WINDOW_TITLE, /* Window name */
|
||||
WS_OVERLAPPED, /* Not visible anyway */
|
||||
CW_USEDEFAULT, /* Horizontal position */
|
||||
CW_USEDEFAULT, /* Vertical position */
|
||||
CW_USEDEFAULT, /* Right edge */
|
||||
CW_USEDEFAULT, /* Bottom edge */
|
||||
(HWND) NULL, /* No parent or owner window */
|
||||
(HMENU) NULL, /* No menu */
|
||||
GetModuleHandle(NULL), /* Instance handle */
|
||||
&cwcp); /* Creation data */
|
||||
assert(hwnd != NULL);
|
||||
|
||||
/* I'm not sure, but we may need to call this to start message processing */
|
||||
ShowWindow(hwnd, SW_HIDE);
|
||||
|
||||
/* Similarly, we may need a call to this even though we don't paint */
|
||||
UpdateWindow(hwnd);
|
||||
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
void
|
||||
winClipboardWindowDestroy(void)
|
||||
{
|
||||
if (g_hwndClipboard) {
|
||||
SendMessage(g_hwndClipboard, WM_WM_QUIT, 0, 0);
|
||||
}
|
||||
}
|
41
xserver/hw/xwin/winclipboard/winclipboard.h
Normal file
41
xserver/hw/xwin/winclipboard/winclipboard.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Copyright © Jon TURNEY 2013
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice (including the next
|
||||
// paragraph) shall be included in all copies or substantial portions of the
|
||||
// Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// File: winclipboard.h
|
||||
// Purpose: public interface to winclipboard library
|
||||
//
|
||||
|
||||
#ifndef WINCLIPBOARD_H
|
||||
#define WINCLIPBOARD_H
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
#include <X11/Xmd.h> // for BOOL type
|
||||
|
||||
BOOL winClipboardProc(char *szDisplay, xcb_auth_info_t *auth_info);
|
||||
|
||||
void winFixClipboardChain(void);
|
||||
|
||||
void winClipboardWindowDestroy(void);
|
||||
|
||||
extern BOOL fPrimarySelection;
|
||||
|
||||
#endif
|
462
xserver/hw/xwin/winclipboard/wndproc.c
Normal file
462
xserver/hw/xwin/winclipboard/wndproc.c
Normal file
|
@ -0,0 +1,462 @@
|
|||
/*
|
||||
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
|
||||
*Copyright (C) Colin Harrison 2005-2008
|
||||
*
|
||||
*Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
*"Software"), to deal in the Software without restriction, including
|
||||
*without limitation the rights to use, copy, modify, merge, publish,
|
||||
*distribute, sublicense, and/or sell copies of the Software, and to
|
||||
*permit persons to whom the Software is furnished to do so, subject to
|
||||
*the following conditions:
|
||||
*
|
||||
*The above copyright notice and this permission notice shall be
|
||||
*included in all copies or substantial portions of the Software.
|
||||
*
|
||||
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
*NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
|
||||
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*Except as contained in this notice, the name of the copyright holder(s)
|
||||
*and author(s) shall not be used in advertising or otherwise to promote
|
||||
*the sale, use or other dealings in this Software without prior written
|
||||
*authorization from the copyright holder(s) and author(s).
|
||||
*
|
||||
* Authors: Harold L Hunt II
|
||||
* Colin Harrison
|
||||
*/
|
||||
|
||||
#define WINVER 0x0600
|
||||
|
||||
#ifdef HAVE_XWIN_CONFIG_H
|
||||
#include <xwin-config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <xcb/xproto.h>
|
||||
#include <xcb/xcb_aux.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "winclipboard.h"
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
|
||||
#define WIN_POLL_TIMEOUT 1
|
||||
|
||||
/*
|
||||
* Process X events up to specified timeout
|
||||
*/
|
||||
|
||||
static int
|
||||
winProcessXEventsTimeout(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn,
|
||||
ClipboardConversionData *data, ClipboardAtoms *atoms, int iTimeoutSec)
|
||||
{
|
||||
int iConnNumber;
|
||||
struct timeval tv;
|
||||
int iReturn;
|
||||
|
||||
winDebug("winProcessXEventsTimeout () - pumping X events, timeout %d seconds\n",
|
||||
iTimeoutSec);
|
||||
|
||||
/* Get our connection number */
|
||||
iConnNumber = xcb_get_file_descriptor(conn);
|
||||
|
||||
/* Loop for X events */
|
||||
while (1) {
|
||||
fd_set fdsRead;
|
||||
long remainingTime;
|
||||
|
||||
/* Process X events */
|
||||
iReturn = winClipboardFlushXEvents(hwnd, iWindow, conn, data, atoms);
|
||||
|
||||
winDebug("winProcessXEventsTimeout () - winClipboardFlushXEvents returned %d\n", iReturn);
|
||||
|
||||
if ((WIN_XEVENTS_NOTIFY_DATA == iReturn) || (WIN_XEVENTS_NOTIFY_TARGETS == iReturn) || (WIN_XEVENTS_FAILED == iReturn)) {
|
||||
/* Bail out */
|
||||
return iReturn;
|
||||
}
|
||||
|
||||
/* We need to ensure that all pending requests are sent */
|
||||
xcb_flush(conn);
|
||||
|
||||
/* Setup the file descriptor set */
|
||||
FD_ZERO(&fdsRead);
|
||||
FD_SET(iConnNumber, &fdsRead);
|
||||
|
||||
/* Adjust timeout */
|
||||
remainingTime = iTimeoutSec * 1000;
|
||||
tv.tv_sec = remainingTime / 1000;
|
||||
tv.tv_usec = (remainingTime % 1000) * 1000;
|
||||
|
||||
/* Break out if no time left */
|
||||
if (remainingTime <= 0)
|
||||
return WIN_XEVENTS_SUCCESS;
|
||||
|
||||
/* Wait for an X event */
|
||||
iReturn = select(iConnNumber + 1, /* Highest fds number */
|
||||
&fdsRead, /* Read mask */
|
||||
NULL, /* No write mask */
|
||||
NULL, /* No exception mask */
|
||||
&tv); /* Timeout */
|
||||
if (iReturn < 0) {
|
||||
ErrorF("winProcessXEventsTimeout - Call to select () failed: %d. "
|
||||
"Bailing.\n", iReturn);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!FD_ISSET(iConnNumber, &fdsRead)) {
|
||||
winDebug("winProcessXEventsTimeout - Spurious wake, select() returned %d\n", iReturn);
|
||||
}
|
||||
}
|
||||
|
||||
return WIN_XEVENTS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a given Windows message
|
||||
*/
|
||||
|
||||
LRESULT CALLBACK
|
||||
winClipboardWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static xcb_connection_t *conn;
|
||||
static xcb_window_t iWindow;
|
||||
static ClipboardAtoms *atoms;
|
||||
static BOOL fRunning;
|
||||
|
||||
/* Branch on message type */
|
||||
switch (message) {
|
||||
case WM_DESTROY:
|
||||
{
|
||||
winDebug("winClipboardWindowProc - WM_DESTROY\n");
|
||||
|
||||
/* Remove clipboard listener */
|
||||
RemoveClipboardFormatListener(hwnd);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_WM_QUIT:
|
||||
{
|
||||
winDebug("winClipboardWindowProc - WM_WM_QUIT\n");
|
||||
fRunning = FALSE;
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_CREATE:
|
||||
{
|
||||
ClipboardWindowCreationParams *cwcp = (ClipboardWindowCreationParams *)((CREATESTRUCT *)lParam)->lpCreateParams;
|
||||
|
||||
winDebug("winClipboardWindowProc - WM_CREATE\n");
|
||||
|
||||
conn = cwcp->pClipboardDisplay;
|
||||
iWindow = cwcp->iClipboardWindow;
|
||||
atoms = cwcp->atoms;
|
||||
fRunning = TRUE;
|
||||
|
||||
AddClipboardFormatListener(hwnd);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_CLIPBOARDUPDATE:
|
||||
{
|
||||
xcb_generic_error_t *error;
|
||||
xcb_void_cookie_t cookie_set;
|
||||
|
||||
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Enter\n");
|
||||
|
||||
/*
|
||||
* NOTE: We cannot bail out when NULL == GetClipboardOwner ()
|
||||
* because some applications deal with the clipboard in a manner
|
||||
* that causes the clipboard owner to be NULL when they are in
|
||||
* fact taking ownership. One example of this is the Win32
|
||||
* native compile of emacs.
|
||||
*/
|
||||
|
||||
/* Bail when we still own the clipboard */
|
||||
if (hwnd == GetClipboardOwner()) {
|
||||
|
||||
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
|
||||
"We own the clipboard, returning.\n");
|
||||
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Exit\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bail when shutting down */
|
||||
if (!fRunning)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Do not take ownership of the X11 selections when something
|
||||
* other than CF_TEXT or CF_UNICODETEXT has been copied
|
||||
* into the Win32 clipboard.
|
||||
*/
|
||||
if (!IsClipboardFormatAvailable(CF_TEXT)
|
||||
&& !IsClipboardFormatAvailable(CF_UNICODETEXT)) {
|
||||
|
||||
xcb_get_selection_owner_cookie_t cookie_get;
|
||||
xcb_get_selection_owner_reply_t *reply;
|
||||
|
||||
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
|
||||
"Clipboard does not contain CF_TEXT nor "
|
||||
"CF_UNICODETEXT.\n");
|
||||
|
||||
/*
|
||||
* We need to make sure that the X Server has processed
|
||||
* previous XSetSelectionOwner messages.
|
||||
*/
|
||||
xcb_aux_sync(conn);
|
||||
|
||||
winDebug("winClipboardWindowProc - XSync done.\n");
|
||||
|
||||
/* Release PRIMARY selection if owned */
|
||||
cookie_get = xcb_get_selection_owner(conn, XCB_ATOM_PRIMARY);
|
||||
reply = xcb_get_selection_owner_reply(conn, cookie_get, NULL);
|
||||
if (reply) {
|
||||
if (reply->owner == iWindow) {
|
||||
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
|
||||
"PRIMARY selection is owned by us, releasing.\n");
|
||||
xcb_set_selection_owner(conn, XCB_NONE, XCB_ATOM_PRIMARY, XCB_CURRENT_TIME);
|
||||
}
|
||||
free(reply);
|
||||
}
|
||||
|
||||
/* Release CLIPBOARD selection if owned */
|
||||
cookie_get = xcb_get_selection_owner(conn, atoms->atomClipboard);
|
||||
reply = xcb_get_selection_owner_reply(conn, cookie_get, NULL);
|
||||
if (reply) {
|
||||
if (reply->owner == iWindow) {
|
||||
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
|
||||
"CLIPBOARD selection is owned by us, releasing\n");
|
||||
xcb_set_selection_owner(conn, XCB_NONE, atoms->atomClipboard, XCB_CURRENT_TIME);
|
||||
}
|
||||
free(reply);
|
||||
}
|
||||
|
||||
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Exit\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reassert ownership of PRIMARY */
|
||||
cookie_set = xcb_set_selection_owner_checked(conn, iWindow, XCB_ATOM_PRIMARY, XCB_CURRENT_TIME);
|
||||
error = xcb_request_check(conn, cookie_set);
|
||||
if (error) {
|
||||
ErrorF("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
|
||||
"Could not reassert ownership of PRIMARY\n");
|
||||
free(error);
|
||||
} else {
|
||||
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
|
||||
"Reasserted ownership of PRIMARY\n");
|
||||
}
|
||||
|
||||
/* Reassert ownership of the CLIPBOARD */
|
||||
cookie_set = xcb_set_selection_owner_checked(conn, iWindow, atoms->atomClipboard, XCB_CURRENT_TIME);
|
||||
error = xcb_request_check(conn, cookie_set);
|
||||
if (error) {
|
||||
ErrorF("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
|
||||
"Could not reassert ownership of CLIPBOARD\n");
|
||||
free(error);
|
||||
}
|
||||
else {
|
||||
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE - "
|
||||
"Reasserted ownership of CLIPBOARD\n");
|
||||
}
|
||||
|
||||
/* Flush the pending SetSelectionOwner event now */
|
||||
xcb_flush(conn);
|
||||
}
|
||||
winDebug("winClipboardWindowProc - WM_CLIPBOARDUPDATE: Exit\n");
|
||||
return 0;
|
||||
|
||||
case WM_DESTROYCLIPBOARD:
|
||||
/*
|
||||
* NOTE: Intentionally do nothing.
|
||||
* Changes in the Win32 clipboard are handled by WM_CLIPBOARDUPDATE
|
||||
* above. We only process this message to conform to the specs
|
||||
* for delayed clipboard rendering in Win32. You might think
|
||||
* that we need to release ownership of the X11 selections, but
|
||||
* we do not, because a WM_CLIPBOARDUPDATE message will closely
|
||||
* follow this message and reassert ownership of the X11
|
||||
* selections, handling the issue for us.
|
||||
*/
|
||||
winDebug("winClipboardWindowProc - WM_DESTROYCLIPBOARD - Ignored.\n");
|
||||
return 0;
|
||||
|
||||
case WM_RENDERALLFORMATS:
|
||||
winDebug("winClipboardWindowProc - WM_RENDERALLFORMATS - Hello.\n");
|
||||
|
||||
/*
|
||||
WM_RENDERALLFORMATS is sent as we are shutting down, to render the
|
||||
clipboard so its contents remains available to other applications.
|
||||
|
||||
Unfortunately, this can't work without major changes. The server is
|
||||
already waiting for us to stop, so we can't ask for the rendering of
|
||||
clipboard text now.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
|
||||
case WM_RENDERFORMAT:
|
||||
{
|
||||
int iReturn;
|
||||
BOOL pasted = FALSE;
|
||||
xcb_atom_t selection;
|
||||
ClipboardConversionData data;
|
||||
int best_target = 0;
|
||||
|
||||
winDebug("winClipboardWindowProc - WM_RENDERFORMAT %d - Hello.\n",
|
||||
(int)wParam);
|
||||
|
||||
selection = winClipboardGetLastOwnedSelectionAtom(atoms);
|
||||
if (selection == XCB_NONE) {
|
||||
ErrorF("winClipboardWindowProc - no monitored selection is owned\n");
|
||||
goto fake_paste;
|
||||
}
|
||||
|
||||
winDebug("winClipboardWindowProc - requesting targets for selection from owner\n");
|
||||
|
||||
/* Request the selection's supported conversion targets */
|
||||
xcb_convert_selection(conn, iWindow, selection, atoms->atomTargets,
|
||||
atoms->atomLocalProperty, XCB_CURRENT_TIME);
|
||||
|
||||
/* Process X events */
|
||||
data.incr = NULL;
|
||||
data.incrsize = 0;
|
||||
|
||||
iReturn = winProcessXEventsTimeout(hwnd,
|
||||
iWindow,
|
||||
conn,
|
||||
&data,
|
||||
atoms,
|
||||
WIN_POLL_TIMEOUT);
|
||||
|
||||
if (WIN_XEVENTS_NOTIFY_TARGETS != iReturn) {
|
||||
ErrorF
|
||||
("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY_TARGETS\n");
|
||||
goto fake_paste;
|
||||
}
|
||||
|
||||
/* Choose the most preferred target */
|
||||
{
|
||||
struct target_priority
|
||||
{
|
||||
xcb_atom_t target;
|
||||
unsigned int priority;
|
||||
};
|
||||
|
||||
struct target_priority target_priority_table[] =
|
||||
{
|
||||
{ atoms->atomUTF8String, 0 },
|
||||
// { atoms->atomCompoundText, 1 }, not implemented (yet?)
|
||||
{ XCB_ATOM_STRING, 2 },
|
||||
};
|
||||
|
||||
int best_priority = INT_MAX;
|
||||
|
||||
int i,j;
|
||||
for (i = 0 ; data.targetList[i] != 0; i++)
|
||||
{
|
||||
for (j = 0; j < ARRAY_SIZE(target_priority_table); j ++)
|
||||
{
|
||||
if ((data.targetList[i] == target_priority_table[j].target) &&
|
||||
(target_priority_table[j].priority < best_priority))
|
||||
{
|
||||
best_target = target_priority_table[j].target;
|
||||
best_priority = target_priority_table[j].priority;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(data.targetList);
|
||||
data.targetList = 0;
|
||||
|
||||
winDebug("winClipboardWindowProc - best target is %d\n", best_target);
|
||||
|
||||
/* No useful targets found */
|
||||
if (best_target == 0)
|
||||
goto fake_paste;
|
||||
|
||||
winDebug("winClipboardWindowProc - requesting selection from owner\n");
|
||||
|
||||
/* Request the selection contents */
|
||||
xcb_convert_selection(conn, iWindow, selection, best_target,
|
||||
atoms->atomLocalProperty, XCB_CURRENT_TIME);
|
||||
|
||||
/* Process X events */
|
||||
iReturn = winProcessXEventsTimeout(hwnd,
|
||||
iWindow,
|
||||
conn,
|
||||
&data,
|
||||
atoms,
|
||||
WIN_POLL_TIMEOUT);
|
||||
|
||||
/*
|
||||
* winProcessXEventsTimeout had better have seen a notify event,
|
||||
* or else we are dealing with a buggy or old X11 app.
|
||||
*/
|
||||
if (WIN_XEVENTS_NOTIFY_DATA != iReturn) {
|
||||
ErrorF
|
||||
("winClipboardWindowProc - timed out waiting for WIN_XEVENTS_NOTIFY_DATA\n");
|
||||
}
|
||||
else {
|
||||
pasted = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we couldn't get the data from the X clipboard, we
|
||||
* have to paste some fake data to the Win32 clipboard to
|
||||
* satisfy the requirement that we write something to it.
|
||||
*/
|
||||
fake_paste:
|
||||
if (!pasted)
|
||||
{
|
||||
/* Paste no data, to satisfy required call to SetClipboardData */
|
||||
SetClipboardData(CF_UNICODETEXT, NULL);
|
||||
SetClipboardData(CF_TEXT, NULL);
|
||||
}
|
||||
|
||||
winDebug("winClipboardWindowProc - WM_RENDERFORMAT - Returning.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Let Windows perform default processing for unhandled messages */
|
||||
return DefWindowProc(hwnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process any pending Windows messages
|
||||
*/
|
||||
|
||||
BOOL
|
||||
winClipboardFlushWindowsMessageQueue(HWND hwnd)
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
/* Flush the messaging window queue */
|
||||
/* NOTE: Do not pass the hwnd of our messaging window to PeekMessage,
|
||||
* as this will filter out many non-window-specific messages that
|
||||
* are sent to our thread, such as WM_QUIT.
|
||||
*/
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
/* Dispatch the message if not WM_QUIT */
|
||||
if (msg.message == WM_QUIT)
|
||||
return FALSE;
|
||||
else
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
829
xserver/hw/xwin/winclipboard/xevents.c
Normal file
829
xserver/hw/xwin/winclipboard/xevents.c
Normal file
|
@ -0,0 +1,829 @@
|
|||
/*
|
||||
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
|
||||
*Copyright (C) Colin Harrison 2005-2008
|
||||
*
|
||||
*Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
*"Software"), to deal in the Software without restriction, including
|
||||
*without limitation the rights to use, copy, modify, merge, publish,
|
||||
*distribute, sublicense, and/or sell copies of the Software, and to
|
||||
*permit persons to whom the Software is furnished to do so, subject to
|
||||
*the following conditions:
|
||||
*
|
||||
*The above copyright notice and this permission notice shall be
|
||||
*included in all copies or substantial portions of the Software.
|
||||
*
|
||||
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
*NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
|
||||
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*Except as contained in this notice, the name of the copyright holder(s)
|
||||
*and author(s) shall not be used in advertising or otherwise to promote
|
||||
*the sale, use or other dealings in this Software without prior written
|
||||
*authorization from the copyright holder(s) and author(s).
|
||||
*
|
||||
* Authors: Harold L Hunt II
|
||||
* Colin Harrison
|
||||
*/
|
||||
|
||||
#ifdef HAVE_XWIN_CONFIG_H
|
||||
#include <xwin-config.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xfixes.h>
|
||||
|
||||
#include "winclipboard.h"
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
|
||||
#define CLIP_NUM_SELECTIONS 2
|
||||
#define CLIP_OWN_NONE -1
|
||||
#define CLIP_OWN_PRIMARY 0
|
||||
#define CLIP_OWN_CLIPBOARD 1
|
||||
|
||||
#define CP_ISO_8559_1 28591
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
|
||||
extern int xfixes_event_base;
|
||||
BOOL fPrimarySelection = TRUE;
|
||||
|
||||
/*
|
||||
* Local variables
|
||||
*/
|
||||
|
||||
static xcb_window_t s_iOwners[CLIP_NUM_SELECTIONS] = { XCB_NONE, XCB_NONE };
|
||||
static const char *szSelectionNames[CLIP_NUM_SELECTIONS] =
|
||||
{ "PRIMARY", "CLIPBOARD" };
|
||||
|
||||
static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE;
|
||||
|
||||
static void
|
||||
MonitorSelection(xcb_xfixes_selection_notify_event_t * e, unsigned int i)
|
||||
{
|
||||
/* Look for owned -> not owned transition */
|
||||
if ((XCB_NONE == e->owner) && (XCB_NONE != s_iOwners[i])) {
|
||||
unsigned int other_index;
|
||||
|
||||
winDebug("MonitorSelection - %s - Going from owned to not owned.\n",
|
||||
szSelectionNames[i]);
|
||||
|
||||
/* If this selection is not owned, the other monitored selection must be the most
|
||||
recently owned, if it is owned at all */
|
||||
if (i == CLIP_OWN_PRIMARY)
|
||||
other_index = CLIP_OWN_CLIPBOARD;
|
||||
if (i == CLIP_OWN_CLIPBOARD)
|
||||
other_index = CLIP_OWN_PRIMARY;
|
||||
if (XCB_NONE != s_iOwners[other_index])
|
||||
lastOwnedSelectionIndex = other_index;
|
||||
else
|
||||
lastOwnedSelectionIndex = CLIP_OWN_NONE;
|
||||
}
|
||||
|
||||
/* Save last owned selection */
|
||||
if (XCB_NONE != e->owner) {
|
||||
lastOwnedSelectionIndex = i;
|
||||
}
|
||||
|
||||
/* Save new selection owner or None */
|
||||
s_iOwners[i] = e->owner;
|
||||
winDebug("MonitorSelection - %s - Now owned by XID %x\n",
|
||||
szSelectionNames[i], e->owner);
|
||||
}
|
||||
|
||||
xcb_atom_t
|
||||
winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms)
|
||||
{
|
||||
if (lastOwnedSelectionIndex == CLIP_OWN_NONE)
|
||||
return XCB_NONE;
|
||||
|
||||
if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY)
|
||||
return XCB_ATOM_PRIMARY;
|
||||
|
||||
if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD)
|
||||
return atoms->atomClipboard;
|
||||
|
||||
return XCB_NONE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
winClipboardInitMonitoredSelections(void)
|
||||
{
|
||||
/* Initialize static variables */
|
||||
int i;
|
||||
for (i = 0; i < CLIP_NUM_SELECTIONS; ++i)
|
||||
s_iOwners[i] = XCB_NONE;
|
||||
|
||||
lastOwnedSelectionIndex = CLIP_OWN_NONE;
|
||||
}
|
||||
|
||||
static char *get_atom_name(xcb_connection_t *conn, xcb_atom_t atom)
|
||||
{
|
||||
char *ret;
|
||||
xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(conn, atom);
|
||||
xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(conn, cookie, NULL);
|
||||
if (!reply)
|
||||
return NULL;
|
||||
ret = malloc(xcb_get_atom_name_name_length(reply) + 1);
|
||||
if (ret) {
|
||||
memcpy(ret, xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply));
|
||||
ret[xcb_get_atom_name_name_length(reply)] = '\0';
|
||||
}
|
||||
free(reply);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
winClipboardSelectionNotifyTargets(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn, ClipboardConversionData *data, ClipboardAtoms *atoms)
|
||||
{
|
||||
/* Retrieve the selection data and delete the property */
|
||||
xcb_get_property_cookie_t cookie = xcb_get_property(conn,
|
||||
TRUE,
|
||||
iWindow,
|
||||
atoms->atomLocalProperty,
|
||||
XCB_GET_PROPERTY_TYPE_ANY,
|
||||
0,
|
||||
INT_MAX);
|
||||
xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
|
||||
if (!reply) {
|
||||
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
|
||||
"XGetWindowProperty () failed\n");
|
||||
} else {
|
||||
xcb_atom_t *prop = xcb_get_property_value(reply);
|
||||
int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t);
|
||||
int i;
|
||||
data->targetList = malloc((nitems+1)*sizeof(xcb_atom_t));
|
||||
|
||||
for (i = 0; i < nitems; i++)
|
||||
{
|
||||
xcb_atom_t atom = prop[i];
|
||||
char *pszAtomName = get_atom_name(conn, atom);
|
||||
data->targetList[i] = atom;
|
||||
winDebug("winClipboardFlushXEvents - SelectionNotify - target[%d] %d = %s\n", i, atom, pszAtomName);
|
||||
free(pszAtomName);
|
||||
}
|
||||
|
||||
data->targetList[nitems] = 0;
|
||||
|
||||
free(reply);
|
||||
}
|
||||
|
||||
return WIN_XEVENTS_NOTIFY_TARGETS;
|
||||
}
|
||||
|
||||
static int
|
||||
winClipboardSelectionNotifyData(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn, ClipboardConversionData *data, ClipboardAtoms *atoms)
|
||||
{
|
||||
xcb_atom_t encoding;
|
||||
int format;
|
||||
unsigned long int nitems;
|
||||
unsigned long int after;
|
||||
unsigned char *value;
|
||||
|
||||
unsigned char *xtpText_value;
|
||||
xcb_atom_t xtpText_encoding;
|
||||
int xtpText_nitems;
|
||||
|
||||
BOOL fSetClipboardData = TRUE;
|
||||
char *pszReturnData = NULL;
|
||||
UINT codepage;
|
||||
wchar_t *pwszUnicodeStr = NULL;
|
||||
HGLOBAL hGlobal = NULL;
|
||||
char *pszGlobalData = NULL;
|
||||
|
||||
/* Retrieve the selection data and delete the property */
|
||||
xcb_get_property_cookie_t cookie = xcb_get_property(conn,
|
||||
TRUE,
|
||||
iWindow,
|
||||
atoms->atomLocalProperty,
|
||||
XCB_GET_PROPERTY_TYPE_ANY,
|
||||
0,
|
||||
INT_MAX);
|
||||
xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
|
||||
if (!reply) {
|
||||
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
|
||||
"XGetWindowProperty () failed\n");
|
||||
goto winClipboardFlushXEvents_SelectionNotify_Done;
|
||||
} else {
|
||||
nitems = xcb_get_property_value_length(reply);
|
||||
value = xcb_get_property_value(reply);
|
||||
after = reply->bytes_after;
|
||||
encoding = reply->type;
|
||||
format = reply->format;
|
||||
// We assume format == 8 (i.e. data is a sequence of bytes). It's not
|
||||
// clear how anything else should be handled.
|
||||
if (format != 8)
|
||||
ErrorF("SelectionNotify: format is %d, proceeding as if it was 8\n", format);
|
||||
}
|
||||
|
||||
{
|
||||
char *pszAtomName;
|
||||
winDebug("SelectionNotify - returned data %lu left %lu\n", nitems, after);
|
||||
pszAtomName = get_atom_name(conn, encoding);
|
||||
winDebug("Notify atom name %s\n", pszAtomName);
|
||||
free(pszAtomName);
|
||||
}
|
||||
|
||||
/* INCR reply indicates the start of a incremental transfer */
|
||||
if (encoding == atoms->atomIncr) {
|
||||
winDebug("winClipboardSelectionNotifyData: starting INCR, anticipated size %d\n", *(int *)value);
|
||||
data->incrsize = 0;
|
||||
data->incr = malloc(*(int *)value);
|
||||
// XXX: if malloc failed, we have an error
|
||||
return WIN_XEVENTS_SUCCESS;
|
||||
}
|
||||
else if (data->incr) {
|
||||
/* If an INCR transfer is in progress ... */
|
||||
if (nitems == 0) {
|
||||
winDebug("winClipboardSelectionNotifyData: ending INCR, actual size %ld\n", data->incrsize);
|
||||
/* a zero-length property indicates the end of the data */
|
||||
xtpText_value = data->incr;
|
||||
xtpText_encoding = encoding;
|
||||
// XXX: The type of the converted selection is the type of the first
|
||||
// partial property. The remaining partial properties must have the
|
||||
// same type.
|
||||
xtpText_nitems = data->incrsize;
|
||||
}
|
||||
else {
|
||||
/* Otherwise, continue appending the INCR data */
|
||||
winDebug("winClipboardSelectionNotifyData: INCR, %ld bytes\n", nitems);
|
||||
data->incr = realloc(data->incr, data->incrsize + nitems);
|
||||
memcpy(data->incr + data->incrsize, value, nitems);
|
||||
data->incrsize = data->incrsize + nitems;
|
||||
return WIN_XEVENTS_SUCCESS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Otherwise, the data is just contained in the property */
|
||||
winDebug("winClipboardSelectionNotifyData: non-INCR, %ld bytes\n", nitems);
|
||||
xtpText_value = value;
|
||||
xtpText_encoding = encoding;
|
||||
xtpText_nitems = nitems;
|
||||
}
|
||||
|
||||
if (xtpText_encoding == atoms->atomUTF8String) {
|
||||
pszReturnData = malloc(xtpText_nitems + 1);
|
||||
memcpy(pszReturnData, xtpText_value, xtpText_nitems);
|
||||
pszReturnData[xtpText_nitems] = 0;
|
||||
codepage = CP_UTF8; // code page identifier for utf8
|
||||
} else if (xtpText_encoding == XCB_ATOM_STRING) {
|
||||
// STRING encoding is Latin1 (ISO8859-1) plus tab and newline
|
||||
pszReturnData = malloc(xtpText_nitems + 1);
|
||||
memcpy(pszReturnData, xtpText_value, xtpText_nitems);
|
||||
pszReturnData[xtpText_nitems] = 0;
|
||||
codepage = CP_ISO_8559_1; // code page identifier for iso-8559-1
|
||||
} else if (xtpText_encoding == atoms->atomCompoundText) {
|
||||
// COMPOUND_TEXT is complex, based on ISO 2022
|
||||
ErrorF("SelectionNotify: data in COMPOUND_TEXT encoding which is not implemented, discarding\n");
|
||||
pszReturnData = malloc(1);
|
||||
pszReturnData[0] = '\0';
|
||||
} else { // shouldn't happen as we accept no other encodings
|
||||
pszReturnData = malloc(1);
|
||||
pszReturnData[0] = '\0';
|
||||
}
|
||||
|
||||
/* Free the data returned from xcb_get_property */
|
||||
free(reply);
|
||||
|
||||
/* Free any INCR data */
|
||||
if (data->incr) {
|
||||
free(data->incr);
|
||||
data->incr = NULL;
|
||||
data->incrsize = 0;
|
||||
}
|
||||
|
||||
/* Convert the X clipboard string to DOS format */
|
||||
winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData));
|
||||
|
||||
/* Find out how much space needed when converted to UTF-16 */
|
||||
int iUnicodeLen = MultiByteToWideChar(codepage, 0,
|
||||
pszReturnData, -1, NULL, 0);
|
||||
|
||||
/* NOTE: iUnicodeLen includes space for null terminator */
|
||||
pwszUnicodeStr = malloc(sizeof(wchar_t) * iUnicodeLen);
|
||||
if (!pwszUnicodeStr) {
|
||||
ErrorF("winClipboardFlushXEvents - SelectionNotify "
|
||||
"malloc failed for pwszUnicodeStr, aborting.\n");
|
||||
|
||||
/* Abort */
|
||||
goto winClipboardFlushXEvents_SelectionNotify_Done;
|
||||
}
|
||||
|
||||
/* Do the actual conversion */
|
||||
MultiByteToWideChar(codepage, 0,
|
||||
pszReturnData, -1, pwszUnicodeStr, iUnicodeLen);
|
||||
|
||||
/* Allocate global memory for the X clipboard data */
|
||||
hGlobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * iUnicodeLen);
|
||||
|
||||
free(pszReturnData);
|
||||
|
||||
/* Check that global memory was allocated */
|
||||
if (!hGlobal) {
|
||||
ErrorF("winClipboardFlushXEvents - SelectionNotify "
|
||||
"GlobalAlloc failed, aborting: %08x\n", (unsigned int)GetLastError());
|
||||
|
||||
/* Abort */
|
||||
goto winClipboardFlushXEvents_SelectionNotify_Done;
|
||||
}
|
||||
|
||||
/* Obtain a pointer to the global memory */
|
||||
pszGlobalData = GlobalLock(hGlobal);
|
||||
if (pszGlobalData == NULL) {
|
||||
ErrorF("winClipboardFlushXEvents - Could not lock global "
|
||||
"memory for clipboard transfer\n");
|
||||
|
||||
/* Abort */
|
||||
goto winClipboardFlushXEvents_SelectionNotify_Done;
|
||||
}
|
||||
|
||||
/* Copy the returned string into the global memory */
|
||||
wcscpy((wchar_t *)pszGlobalData, pwszUnicodeStr);
|
||||
free(pwszUnicodeStr);
|
||||
pwszUnicodeStr = NULL;
|
||||
|
||||
/* Release the pointer to the global memory */
|
||||
GlobalUnlock(hGlobal);
|
||||
pszGlobalData = NULL;
|
||||
|
||||
/* Push the selection data to the Windows clipboard */
|
||||
SetClipboardData(CF_UNICODETEXT, hGlobal);
|
||||
|
||||
/* Flag that SetClipboardData has been called */
|
||||
fSetClipboardData = FALSE;
|
||||
|
||||
/*
|
||||
* NOTE: Do not try to free pszGlobalData, it is owned by
|
||||
* Windows after the call to SetClipboardData ().
|
||||
*/
|
||||
|
||||
winClipboardFlushXEvents_SelectionNotify_Done:
|
||||
/* Free allocated resources */
|
||||
free(pwszUnicodeStr);
|
||||
if (hGlobal && pszGlobalData)
|
||||
GlobalUnlock(hGlobal);
|
||||
if (fSetClipboardData) {
|
||||
SetClipboardData(CF_UNICODETEXT, NULL);
|
||||
SetClipboardData(CF_TEXT, NULL);
|
||||
}
|
||||
return WIN_XEVENTS_NOTIFY_DATA;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process any pending X events
|
||||
*/
|
||||
|
||||
int
|
||||
winClipboardFlushXEvents(HWND hwnd,
|
||||
xcb_window_t iWindow, xcb_connection_t *conn,
|
||||
ClipboardConversionData *data, ClipboardAtoms *atoms)
|
||||
{
|
||||
xcb_atom_t atomClipboard = atoms->atomClipboard;
|
||||
xcb_atom_t atomUTF8String = atoms->atomUTF8String;
|
||||
xcb_atom_t atomCompoundText = atoms->atomCompoundText;
|
||||
xcb_atom_t atomTargets = atoms->atomTargets;
|
||||
|
||||
/* Process all pending events */
|
||||
xcb_generic_event_t *event;
|
||||
while ((event = xcb_poll_for_event(conn))) {
|
||||
const char *pszGlobalData = NULL;
|
||||
HGLOBAL hGlobal = NULL;
|
||||
char *pszConvertData = NULL;
|
||||
BOOL fAbort = FALSE;
|
||||
BOOL fCloseClipboard = FALSE;
|
||||
|
||||
/* Branch on the event type */
|
||||
switch (event->response_type & ~0x80) {
|
||||
case XCB_SELECTION_REQUEST:
|
||||
{
|
||||
char *xtpText_value = NULL;
|
||||
int xtpText_nitems;
|
||||
UINT codepage;
|
||||
|
||||
xcb_selection_request_event_t *selection_request = (xcb_selection_request_event_t *)event;
|
||||
{
|
||||
char *pszAtomName = NULL;
|
||||
|
||||
winDebug("SelectionRequest - target %d\n", selection_request->target);
|
||||
|
||||
pszAtomName = get_atom_name(conn, selection_request->target);
|
||||
winDebug("SelectionRequest - Target atom name %s\n", pszAtomName);
|
||||
free(pszAtomName);
|
||||
}
|
||||
|
||||
/* Abort if invalid target type */
|
||||
if (selection_request->target != XCB_ATOM_STRING
|
||||
&& selection_request->target != atomUTF8String
|
||||
&& selection_request->target != atomCompoundText
|
||||
&& selection_request->target != atomTargets) {
|
||||
/* Abort */
|
||||
fAbort = TRUE;
|
||||
goto winClipboardFlushXEvents_SelectionRequest_Done;
|
||||
}
|
||||
|
||||
/* Handle targets type of request */
|
||||
if (selection_request->target == atomTargets) {
|
||||
xcb_atom_t atomTargetArr[] =
|
||||
{
|
||||
atomTargets,
|
||||
atomUTF8String,
|
||||
XCB_ATOM_STRING,
|
||||
// atomCompoundText, not implemented (yet?)
|
||||
};
|
||||
|
||||
/* Try to change the property */
|
||||
xcb_void_cookie_t cookie = xcb_change_property_checked(conn,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
selection_request->requestor,
|
||||
selection_request->property,
|
||||
XCB_ATOM_ATOM,
|
||||
32,
|
||||
ARRAY_SIZE(atomTargetArr),
|
||||
(unsigned char *) atomTargetArr);
|
||||
xcb_generic_error_t *error;
|
||||
if ((error = xcb_request_check(conn, cookie))) {
|
||||
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
|
||||
"xcb_change_property failed");
|
||||
free(error);
|
||||
}
|
||||
|
||||
/* Setup selection notify xevent */
|
||||
xcb_selection_notify_event_t eventSelection;
|
||||
eventSelection.response_type = XCB_SELECTION_NOTIFY;
|
||||
eventSelection.requestor = selection_request->requestor;
|
||||
eventSelection.selection = selection_request->selection;
|
||||
eventSelection.target = selection_request->target;
|
||||
eventSelection.property = selection_request->property;
|
||||
eventSelection.time = selection_request->time;
|
||||
|
||||
/*
|
||||
* Notify the requesting window that
|
||||
* the operation has completed
|
||||
*/
|
||||
cookie = xcb_send_event_checked(conn, FALSE,
|
||||
eventSelection.requestor,
|
||||
0, (char *) &eventSelection);
|
||||
if ((error = xcb_request_check(conn, cookie))) {
|
||||
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
|
||||
"xcb_send_event() failed\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Close clipboard if we have it open already */
|
||||
if (GetOpenClipboardWindow() == hwnd) {
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
/* Access the clipboard */
|
||||
if (!OpenClipboard(hwnd)) {
|
||||
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
|
||||
"OpenClipboard () failed: %08x\n", (unsigned int)GetLastError());
|
||||
|
||||
/* Abort */
|
||||
fAbort = TRUE;
|
||||
goto winClipboardFlushXEvents_SelectionRequest_Done;
|
||||
}
|
||||
|
||||
/* Indicate that clipboard was opened */
|
||||
fCloseClipboard = TRUE;
|
||||
|
||||
/* Check that clipboard format is available */
|
||||
if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) {
|
||||
static int count; /* Hack to stop acroread spamming the log */
|
||||
static HWND lasthwnd; /* I've not seen any other client get here repeatedly? */
|
||||
|
||||
if (hwnd != lasthwnd)
|
||||
count = 0;
|
||||
count++;
|
||||
if (count < 6)
|
||||
ErrorF("winClipboardFlushXEvents - CF_UNICODETEXT is not "
|
||||
"available from Win32 clipboard. Aborting %d.\n",
|
||||
count);
|
||||
lasthwnd = hwnd;
|
||||
|
||||
/* Abort */
|
||||
fAbort = TRUE;
|
||||
goto winClipboardFlushXEvents_SelectionRequest_Done;
|
||||
}
|
||||
|
||||
/* Get a pointer to the clipboard text, in desired format */
|
||||
/* Retrieve clipboard data */
|
||||
hGlobal = GetClipboardData(CF_UNICODETEXT);
|
||||
|
||||
if (!hGlobal) {
|
||||
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
|
||||
"GetClipboardData () failed: %08x\n", (unsigned int)GetLastError());
|
||||
|
||||
/* Abort */
|
||||
fAbort = TRUE;
|
||||
goto winClipboardFlushXEvents_SelectionRequest_Done;
|
||||
}
|
||||
pszGlobalData = (char *) GlobalLock(hGlobal);
|
||||
|
||||
/* Convert to target string style */
|
||||
if (selection_request->target == XCB_ATOM_STRING) {
|
||||
codepage = CP_ISO_8559_1; // code page identifier for iso-8559-1
|
||||
} else if (selection_request->target == atomUTF8String) {
|
||||
codepage = CP_UTF8; // code page identifier for utf8
|
||||
} else if (selection_request->target == atomCompoundText) {
|
||||
// COMPOUND_TEXT is complex, not (yet) implemented
|
||||
pszGlobalData = "COMPOUND_TEXT not implemented";
|
||||
codepage = CP_UTF8; // code page identifier for utf8
|
||||
}
|
||||
|
||||
/* Convert the UTF16 string to required encoding */
|
||||
int iConvertDataLen = WideCharToMultiByte(codepage, 0,
|
||||
(LPCWSTR) pszGlobalData, -1,
|
||||
NULL, 0, NULL, NULL);
|
||||
/* NOTE: iConvertDataLen includes space for null terminator */
|
||||
pszConvertData = malloc(iConvertDataLen);
|
||||
WideCharToMultiByte(codepage, 0,
|
||||
(LPCWSTR) pszGlobalData, -1,
|
||||
pszConvertData, iConvertDataLen, NULL, NULL);
|
||||
|
||||
/* Convert DOS string to UNIX string */
|
||||
winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData));
|
||||
|
||||
xtpText_value = strdup(pszConvertData);
|
||||
xtpText_nitems = strlen(pszConvertData);
|
||||
|
||||
/* data will fit into a single X request? (INCR not yet supported) */
|
||||
{
|
||||
uint32_t maxreqsize = xcb_get_maximum_request_length(conn);
|
||||
|
||||
/* covert to bytes and allow for allow for X_ChangeProperty request */
|
||||
maxreqsize = maxreqsize*4 - 24;
|
||||
|
||||
if (xtpText_nitems > maxreqsize) {
|
||||
ErrorF("winClipboardFlushXEvents - clipboard data size %d greater than maximum %u\n", xtpText_nitems, maxreqsize);
|
||||
|
||||
/* Abort */
|
||||
fAbort = TRUE;
|
||||
goto winClipboardFlushXEvents_SelectionRequest_Done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the clipboard text to the requesting window */
|
||||
xcb_void_cookie_t cookie = xcb_change_property_checked(conn,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
selection_request->requestor,
|
||||
selection_request->property,
|
||||
selection_request->target,
|
||||
8,
|
||||
xtpText_nitems, xtpText_value);
|
||||
xcb_generic_error_t *error;
|
||||
if ((error = xcb_request_check(conn, cookie))) {
|
||||
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
|
||||
"xcb_change_property failed\n");
|
||||
|
||||
/* Abort */
|
||||
fAbort = TRUE;
|
||||
goto winClipboardFlushXEvents_SelectionRequest_Done;
|
||||
}
|
||||
|
||||
/* Free the converted string */
|
||||
free(pszConvertData);
|
||||
pszConvertData = NULL;
|
||||
|
||||
/* Release the clipboard data */
|
||||
GlobalUnlock(hGlobal);
|
||||
pszGlobalData = NULL;
|
||||
fCloseClipboard = FALSE;
|
||||
CloseClipboard();
|
||||
|
||||
/* Clean up */
|
||||
free(xtpText_value);
|
||||
xtpText_value = NULL;
|
||||
|
||||
/* Setup selection notify event */
|
||||
xcb_selection_notify_event_t eventSelection;
|
||||
eventSelection.response_type = XCB_SELECTION_NOTIFY;
|
||||
eventSelection.requestor = selection_request->requestor;
|
||||
eventSelection.selection = selection_request->selection;
|
||||
eventSelection.target = selection_request->target;
|
||||
eventSelection.property = selection_request->property;
|
||||
eventSelection.time = selection_request->time;
|
||||
|
||||
/* Notify the requesting window that the operation has completed */
|
||||
cookie = xcb_send_event_checked(conn, FALSE,
|
||||
eventSelection.requestor,
|
||||
0, (char *) &eventSelection);
|
||||
if ((error = xcb_request_check(conn, cookie))) {
|
||||
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
|
||||
"xcb_send_event() failed\n");
|
||||
|
||||
/* Abort */
|
||||
fAbort = TRUE;
|
||||
goto winClipboardFlushXEvents_SelectionRequest_Done;
|
||||
}
|
||||
|
||||
winClipboardFlushXEvents_SelectionRequest_Done:
|
||||
/* Free allocated resources */
|
||||
if (xtpText_value) {
|
||||
free(xtpText_value);
|
||||
}
|
||||
if (pszConvertData)
|
||||
free(pszConvertData);
|
||||
if (hGlobal && pszGlobalData)
|
||||
GlobalUnlock(hGlobal);
|
||||
|
||||
/*
|
||||
* Send a SelectionNotify event to the requesting
|
||||
* client when we abort.
|
||||
*/
|
||||
if (fAbort) {
|
||||
/* Setup selection notify event */
|
||||
eventSelection.response_type = XCB_SELECTION_NOTIFY;
|
||||
eventSelection.requestor = selection_request->requestor;
|
||||
eventSelection.selection = selection_request->selection;
|
||||
eventSelection.target = selection_request->target;
|
||||
eventSelection.property = XCB_NONE;
|
||||
eventSelection.time = selection_request->time;
|
||||
|
||||
/* Notify the requesting window that the operation is complete */
|
||||
cookie = xcb_send_event_checked(conn, FALSE,
|
||||
eventSelection.requestor,
|
||||
0, (char *) &eventSelection);
|
||||
if ((error = xcb_request_check(conn, cookie))) {
|
||||
/*
|
||||
* Should not be a problem if XSendEvent fails because
|
||||
* the client may simply have exited.
|
||||
*/
|
||||
ErrorF("winClipboardFlushXEvents - SelectionRequest - "
|
||||
"xcb_send_event() failed for abort event.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Close clipboard if it was opened */
|
||||
if (fCloseClipboard) {
|
||||
fCloseClipboard = FALSE;
|
||||
CloseClipboard();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case XCB_SELECTION_NOTIFY:
|
||||
{
|
||||
xcb_selection_notify_event_t *selection_notify = (xcb_selection_notify_event_t *)event;
|
||||
winDebug("winClipboardFlushXEvents - SelectionNotify\n");
|
||||
{
|
||||
char *pszAtomName;
|
||||
pszAtomName = get_atom_name(conn, selection_notify->selection);
|
||||
winDebug("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n", pszAtomName);
|
||||
free(pszAtomName);
|
||||
}
|
||||
|
||||
/*
|
||||
SelectionNotify with property of XCB_NONE indicates either:
|
||||
|
||||
(i) Generated by the X server if no owner for the specified selection exists
|
||||
(perhaps it's disappeared on us mid-transaction), or
|
||||
(ii) Sent by the selection owner when the requested selection conversion could
|
||||
not be performed or server errors prevented the conversion data being returned
|
||||
*/
|
||||
if (selection_notify->property == XCB_NONE) {
|
||||
ErrorF("winClipboardFlushXEvents - SelectionNotify - "
|
||||
"Conversion to format %d refused.\n",
|
||||
selection_notify->target);
|
||||
return WIN_XEVENTS_FAILED;
|
||||
}
|
||||
|
||||
if (selection_notify->target == atomTargets) {
|
||||
return winClipboardSelectionNotifyTargets(hwnd, iWindow, conn, data, atoms);
|
||||
}
|
||||
|
||||
return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms);
|
||||
}
|
||||
|
||||
case XCB_SELECTION_CLEAR:
|
||||
winDebug("SelectionClear - doing nothing\n");
|
||||
break;
|
||||
|
||||
case XCB_PROPERTY_NOTIFY:
|
||||
{
|
||||
xcb_property_notify_event_t *property_notify = (xcb_property_notify_event_t *)event;
|
||||
|
||||
/* If INCR is in progress, collect the data */
|
||||
if (data->incr &&
|
||||
(property_notify->atom == atoms->atomLocalProperty) &&
|
||||
(property_notify->state == XCB_PROPERTY_NEW_VALUE))
|
||||
return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case XCB_MAPPING_NOTIFY:
|
||||
break;
|
||||
|
||||
case 0:
|
||||
/* This is just laziness rather than making sure we used _checked everywhere */
|
||||
{
|
||||
xcb_generic_error_t *err = (xcb_generic_error_t *)event;
|
||||
ErrorF("winClipboardFlushXEvents - Error code: %i, ID: 0x%08x, "
|
||||
"Major opcode: %i, Minor opcode: %i\n",
|
||||
err->error_code, err->resource_id,
|
||||
err->major_code, err->minor_code);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((event->response_type & ~0x80) == XCB_XFIXES_SELECTION_EVENT_SET_SELECTION_OWNER + xfixes_event_base) {
|
||||
xcb_xfixes_selection_notify_event_t *e = (xcb_xfixes_selection_notify_event_t *)event;
|
||||
winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n");
|
||||
|
||||
/* Save selection owners for monitored selections, ignore other selections */
|
||||
if ((e->selection == XCB_ATOM_PRIMARY) && fPrimarySelection) {
|
||||
MonitorSelection(e, CLIP_OWN_PRIMARY);
|
||||
}
|
||||
else if (e->selection == atomClipboard) {
|
||||
MonitorSelection(e, CLIP_OWN_CLIPBOARD);
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
/* Selection is being disowned */
|
||||
if (e->owner == XCB_NONE) {
|
||||
winDebug("winClipboardFlushXEvents - No window, returning.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
XXX: there are all kinds of wacky edge cases we might need here:
|
||||
- we own windows clipboard, but neither PRIMARY nor CLIPBOARD have an owner, so we should disown it?
|
||||
- root window is taking ownership?
|
||||
*/
|
||||
|
||||
/* If we are the owner of the most recently owned selection, don't go all recursive :) */
|
||||
if ((lastOwnedSelectionIndex != CLIP_OWN_NONE) &&
|
||||
(s_iOwners[lastOwnedSelectionIndex] == iWindow)) {
|
||||
winDebug("winClipboardFlushXEvents - Ownership changed to us, aborting.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Close clipboard if we have it open already (possible? correct??) */
|
||||
if (GetOpenClipboardWindow() == hwnd) {
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
/* Access the Windows clipboard */
|
||||
if (!OpenClipboard(hwnd)) {
|
||||
ErrorF("winClipboardFlushXEvents - OpenClipboard () failed: %08x\n",
|
||||
(int) GetLastError());
|
||||
break;
|
||||
}
|
||||
|
||||
/* Take ownership of the Windows clipboard */
|
||||
if (!EmptyClipboard()) {
|
||||
ErrorF("winClipboardFlushXEvents - EmptyClipboard () failed: %08x\n",
|
||||
(int) GetLastError());
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advertise regular text and unicode */
|
||||
SetClipboardData(CF_UNICODETEXT, NULL);
|
||||
SetClipboardData(CF_TEXT, NULL);
|
||||
|
||||
/* Release the clipboard */
|
||||
if (!CloseClipboard()) {
|
||||
ErrorF("winClipboardFlushXEvents - CloseClipboard () failed: %08x\n",
|
||||
(int) GetLastError());
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* XCB_XFIXES_SELECTION_EVENT_SELECTION_WINDOW_DESTROY */
|
||||
/* XCB_XFIXES_SELECTION_EVENT_SELECTION_CLIENT_CLOSE */
|
||||
else {
|
||||
ErrorF("winClipboardFlushXEvents - unexpected event type %d\n",
|
||||
event->response_type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* I/O errors etc. */
|
||||
{
|
||||
int e = xcb_connection_has_error(conn);
|
||||
if (e) {
|
||||
ErrorF("winClipboardFlushXEvents - Fatal error %d on xcb connection\n", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return WIN_XEVENTS_SUCCESS;
|
||||
|
||||
}
|
85
xserver/hw/xwin/winclipboard/xwinclip.c
Normal file
85
xserver/hw/xwin/winclipboard/xwinclip.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
*Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
|
||||
*Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
|
||||
*Copyright (C) Colin Harrison 2005-2008
|
||||
*
|
||||
*Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
*"Software"), to deal in the Software without restriction, including
|
||||
*without limitation the rights to use, copy, modify, merge, publish,
|
||||
*distribute, sublicense, and/or sell copies of the Software, and to
|
||||
*permit persons to whom the Software is furnished to do so, subject to
|
||||
*the following conditions:
|
||||
*
|
||||
*The above copyright notice and this permission notice shall be
|
||||
*included in all copies or substantial portions of the Software.
|
||||
*
|
||||
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*Except as contained in this notice, the name of the copyright holder(s)
|
||||
*and author(s) shall not be used in advertising or otherwise to promote
|
||||
*the sale, use or other dealings in this Software without prior written
|
||||
*authorization from the copyright holder(s) and author(s).
|
||||
*
|
||||
* Authors: Harold L Hunt II
|
||||
* Colin Harrison
|
||||
*/
|
||||
|
||||
#ifdef HAVE_XWIN_CONFIG_H
|
||||
#include <xwin-config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "winclipboard.h"
|
||||
|
||||
/*
|
||||
* Main function
|
||||
*/
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
char *pszDisplay = NULL;
|
||||
|
||||
/* Parse command-line parameters */
|
||||
for (i = 1; i < argc; ++i)
|
||||
{
|
||||
/* Look for -display "display_name" or --display "display_name" */
|
||||
if (i < argc - 1
|
||||
&& (!strcmp (argv[i], "-display")
|
||||
|| !strcmp (argv[i], "--display")))
|
||||
{
|
||||
/* Grab a pointer to the display parameter */
|
||||
pszDisplay = argv[i + 1];
|
||||
|
||||
/* Skip the display argument */
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Look for -noprimary */
|
||||
if (!strcmp (argv[i], "-noprimary"))
|
||||
{
|
||||
fPrimarySelection = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Yack when we find a parameter that we don't know about */
|
||||
printf ("Unknown parameter: %s\nExiting.\n", argv[i]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
winClipboardProc(pszDisplay, NULL /* Use XAUTHORITY for auth data */);
|
||||
|
||||
return 0;
|
||||
}
|
62
xserver/hw/xwin/winclipboard/xwinclip.man
Normal file
62
xserver/hw/xwin/winclipboard/xwinclip.man
Normal file
|
@ -0,0 +1,62 @@
|
|||
.TH xwinclip 1 @xorgversion@
|
||||
.SH NAME
|
||||
xwinclip - An X11 and Windows clipboard integration tool
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B xwinclip [OPTION]...
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fIxwinclip\fP is a tool for copying and pasting text between the Windows and X11 clipboard systems.
|
||||
|
||||
\fIxwinclip\fP watches for updates to either clipboard and copies data between them when either one is updated.
|
||||
|
||||
\fIxwinclip\fP monitors the X PRIMARY and CLIBPOARD selections for changes in ownership, and makes
|
||||
the contents of the most recent one to change available to paste from the Windows clipboard.
|
||||
|
||||
It also monitors the contents of the Windows clipboard for changes, taking ownership of the PRIMARY and
|
||||
CLIPBOARD selections, and making the contents of the Windows clipboard available in them.
|
||||
|
||||
.B Note well:
|
||||
The \fIXWin(1)\fP X server has internal clipboard integration that is enabled by default.
|
||||
Do \fINOT\fP run \fIxwinclip\fP unless \fIXWin(1)\fP has been started with the -noclipboard option.
|
||||
|
||||
.SH OPTIONS
|
||||
\fIxwinclip\fP accepts the following optional command line switches:
|
||||
|
||||
.TP 8
|
||||
.B \-display [display]
|
||||
Specifies the X server display to connect to.
|
||||
.TP 8
|
||||
.B \-noprimary
|
||||
Do not monitor the PRIMARY selection.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
XWin(1)
|
||||
|
||||
.SH BUGS
|
||||
Only text clipboard contents are supported.
|
||||
|
||||
The INCR (Incremental transfer) clipboard protocol for clipboard contents larger than the maximum size of an X
|
||||
request (approximately 256K) is only supported for X -> Windows clipboard transfers.
|
||||
|
||||
Some X clients, notably ones written in Tcl/Tk, do not re-assert ownership of the PRIMARY selection or update
|
||||
its timestamp when its contents change, which currently prevents \fIxwinclip\fP from correctly noticing that
|
||||
the PRIMARY selection's contents have changed.
|
||||
|
||||
Windows clipboard rendering is synchronous in the WM_RENDER*FORMAT message (that is, we must have placed the
|
||||
contents onto the clipboard by the time we return from processing this message), but we must wait for the X
|
||||
client which owns the selection to convert the selection to our requested format. This is currently achieved
|
||||
using a fixed timeout. After requesting conversion of the selection, if no events are received from the X
|
||||
client which owns the selection for one second, the conversion is assumed to have failed.
|
||||
|
||||
The XWin(1) server should indicate somehow (by placing an atom on the root window?) that it is running with its
|
||||
internal clipboard integration enabled, and xwinclip should notice this and exit with an appropriate error.
|
||||
|
||||
Probably many other bugs.
|
||||
|
||||
.SH "CONFORMING TO"
|
||||
ICCCM (Inter-Client Communication Conventions Manual) 2.0
|
||||
|
||||
.SH AUTHORS
|
||||
Contributors to xwinclip include Benjamin Riefenstahl, Roland Cassard, Brian Genisio, Colin Harrison,
|
||||
Harold L Hunt II, Matsuzaki Kensuke, Jon Turney, Chris Twiner and Jeremy Wilkins.
|
Loading…
Add table
Add a link
Reference in a new issue