void * winClipboardProc(void *pvNotUsed) { Atom atomClipboard, atomClipboardManager; 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; winDebug("winClipboardProc - Hello\n"); ++clipboardRestarts; /* Do we use Unicode clipboard? */ fUseUnicode = g_fUnicodeClipboard; /* Save the Unicode support flag in a global */ g_fUseUnicode = fUseUnicode; /* Allow multiple threads to access Xlib */ if (XInitThreads() == 0) { ErrorF("winClipboardProc - XInitThreads failed.\n"); goto winClipboardProc_Exit; } /* See if X supports the current locale */ if (XSupportsLocale() == False) { ErrorF("winClipboardProc - Warning: Locale not supported by X.\n"); } /* 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 winClipboardProc_Exit; } 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"); pthread_exit(NULL); } /* 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. */ snprintf(szDisplay, 512, "127.0.0.1:%s.0", display); /* Print the display connection string */ ErrorF("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 winClipboardProc_Done; } /* Save the display in the screen privates */ g_pClipboardDisplay = pDisplay; ErrorF("winClipboardProc - XOpenDisplay () returned and " "successfully opened the display.\n"); /* Get our connection number */ iConnectionNumber = ConnectionNumber(pDisplay); #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 /* Create atoms */ atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False); atomClipboardManager = XInternAtom(pDisplay, "CLIPBOARD_MANAGER", 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 winClipboardProc_Done; } 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; /* Create Windows messaging window */ hwnd = winClipboardCreateMessagingWindow(); /* Save copy of HWND in screen privates */ g_hwndClipboard = hwnd; /* Assert ownership of selections if Win32 clipboard is owned */ if (NULL != GetClipboardOwner()) { /* PRIMARY */ iReturn = XSetSelectionOwner(pDisplay, XA_PRIMARY, iWindow, CurrentTime); if (iReturn == BadAtom || iReturn == BadWindow || XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) { ErrorF("winClipboardProc - Could not set PRIMARY owner\n"); goto winClipboardProc_Done; } /* 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 winClipboardProc_Done; } } /* 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 */ if (!winClipboardFlushWindowsMessageQueue(hwnd)) return 0; /* 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)) { /* Process X events */ /* Exit when we see that server is shutting down */ iReturn = winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode); if (WIN_XEVENTS_SHUTDOWN == iReturn) { ErrorF("winClipboardProc - winClipboardFlushXEvents " "trapped shutdown event, exiting main loop.\n"); break; } } #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; } } } winClipboardProc_Exit: /* disable the clipboard, which means the thread will die */ g_fClipboard = FALSE; winClipboardProc_Done: /* Close our Windows window */ if (g_hwndClipboard) { /* Destroy the Window window (hwnd) */ winDebug("winClipboardProc - Destroy Windows window\n"); PostMessage(g_hwndClipboard, WM_DESTROY, 0, 0); winClipboardFlushWindowsMessageQueue(g_hwndClipboard); } /* Close our X window */ if (pDisplay && iWindow) { iReturn = XDestroyWindow(pDisplay, iWindow); if (iReturn == BadWindow) ErrorF("winClipboardProc - XDestroyWindow returned BadWindow.\n"); else ErrorF("winClipboardProc - XDestroyWindow succeeded.\n"); } #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 /* global clipboard variable reset */ g_fClipboardLaunched = FALSE; g_fClipboardStarted = FALSE; g_iClipboardWindow = None; g_pClipboardDisplay = NULL; g_hwndClipboard = NULL; /* checking if we need to restart */ if (clipboardRestarts >= WIN_CLIPBOARD_RETRIES) { /* terminates clipboard thread but the main server still lives */ ErrorF ("winClipboardProc - the clipboard thread has restarted %d times and seems to be unstable, disabling clipboard integration\n", clipboardRestarts); g_fClipboard = FALSE; return; } if (g_fClipboard) { sleep(WIN_CLIPBOARD_DELAY); ErrorF("winClipboardProc - trying to restart clipboard thread \n"); /* Create the clipboard client thread */ if (!winInitClipboard()) { ErrorF("winClipboardProc - winClipboardInit failed.\n"); return; } winDebug("winClipboardProc - winInitClipboard returned.\n"); /* Flag that clipboard client has been launched */ g_fClipboardLaunched = TRUE; } else { ErrorF("winClipboardProc - Clipboard disabled - Exit from server \n"); /* clipboard thread has exited, stop server as well */ kill(getpid(), SIGTERM); } return NULL; }
int winProcEstablishConnection (ClientPtr client) { int iReturn; static int s_iCallCount = 0; static unsigned long s_ulServerGeneration = 0; ErrorF ("winProcEstablishConnection - Hello\n"); /* Do nothing if clipboard is not enabled */ if (!g_fClipboard) { ErrorF ("winProcEstablishConnection - Clipboard is not enabled, " "returning.\n"); /* Unwrap the original function, call it, and return */ InitialVector[2] = winProcEstablishConnectionOrig; iReturn = (*winProcEstablishConnectionOrig) (client); winProcEstablishConnectionOrig = NULL; return iReturn; } /* Watch for server reset */ if (s_ulServerGeneration != serverGeneration) { /* Save new generation number */ s_ulServerGeneration = serverGeneration; /* Reset call count */ s_iCallCount = 0; } /* Increment call count */ ++s_iCallCount; /* Wait for second call when Xdmcp is enabled */ if (g_fXdmcpEnabled && !g_fClipboardLaunched && s_iCallCount < 4) { ErrorF ("winProcEstablishConnection - Xdmcp enabled, waiting to " "start clipboard client until fourth call.\n"); return (*winProcEstablishConnectionOrig) (client); } /* * This procedure is only used for initialization. * We can unwrap the original procedure at this point * so that this function is no longer called until the * server resets and the function is wrapped again. */ InitialVector[2] = winProcEstablishConnectionOrig; /* * Call original function and bail if it fails. * NOTE: We must do this first, since we need XdmcpOpenDisplay * to be called before we initialize our clipboard client. */ iReturn = (*winProcEstablishConnectionOrig) (client); if (iReturn != 0) { ErrorF ("winProcEstablishConnection - ProcEstablishConnection " "failed, bailing.\n"); return iReturn; } /* Clear original function pointer */ winProcEstablishConnectionOrig = NULL; /* If the clipboard client has already been started, abort */ if (g_fClipboardLaunched) { ErrorF ("winProcEstablishConnection - Clipboard client already " "launched, returning.\n"); return iReturn; } /* Startup the clipboard client if clipboard mode is being used */ if (g_fClipboard) { /* * NOTE: The clipboard client is started here for a reason: * 1) Assume you are using XDMCP (e.g. XWin -query %hostname%) * 2) If the clipboard client attaches during X Server startup, * then it becomes the "magic client" that causes the X Server * to reset if it exits. * 3) XDMCP calls KillAllClients when it starts up. * 4) The clipboard client is a client, so it is killed. * 5) The clipboard client is the "magic client", so the X Server * resets itself. * 6) This repeats ad infinitum. * 7) We avoid this by waiting until at least one client (could * be XDM, could be another client) connects, which makes it * almost certain that the clipboard client will not connect * until after XDM when using XDMCP. * 8) Unfortunately, there is another problem. * 9) XDM walks the list of windows with XQueryTree, * killing any client it finds with a window. * 10)Thus, when using XDMCP we wait until the second call * to ProcEstablishCeonnection before we startup the clipboard * client. This should prevent XDM from finding the clipboard * client, since it has not yet created a window. */ /* Create the clipboard client thread */ if (!winInitClipboard ()) { ErrorF ("winProcEstablishConnection - winClipboardInit " "failed.\n"); return iReturn; } ErrorF ("winProcEstablishConnection - winInitClipboard returned.\n"); } /* Flag that clipboard client has been launched */ g_fClipboardLaunched = TRUE; return iReturn; }
int winProcQueryTree (ClientPtr client) { int iReturn; /* * This procedure is only used for initialization. * We can unwrap the original procedure at this point * so that this function is no longer called until the * server resets and the function is wrapped again. */ ProcVector[X_QueryTree] = winProcQueryTreeOrig; /* * Call original function and bail if it fails. * NOTE: We must do this first, since we need XdmcpOpenDisplay * to be called before we initialize our clipboard client. */ iReturn = (*winProcQueryTreeOrig) (client); if (iReturn != 0) { ErrorF ("winProcQueryTree - ProcQueryTree failed, bailing.\n"); return iReturn; } /* Make errors more obvious */ winProcQueryTreeOrig = NULL; /* Do nothing if clipboard is not enabled */ if (!g_fClipboard) { ErrorF ("winProcQueryTree - Clipboard is not enabled, " "returning.\n"); return iReturn; } /* If the clipboard client has already been started, abort */ if (g_fClipboardLaunched) { ErrorF ("winProcQueryTree - Clipboard client already " "launched, returning.\n"); return iReturn; } /* Startup the clipboard client if clipboard mode is being used */ if (g_fXdmcpEnabled && g_fClipboard) { /* * NOTE: The clipboard client is started here for a reason: * 1) Assume you are using XDMCP (e.g. XWin -query %hostname%) * 2) If the clipboard client attaches during X Server startup, * then it becomes the "magic client" that causes the X Server * to reset if it exits. * 3) XDMCP calls KillAllClients when it starts up. * 4) The clipboard client is a client, so it is killed. * 5) The clipboard client is the "magic client", so the X Server * resets itself. * 6) This repeats ad infinitum. * 7) We avoid this by waiting until at least one client (could * be XDM, could be another client) connects, which makes it * almost certain that the clipboard client will not connect * until after XDM when using XDMCP. * 8) Unfortunately, there is another problem. * 9) XDM walks the list of windows with XQueryTree, * killing any client it finds with a window. * 10)Thus, when using XDMCP we wait until the first call * to ProcQueryTree before we startup the clipboard client. * This should prevent XDM from finding the clipboard client, * since it has not yet created a window. * 11)Startup when not using XDMCP is handled in * winProcEstablishConnection. */ /* Create the clipboard client thread */ if (!winInitClipboard ()) { ErrorF ("winProcQueryTree - winClipboardInit " "failed.\n"); return iReturn; } ErrorF ("winProcQueryTree - winInitClipboard returned.\n"); } /* Flag that clipboard client has been launched */ g_fClipboardLaunched = TRUE; return iReturn; }
int winProcEstablishConnection(ClientPtr client) { int iReturn; static int s_iCallCount = 0; static unsigned long s_ulServerGeneration = 0; if (s_iCallCount == 0) winDebug("winProcEstablishConnection - Hello\n"); /* Do nothing if clipboard is not enabled */ if (!g_fClipboard) { ErrorF("winProcEstablishConnection - Clipboard is not enabled, " "returning.\n"); /* Unwrap the original function, call it, and return */ InitialVector[2] = winProcEstablishConnectionOrig; iReturn = (*winProcEstablishConnectionOrig) (client); winProcEstablishConnectionOrig = NULL; return iReturn; } /* Watch for server reset */ if (s_ulServerGeneration != serverGeneration) { /* Save new generation number */ s_ulServerGeneration = serverGeneration; /* Reset call count */ s_iCallCount = 0; } /* Increment call count */ ++s_iCallCount; /* * This procedure is only used for initialization. * We can unwrap the original procedure at this point * so that this function is no longer called until the * server resets and the function is wrapped again. */ InitialVector[2] = winProcEstablishConnectionOrig; /* * Call original function and bail if it fails. * NOTE: We must do this first, since we need XdmcpOpenDisplay * to be called before we initialize our clipboard client. */ iReturn = (*winProcEstablishConnectionOrig) (client); if (iReturn != 0) { ErrorF("winProcEstablishConnection - ProcEstablishConnection " "failed, bailing.\n"); return iReturn; } /* Clear original function pointer */ winProcEstablishConnectionOrig = NULL; /* Startup the clipboard client if clipboard mode is being used */ if (g_fClipboard) { /* * NOTE: The clipboard client is started here for a reason: * 1) Assume you are using XDMCP (e.g. XWin -query %hostname%) * 2) If the clipboard client attaches during X Server startup, * then it becomes the "magic client" that causes the X Server * to reset if it exits. * 3) XDMCP calls KillAllClients when it starts up. * 4) The clipboard client is a client, so it is killed. * 5) The clipboard client is the "magic client", so the X Server * resets itself. * 6) This repeats ad infinitum. * 7) We avoid this by waiting until at least one client (could * be XDM, could be another client) connects, which makes it * almost certain that the clipboard client will not connect * until after XDM when using XDMCP. */ /* Create the clipboard client thread */ if (!winInitClipboard()) { ErrorF("winProcEstablishConnection - winClipboardInit " "failed.\n"); return iReturn; } ErrorF("winProcEstablishConnection - winInitClipboard returned.\n"); } return iReturn; }