2003-11-14 16:48:57 +00:00
/*
2004-06-21 13:19:32 +00:00
* Copyright ( C ) 2003 - 2004 Harold L Hunt II All Rights Reserved .
2009-02-03 15:48:04 +00:00
* Copyright ( C ) Colin Harrison 2005 - 2008
2003-11-14 16:48:57 +00:00
*
* 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
2004-06-21 13:19:32 +00:00
* NONINFRINGEMENT . IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
2003-11-14 16:48:57 +00:00
* 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 .
*
2009-02-03 15:48:04 +00:00
* 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 ) .
2003-11-14 16:48:57 +00:00
*
* Authors : Harold L Hunt II
2009-02-03 15:48:04 +00:00
* Colin Harrison
2003-11-14 16:48:57 +00:00
*/
2005-07-04 22:10:43 +00:00
# ifdef HAVE_XWIN_CONFIG_H
# include <xwin-config.h>
2011-11-04 13:17:50 -05:00
# else
# define HAS_WINSOCK 1
2005-07-04 22:10:43 +00:00
# endif
# include <sys/types.h>
2003-11-14 16:48:57 +00:00
# include "winclipboard.h"
2004-11-15 15:06:51 +00:00
# ifdef __CYGWIN__
# include <errno.h>
# endif
2009-06-02 21:19:46 +01:00
# include "misc.h"
2004-06-21 13:19:32 +00:00
2003-11-14 16:48:57 +00:00
/*
* References to external symbols
*/
2004-06-21 13:19:32 +00:00
extern Bool g_fUnicodeClipboard ;
extern unsigned long serverGeneration ;
extern Bool g_fClipboardStarted ;
2010-10-31 14:53:02 +00:00
extern Bool g_fClipboardLaunched ;
extern Bool g_fClipboard ;
2004-06-21 13:19:32 +00:00
extern HWND g_hwndClipboard ;
extern void * g_pClipboardDisplay ;
extern Window g_iClipboardWindow ;
2003-11-14 16:48:57 +00:00
/*
* Global variables
*/
static jmp_buf g_jmpEntry ;
2010-10-31 14:53:02 +00:00
static int clipboardRestarts = 0 ;
2004-06-21 13:19:32 +00:00
Bool g_fUnicodeSupport = FALSE ;
2004-08-03 10:12:25 +00:00
Bool g_fUseUnicode = FALSE ;
2003-11-14 16:48:57 +00:00
/*
* Local function prototypes
*/
static int
winClipboardErrorHandler ( Display * pDisplay , XErrorEvent * pErr ) ;
static int
winClipboardIOErrorHandler ( Display * pDisplay ) ;
/*
* Main thread function
*/
void *
2004-06-21 13:19:32 +00:00
winClipboardProc ( void * pvNotUsed )
2003-11-14 16:48:57 +00:00
{
Atom atomClipboard , atomClipboardManager ;
int iReturn ;
HWND hwnd = NULL ;
2004-06-21 13:19:32 +00:00
int iConnectionNumber = 0 ;
2004-11-15 15:06:51 +00:00
# ifdef HAS_DEVWINDOWS
2004-06-21 13:19:32 +00:00
int fdMessageQueue = 0 ;
2004-11-15 15:06:51 +00:00
# else
struct timeval tvTimeout ;
# endif
2003-11-14 16:48:57 +00:00
fd_set fdsRead ;
int iMaxDescriptor ;
2004-06-21 13:19:32 +00:00
Display * pDisplay = NULL ;
Window iWindow = None ;
2003-11-14 16:48:57 +00:00
int iRetries ;
2004-08-03 10:12:25 +00:00
Bool fUseUnicode ;
2003-11-14 16:48:57 +00:00
char szDisplay [ 512 ] ;
2004-11-15 15:06:51 +00:00
int iSelectError ;
2003-11-14 16:48:57 +00:00
ErrorF ( " winClipboardProc - Hello \n " ) ;
2010-10-31 14:53:02 +00:00
+ + clipboardRestarts ;
2003-11-14 16:48:57 +00:00
/* Do we have Unicode support? */
2004-08-03 10:12:25 +00:00
g_fUnicodeSupport = winClipboardDetectUnicodeSupport ( ) ;
/* Do we use Unicode clipboard? */
fUseUnicode = g_fUnicodeClipboard & & g_fUnicodeSupport ;
2003-11-14 16:48:57 +00:00
2004-06-21 13:19:32 +00:00
/* Save the Unicode support flag in a global */
2004-08-03 10:12:25 +00:00
g_fUseUnicode = fUseUnicode ;
2003-11-14 16:48:57 +00:00
/* Allow multiple threads to access Xlib */
if ( XInitThreads ( ) = = 0 )
{
ErrorF ( " winClipboardProc - XInitThreads failed. \n " ) ;
2010-10-31 14:53:02 +00:00
goto winClipboardProc_Exit ;
2003-11-14 16:48:57 +00:00
}
2004-06-21 13:19:32 +00:00
/* See if X supports the current locale */
if ( XSupportsLocale ( ) = = False )
{
2009-10-29 18:50:23 +00:00
ErrorF ( " winClipboardProc - Warning: Locale not supported by X. \n " ) ;
2004-06-21 13:19:32 +00:00
}
2003-11-25 19:29:01 +00:00
2003-11-14 16:48:57 +00:00
/* 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 ) ;
2010-10-31 14:53:02 +00:00
goto winClipboardProc_Exit ;
2003-11-14 16:48:57 +00:00
}
else if ( iReturn = = WIN_JMP_ERROR_IO )
{
2004-06-21 13:19:32 +00:00
/* TODO: Cleanup the Win32 window and free any allocated memory */
ErrorF ( " winClipboardProc - setjmp returned for IO Error Handler. \n " ) ;
pthread_exit ( NULL ) ;
2003-11-14 16:48:57 +00:00
}
2004-06-21 13:19:32 +00:00
/* Use our generated cookie for authentication */
2009-07-13 13:46:45 +01:00
winSetAuthorization ( ) ;
2004-06-21 13:19:32 +00:00
/* Set error handler */
XSetErrorHandler ( winClipboardErrorHandler ) ;
XSetIOErrorHandler ( winClipboardIOErrorHandler ) ;
2003-11-14 16:48:57 +00:00
/* Initialize retry count */
iRetries = 0 ;
/* Setup the display connection string x */
2004-06-21 13:19:32 +00:00
/*
* 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 .
*/
2003-11-25 19:29:01 +00:00
snprintf ( szDisplay ,
512 ,
2004-06-21 13:19:32 +00:00
" 127.0.0.1:%s.0 " ,
display ) ;
2003-11-14 16:48:57 +00:00
/* 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 " ) ;
2010-10-31 14:53:02 +00:00
goto winClipboardProc_Done ;
2003-11-14 16:48:57 +00:00
}
2004-06-21 13:19:32 +00:00
/* Save the display in the screen privates */
g_pClipboardDisplay = pDisplay ;
2003-11-14 16:48:57 +00:00
ErrorF ( " winClipboardProc - XOpenDisplay () returned and "
" successfully opened the display. \n " ) ;
/* Get our connection number */
iConnectionNumber = ConnectionNumber ( pDisplay ) ;
2004-11-15 15:06:51 +00:00
# ifdef HAS_DEVWINDOWS
2003-11-14 16:48:57 +00:00
/* 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 ) ;
2010-10-31 14:53:02 +00:00
goto winClipboardProc_Done ;
2003-11-14 16:48:57 +00:00
}
/* Find max of our file descriptors */
iMaxDescriptor = max ( fdMessageQueue , iConnectionNumber ) + 1 ;
2004-11-15 15:06:51 +00:00
# else
iMaxDescriptor = iConnectionNumber + 1 ;
# endif
2003-11-14 16:48:57 +00:00
2004-06-21 13:19:32 +00:00
/* Create atoms */
atomClipboard = XInternAtom ( pDisplay , " CLIPBOARD " , False ) ;
atomClipboardManager = XInternAtom ( pDisplay , " CLIPBOARD_MANAGER " , False ) ;
2003-11-14 16:48:57 +00:00
/* Create a messaging window */
iWindow = XCreateSimpleWindow ( pDisplay ,
DefaultRootWindow ( pDisplay ) ,
1 , 1 ,
500 , 500 ,
0 ,
BlackPixel ( pDisplay , 0 ) ,
BlackPixel ( pDisplay , 0 ) ) ;
if ( iWindow = = 0 )
{
2004-06-21 13:19:32 +00:00
ErrorF ( " winClipboardProc - Could not create an X window. \n " ) ;
2010-10-31 14:53:02 +00:00
goto winClipboardProc_Done ;
2003-11-14 16:48:57 +00:00
}
2010-02-08 22:37:30 +00:00
XStoreName ( pDisplay , iWindow , " xwinclip " ) ;
2009-02-03 15:51:02 +00:00
/* Select event types to watch */
if ( XSelectInput ( pDisplay ,
iWindow ,
PropertyChangeMask ) = = BadWindow )
ErrorF ( " winClipboardProc - XSelectInput generated BadWindow "
" on messaging window \n " ) ;
2004-06-21 13:19:32 +00:00
/* Save the window in the screen privates */
g_iClipboardWindow = iWindow ;
2003-11-14 16:48:57 +00:00
2004-06-21 13:19:32 +00:00
/* Create Windows messaging window */
hwnd = winClipboardCreateMessagingWindow ( ) ;
/* Save copy of HWND in screen privates */
g_hwndClipboard = hwnd ;
2003-11-14 16:48:57 +00:00
2004-06-21 13:19:32 +00:00
/* Assert ownership of selections if Win32 clipboard is owned */
if ( NULL ! = GetClipboardOwner ( ) )
2003-11-14 16:48:57 +00:00
{
2004-06-21 13:19:32 +00:00
/* PRIMARY */
iReturn = XSetSelectionOwner ( pDisplay , XA_PRIMARY ,
iWindow , CurrentTime ) ;
2009-02-03 15:57:29 +00:00
if ( iReturn = = BadAtom | | iReturn = = BadWindow | |
XGetSelectionOwner ( pDisplay , XA_PRIMARY ) ! = iWindow )
2004-06-21 13:19:32 +00:00
{
ErrorF ( " winClipboardProc - Could not set PRIMARY owner \n " ) ;
2010-10-31 14:53:02 +00:00
goto winClipboardProc_Done ;
2004-06-21 13:19:32 +00:00
}
2003-11-14 16:48:57 +00:00
2004-06-21 13:19:32 +00:00
/* CLIPBOARD */
iReturn = XSetSelectionOwner ( pDisplay , atomClipboard ,
iWindow , CurrentTime ) ;
2009-02-03 15:57:29 +00:00
if ( iReturn = = BadAtom | | iReturn = = BadWindow | |
XGetSelectionOwner ( pDisplay , atomClipboard ) ! = iWindow )
2004-06-21 13:19:32 +00:00
{
ErrorF ( " winClipboardProc - Could not set CLIPBOARD owner \n " ) ;
2010-10-31 14:53:02 +00:00
goto winClipboardProc_Done ;
2004-06-21 13:19:32 +00:00
}
2003-11-14 16:48:57 +00:00
}
/* 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 ,
2004-08-03 10:12:25 +00:00
fUseUnicode ) ;
2003-11-14 16:48:57 +00:00
/* Pre-flush Windows messages */
if ( ! winClipboardFlushWindowsMessageQueue ( hwnd ) )
return 0 ;
2004-06-21 13:19:32 +00:00
/* Signal that the clipboard client has started */
g_fClipboardStarted = TRUE ;
2003-11-14 16:48:57 +00:00
/* 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 ) ;
2004-11-15 15:06:51 +00:00
# ifdef HAS_DEVWINDOWS
FD_SET ( fdMessageQueue , & fdsRead ) ;
# else
tvTimeout . tv_sec = 0 ;
tvTimeout . tv_usec = 100 ;
# endif
2003-11-14 16:48:57 +00:00
/* 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 */
2004-11-15 15:06:51 +00:00
# ifdef HAS_DEVWINDOWS
NULL /* No timeout */
# else
& tvTimeout /* Set timeout */
# endif
) ;
# ifndef HAS_WINSOCK
iSelectError = errno ;
# else
iSelectError = WSAGetLastError ( ) ;
# endif
if ( iReturn < 0 )
2003-11-14 16:48:57 +00:00
{
2004-11-15 15:06:51 +00:00
# ifndef HAS_WINSOCK
if ( iSelectError = = EINTR )
# else
if ( iSelectError = = WSAEINTR )
# endif
continue ;
2003-11-14 16:48:57 +00:00
ErrorF ( " winClipboardProc - Call to select () failed: %d. "
" Bailing. \n " , iReturn ) ;
break ;
}
2004-06-21 13:19:32 +00:00
2003-11-14 16:48:57 +00:00
/* Branch on which descriptor became active */
if ( FD_ISSET ( iConnectionNumber , & fdsRead ) )
{
/* Process X events */
/* Exit when we see that server is shutting down */
2004-06-21 13:19:32 +00:00
iReturn = winClipboardFlushXEvents ( hwnd ,
2003-11-14 16:48:57 +00:00
iWindow ,
pDisplay ,
2004-08-03 10:12:25 +00:00
fUseUnicode ) ;
2004-06-21 13:19:32 +00:00
if ( WIN_XEVENTS_SHUTDOWN = = iReturn )
2003-11-14 16:48:57 +00:00
{
2004-06-21 13:19:32 +00:00
ErrorF ( " winClipboardProc - winClipboardFlushXEvents "
" trapped shutdown event, exiting main loop. \n " ) ;
2003-11-14 16:48:57 +00:00
break ;
}
}
2004-11-15 15:06:51 +00:00
# ifdef HAS_DEVWINDOWS
2003-11-14 16:48:57 +00:00
/* Check for Windows event ready */
if ( FD_ISSET ( fdMessageQueue , & fdsRead ) )
2004-11-15 15:06:51 +00:00
# else
if ( 1 )
2003-11-14 16:48:57 +00:00
# endif
2004-11-15 15:06:51 +00:00
{
2003-11-14 16:48:57 +00:00
/* Process Windows messages */
if ( ! winClipboardFlushWindowsMessageQueue ( hwnd ) )
2004-06-21 13:19:32 +00:00
{
ErrorF ( " winClipboardProc - "
" winClipboardFlushWindowsMessageQueue trapped "
" WM_QUIT message, exiting main loop. \n " ) ;
break ;
}
2003-11-14 16:48:57 +00:00
}
}
2010-10-31 14:53:02 +00:00
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 ) ;
}
2004-06-21 13:19:32 +00:00
/* 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 " ) ;
}
2004-11-15 15:06:51 +00:00
# ifdef HAS_DEVWINDOWS
2004-06-21 13:19:32 +00:00
/* Close our Win32 message handle */
if ( fdMessageQueue )
close ( fdMessageQueue ) ;
2004-11-15 15:06:51 +00:00
# endif
2004-06-21 13:19:32 +00:00
#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
2010-10-31 14:53:02 +00:00
/* global clipboard variable reset */
g_fClipboardLaunched = FALSE ;
g_fClipboardStarted = FALSE ;
2004-06-21 13:19:32 +00:00
g_iClipboardWindow = None ;
g_pClipboardDisplay = NULL ;
g_hwndClipboard = NULL ;
2010-10-31 14:53:02 +00:00
/* 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 ) ;
}
2004-06-21 13:19:32 +00:00
return NULL ;
2003-11-14 16:48:57 +00:00
}
/*
* winClipboardErrorHandler - Our application specific error handler
*/
static int
winClipboardErrorHandler ( Display * pDisplay , XErrorEvent * pErr )
{
char pszErrorMsg [ 100 ] ;
XGetErrorText ( pDisplay ,
pErr - > error_code ,
pszErrorMsg ,
sizeof ( pszErrorMsg ) ) ;
2004-10-28 14:23:08 +00:00
ErrorF ( " winClipboardErrorHandler - ERROR: \n \t %s \n "
2010-10-15 14:13:57 +01:00
" \t Serial: %lu, Request Code: %d, Minor Code: %d \n " ,
2004-10-28 14:23:08 +00:00
pszErrorMsg ,
pErr - > serial ,
pErr - > request_code ,
pErr - > minor_code ) ;
2003-11-14 16:48:57 +00:00
return 0 ;
}
/*
* winClipboardIOErrorHandler - Our application specific IO error handler
*/
static int
winClipboardIOErrorHandler ( Display * pDisplay )
{
2010-02-26 14:22:57 +00:00
ErrorF ( " winClipboardIOErrorHandler! \n \n " ) ;
2003-11-14 16:48:57 +00:00
/* Restart at the main entry point */
longjmp ( g_jmpEntry , WIN_JMP_ERROR_IO ) ;
return 0 ;
}