diff options
Diffstat (limited to 'xorg-server/hw/xwin/winclipboard/thread.c')
-rwxr-xr-x | xorg-server/hw/xwin/winclipboard/thread.c | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/xorg-server/hw/xwin/winclipboard/thread.c b/xorg-server/hw/xwin/winclipboard/thread.c new file mode 100755 index 000000000..56f5484e6 --- /dev/null +++ b/xorg-server/hw/xwin/winclipboard/thread.c @@ -0,0 +1,480 @@ +/* + *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 <sys/types.h> +#include <signal.h> +#include <pthread.h> +#include "winclipboard.h" +#include "windisplay.h" +#ifdef __CYGWIN__ +#include <errno.h> +#endif +#include "misc.h" +#include "winmsg.h" +#include "internal.h" + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif +/* + * References to external symbols + */ + +extern Bool g_fUnicodeClipboard; +extern Bool g_fClipboardStarted; +extern Bool g_fClipboardLaunched; +extern HWND g_hwndClipboard; +extern void *g_pClipboardDisplay; +extern Window g_iClipboardWindow; +extern Bool g_fClipboardPrimary; + +/* + * Global variables + */ + +static jmp_buf g_jmpEntry; +static XIOErrorHandler g_winClipboardOldIOErrorHandler; +static pthread_t g_winClipboardProcThread; + +Bool g_fUseUnicode = FALSE; + +/* + * Local function prototypes + */ + +static int + winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr); + +static int + winClipboardIOErrorHandler(Display * pDisplay); + +static void +winClipboardThreadExit(void *arg); +/* + * Main thread function + */ + +void * +winClipboardProc(void *pvNotUsed) +{ + Atom atomClipboard; + int iReturn; + HWND hwnd = NULL; + int iConnectionNumber = 0; + +#ifdef HAS_DEVWINDOWS + int fdMessageQueue = 0; +#else + struct timeval tvTimeout; +#endif + fd_set fdsRead; + int iMaxDescriptor; + Display *pDisplay = NULL; + Window iWindow = None; + int iRetries; + Bool fUseUnicode; + char szDisplay[512]; + int iSelectError; + + pthread_cleanup_push(&winClipboardThreadExit, NULL); + + winDebug ("winClipboardProc - Hello\n"); + + /* Do we use Unicode clipboard? */ + fUseUnicode = g_fUnicodeClipboard; + + /* Save the Unicode support flag in a global */ + g_fUseUnicode = fUseUnicode; + + /* Create Windows messaging window */ + hwnd = winClipboardCreateMessagingWindow (); + + /* Save copy of HWND in screen privates */ + g_hwndClipboard = hwnd; + + /* Set error handler */ + XSetErrorHandler(winClipboardErrorHandler); + g_winClipboardProcThread = pthread_self(); + g_winClipboardOldIOErrorHandler = + XSetIOErrorHandler(winClipboardIOErrorHandler); + + /* Set jump point for Error exits */ + iReturn = setjmp(g_jmpEntry); + + /* Check if we should continue operations */ + if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) { + /* setjmp returned an unknown value, exit */ + ErrorF("winClipboardProc - setjmp returned: %d exiting\n", iReturn); + goto thread_errorexit; + } + else if (iReturn == WIN_JMP_ERROR_IO) { + /* TODO: Cleanup the Win32 window and free any allocated memory */ + ErrorF("winClipboardProc - setjmp returned for IO Error Handler.\n"); + } + + /* Use our generated cookie for authentication */ + winSetAuthorization(); + + /* Initialize retry count */ + iRetries = 0; + + /* Setup the display connection string x */ + /* + * NOTE: Always connect to screen 0 since we require that screen + * numbers start at 0 and increase without gaps. We only need + * to connect to one screen on the display to get events + * for all screens on the display. That is why there is only + * one clipboard client thread. + */ + winGetDisplayName(szDisplay, 0); + + /* Print the display connection string */ + winDebug ("winClipboardProc - DISPLAY=%s\n", szDisplay); + + /* Open the X display */ + do { + pDisplay = XOpenDisplay(szDisplay); + if (pDisplay == NULL) { + ErrorF("winClipboardProc - Could not open display, " + "try: %d, sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY); + ++iRetries; + sleep(WIN_CONNECT_DELAY); + continue; + } + else + break; + } + while (pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES); + + /* Make sure that the display opened */ + if (pDisplay == NULL) { + ErrorF("winClipboardProc - Failed opening the display, giving up\n"); + goto thread_errorexit; + } + + /* Save the display in the screen privates */ + g_pClipboardDisplay = pDisplay; + + winDebug ("winClipboardProc - XOpenDisplay () returned and " + "successfully opened the display.\n"); + + /* Get our connection number */ + iConnectionNumber = ConnectionNumber(pDisplay); + + winDebug("Clipboard is using socket %d\n",iConnectionNumber); + +#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 thread_errorexit; + } + + /* Find max of our file descriptors */ + iMaxDescriptor = max(fdMessageQueue, iConnectionNumber) + 1; +#else + iMaxDescriptor = iConnectionNumber + 1; +#endif + + /* Create atom */ + atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False); + XInternAtom (pDisplay, WIN_LOCAL_PROPERTY, False); + XInternAtom (pDisplay, "UTF8_STRING", False); + XInternAtom (pDisplay, "COMPOUND_TEXT", False); + XInternAtom (pDisplay, "TARGETS", False); + + /* Create a messaging window */ + iWindow = XCreateSimpleWindow(pDisplay, + DefaultRootWindow(pDisplay), + 1, 1, + 500, 500, + 0, + BlackPixel(pDisplay, 0), + BlackPixel(pDisplay, 0)); + if (iWindow == 0) { + ErrorF("winClipboardProc - Could not create an X window.\n"); + goto thread_errorexit; + } + + XStoreName(pDisplay, iWindow, "xwinclip"); + + /* Select event types to watch */ + if (XSelectInput(pDisplay, iWindow, PropertyChangeMask) == BadWindow) + ErrorF("winClipboardProc - XSelectInput generated BadWindow " + "on messaging window\n"); + + /* Save the window in the screen privates */ + g_iClipboardWindow = iWindow; + + /* Assert ownership of selections if Win32 clipboard is owned */ + if (NULL != GetClipboardOwner()) { + if (g_fClipboardPrimary) + { + /* PRIMARY */ + winDebug("winClipboardProc - asserted ownership.\n"); + iReturn = XSetSelectionOwner (pDisplay, XA_PRIMARY, + iWindow, CurrentTime); + if (iReturn == BadAtom || iReturn == BadWindow /*|| + XGetSelectionOwner (pDisplay, XA_PRIMARY) != iWindow*/) + { + ErrorF ("winClipboardProc - Could not set PRIMARY owner\n"); + goto thread_errorexit; + } + } + + /* CLIPBOARD */ + iReturn = XSetSelectionOwner(pDisplay, atomClipboard, + iWindow, CurrentTime); + if (iReturn == BadAtom || iReturn == BadWindow /*|| + XGetSelectionOwner (pDisplay, atomClipboard) != iWindow*/) + { + ErrorF ("winClipboardProc - Could not set CLIPBOARD owner\n"); + goto thread_errorexit; + } + } + + /* Pre-flush X events */ + /* + * NOTE: Apparently you'll freeze if you don't do this, + * because there may be events in local data structures + * already. + */ + //winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode); + + /* Pre-flush Windows messages */ + winDebug ("Start flushing \n"); + if (!winClipboardFlushWindowsMessageQueue(hwnd)) + { + ErrorF ("winClipboardFlushWindowsMessageQueue - returned 0\n"); + goto thread_errorexit; + } + + winDebug ("winClipboardProc - Started\n"); + /* Signal that the clipboard client has started */ + g_fClipboardStarted = TRUE; + + /* Loop for X events */ + while (1) { + /* 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; + } + + /* Branch on which descriptor became active */ +// if (FD_ISSET (iConnectionNumber, &fdsRead)) { +// Also do it when no read since winClipboardFlushXEvents +// is sending the output. + /* Process X events */ + winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode, FALSE); +// } + +#ifdef HAS_DEVWINDOWS + /* Check for Windows event ready */ + if (FD_ISSET(fdMessageQueue, &fdsRead)) +#else + if (1) +#endif + { + /* Process Windows messages */ + if (!winClipboardFlushWindowsMessageQueue(hwnd)) { + ErrorF("winClipboardProc - " + "winClipboardFlushWindowsMessageQueue trapped " + "WM_QUIT message, exiting main loop.\n"); + break; + } + } + } + + /* Close our X window */ + if (pDisplay && iWindow) { + iReturn = XDestroyWindow(pDisplay, iWindow); + if (iReturn == BadWindow) + ErrorF("winClipboardProc - XDestroyWindow returned BadWindow.\n"); +#ifdef WINDBG + else + winDebug("winClipboardProc - XDestroyWindow succeeded.\n"); +#endif + } + +#ifdef HAS_DEVWINDOWS + /* Close our Win32 message handle */ + if (fdMessageQueue) + close(fdMessageQueue); +#endif + +#if 0 + /* + * FIXME: XCloseDisplay hangs if we call it, as of 2004/03/26. The + * XSync and XSelectInput calls did not help. + */ + + /* Discard any remaining events */ + XSync(pDisplay, TRUE); + + /* Select event types to watch */ + XSelectInput(pDisplay, DefaultRootWindow(pDisplay), None); + + /* Close our X display */ + if (pDisplay) { + XCloseDisplay(pDisplay); + } +#endif + + goto commonexit; + +thread_errorexit: + if (g_pClipboardDisplay && g_iClipboardWindow) + { + iReturn = XDestroyWindow (g_pClipboardDisplay, g_iClipboardWindow); + if (iReturn == BadWindow) + ErrorF ("winClipboardProc - XDestroyWindow returned BadWindow.\n"); +#ifdef WINDBG + else + winDebug ("winClipboardProc - XDestroyWindow succeeded.\n"); +#endif + } + winDebug ("Clipboard thread died.\n"); + +commonexit: + g_iClipboardWindow = None; + g_pClipboardDisplay = NULL; + g_fClipboardLaunched = FALSE; + g_fClipboardStarted = FALSE; + + pthread_cleanup_pop(0); + + return NULL; +} + +/* + * 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" + " errorCode %d\n" + " serial %lu\n" + " resourceID 0x%x\n" + " majorCode %d\n" + " minorCode %d\n" + , pszErrorMsg + , pErr->error_code + , pErr->serial + , pErr->resourceid + , 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, WIN_JMP_ERROR_IO); + } + + if (g_winClipboardOldIOErrorHandler) + g_winClipboardOldIOErrorHandler(pDisplay); + + return 0; +} + +/* + * winClipboardThreadExit - Thread exit handler + */ + +static void +winClipboardThreadExit(void *arg) +{ + /* clipboard thread has exited, stop server as well */ + AbortDDX(EXIT_ERR_ABORT); + TerminateProcess(GetCurrentProcess(),1); +} |