@ -29,6 +29,11 @@
typedef bool ( * x11Proc ) ( NL3D : : IDriver * drv , XEvent * e ) ;
typedef bool ( * x11Proc ) ( NL3D : : IDriver * drv , XEvent * e ) ;
static Atom XA_CLIPBOARD = 0 ;
static Atom XA_UTF8_STRING = 0 ;
static Atom XA_TARGETS = 0 ;
static Atom XA_NEL_SEL = 0 ;
namespace NLMISC {
namespace NLMISC {
CUnixEventEmitter : : CUnixEventEmitter ( ) : _dpy ( NULL ) , _win ( 0 ) , _emulateRawMode ( false ) , _driver ( NULL )
CUnixEventEmitter : : CUnixEventEmitter ( ) : _dpy ( NULL ) , _win ( 0 ) , _emulateRawMode ( false ) , _driver ( NULL )
@ -51,18 +56,12 @@ void CUnixEventEmitter::init(Display *dpy, Window win, NL3D::IDriver *driver)
_driver = driver ;
_driver = driver ;
XSelectInput ( _dpy , _win , KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | ExposureMask ) ;
XSelectInput ( _dpy , _win , KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | ExposureMask ) ;
_PrecomputedAtom [ 0 ] = XInternAtom ( dpy , " CLIPBOARD " , False ) ;
# define XA_CLIPBOARD _PrecomputedAtom[0]
// define Atoms used by clipboard
_PrecomputedAtom [ 1 ] = XInternAtom ( dpy , " UTF8_STRING " , False ) ;
XA_CLIPBOARD = XInternAtom ( dpy , " CLIPBOARD " , False ) ;
# define XA_UTF8_STRING _PrecomputedAtom[1]
XA_UTF8_STRING = XInternAtom ( dpy , " UTF8_STRING " , False ) ;
_PrecomputedAtom [ 2 ] = XInternAtom ( dpy , " TARGETS " , False ) ;
XA_TARGETS = XInternAtom ( dpy , " TARGETS " , False ) ;
# define XA_TARGETS _PrecomputedAtom[2]
XA_NEL_SEL = XInternAtom ( dpy , " NeL_SEL " , False ) ;
_PrecomputedAtom [ 3 ] = XInternAtom ( dpy , " ATOM " , False ) ;
//#define XA_ATOM _PrecomputedAtom[3]
_PrecomputedAtom [ 4 ] = XInternAtom ( dpy , " NeL_SEL " , False ) ;
# define XA_NEL_SEL _PrecomputedAtom[4]
_PrecomputedAtom [ 5 ] = XInternAtom ( dpy , " TEXT " , False ) ;
# define XA_TEXT _PrecomputedAtom[5]
/*
/*
TODO : implements all useful events processing
TODO : implements all useful events processing
@ -568,10 +567,23 @@ bool CUnixEventEmitter::processMessage (XEvent &event, CEventServer *server)
# ifdef X_HAVE_UTF8_STRING
# ifdef X_HAVE_UTF8_STRING
ucstring ucstr ;
ucstring ucstr ;
ucstr . fromUtf8 ( Text ) ;
ucstr . fromUtf8 ( Text ) ;
server - > postEvent ( new CEventChar ( ucstr [ 0 ] , noKeyButton , this ) ) ;
CEventChar * charEvent = new CEventChar ( ucstr [ 0 ] , noKeyButton , this ) ;
// raw if not processed by IME
charEvent - > setRaw ( keyCode ! = 0 ) ;
server - > postEvent ( charEvent ) ;
# else
# else
for ( int i = 0 ; i < c ; i + + )
for ( int i = 0 ; i < c ; i + + )
server - > postEvent ( new CEventChar ( ( ucchar ) ( unsigned char ) Text [ i ] , noKeyButton , this ) ) ;
{
CEventChar * charEvent = new CEventChar ( ( ucchar ) ( unsigned char ) Text [ i ] , noKeyButton , this ) ;
// raw if not processed by IME
charEvent - > setRaw ( keyCode ! = 0 ) ;
server - > postEvent ( charEvent ) ;
}
# endif
# endif
}
}
break ;
break ;
@ -612,12 +624,10 @@ bool CUnixEventEmitter::processMessage (XEvent &event, CEventServer *server)
}
}
if ( req . target = = XA_TARGETS )
if ( req . target = = XA_TARGETS )
{
{
nlwarning ( " Client is asking for TARGETS " ) ;
Atom targets [ ] =
Atom targets [ ] =
{
{
XA_TARGETS ,
XA_TARGETS ,
XA_ TEXT ,
XA_ STRING ,
XA_UTF8_STRING
XA_UTF8_STRING
} ;
} ;
@ -625,23 +635,21 @@ bool CUnixEventEmitter::processMessage (XEvent &event, CEventServer *server)
XChangeProperty ( req . display , req . requestor , req . property , XA_ATOM , 32 , PropModeReplace , ( unsigned char * ) targets , 3 /* number of element */ ) ;
XChangeProperty ( req . display , req . requestor , req . property , XA_ATOM , 32 , PropModeReplace , ( unsigned char * ) targets , 3 /* number of element */ ) ;
}
}
else if ( req . target = = XA_ TEXT | | req . target = = XA_ STRING )
else if ( req . target = = XA_ STRING)
{
{
nlwarning ( " client want TEXT " ) ;
respond . xselection . property = req . property ;
respond . xselection . property = req . property ;
std : : string str = _CopiedString . toString ( ) ;
std : : string str = _CopiedString . toString ( ) ;
XChangeProperty ( req . display , req . requestor , req . property , XA_STRING , 8 , PropModeReplace , ( const unsigned char * ) str . c_str ( ) , str . length ( ) ) ;
XChangeProperty ( req . display , req . requestor , req . property , XA_STRING , 8 , PropModeReplace , ( const unsigned char * ) str . c_str ( ) , str . length ( ) ) ;
}
}
else if ( req . target = = XA_UTF8_STRING )
else if ( req . target = = XA_UTF8_STRING )
{
{
nlwarning ( " Client want UTF8 STRING " ) ;
respond . xselection . property = req . property ;
respond . xselection . property = req . property ;
std : : string str = _CopiedString . toUtf8 ( ) ;
std : : string str = _CopiedString . toUtf8 ( ) ;
XChangeProperty ( req . display , req . requestor , respond . xselection . property , X Intern Atom( _dpy, " UTF8_STRING" , False ) , 8 , PropModeReplace , ( const unsigned char * ) str . c_str ( ) , str len( ( char * ) str . c_str ( ) ) ) ;
XChangeProperty ( req . display , req . requestor , respond . xselection . property , X A_UTF8_STRING, 8 , PropModeReplace , ( const unsigned char * ) str . c_str ( ) , str . length ( ) ) ;
}
}
else
else
{
{
nlwarning ( " Target doesn't want a string %u " , ( uint ) req . target ) ; // Note: Calling XGetAtomName with arbitrary value crash the client, maybe req.target have been sanitized by X11 server
// Note: Calling XGetAtomName with arbitrary value crash the client, maybe req.target have been sanitized by X11 server
respond . xselection . property = None ;
respond . xselection . property = None ;
}
}
@ -650,211 +658,177 @@ bool CUnixEventEmitter::processMessage (XEvent &event, CEventServer *server)
break ;
break ;
}
}
case SelectionClear :
case SelectionClear :
nlwarning ( " SelectionClear: " ) ;
_SelectionOwned = false ;
_SelectionOwned = false ;
_CopiedString = " " ;
_CopiedString = " " ;
break ;
break ;
case FocusIn :
case SelectionNotify :
// keyboard focus
{
if ( _ic ) XSetICFocus ( _ic ) ;
Atom target = event . xselection . target ;
break ;
case FocusOut :
// keyboard focus
if ( _ic ) XUnsetICFocus ( _ic ) ;
break ;
case KeymapNotify :
break ;
case MappingNotify :
// update keymap
XRefreshKeyboardMapping ( ( XMappingEvent * ) & event ) ;
break ;
case DestroyNotify :
// XIM server has crashed
createIM ( ) ;
break ;
default :
// nlinfo("UnknownEvent");
// XtDispatchEvent(&event);
return false ;
}
return true ;
Atom actualType = 0 ;
}
int actualFormat = 0 ;
unsigned long nitems = 0 , bytesLeft = 0 ;
/**
// some applications are sending ATOM and other TARGETS
* This function copy a selection into propertyName .
if ( target = = XA_TARGETS | | target = = XA_ATOM )
* It is subject to timeout .
*
* @ param selection : A Selection Atom
* @ param requestedFormat : Target format Atom
* @ param propertyName : Target property Atom
* @ return true if successfull , false if timeout occured or X11 call failed
*/
bool CUnixEventEmitter : : prepareSelectionContent ( Atom selection , Atom requestedFormat , Atom propertyName )
{
{
XConvertSelection ( _dpy , selection , requestedFormat , propertyName , _win , CurrentTime ) ;
Atom * supportedTargets = NULL ;
XSync ( _dpy , False ) ;
// list NeL selection properties
if ( XGetWindowProperty ( _dpy , _win , XA_NEL_SEL , 0 , XMaxRequestSize ( _dpy ) , False , AnyPropertyType , & actualType , & actualFormat , & nitems , & bytesLeft , ( unsigned char * * ) & supportedTargets ) ! = Success )
return false ;
int i = 0 ;
if ( bytesLeft > 0 )
{
nlwarning ( " Paste: Supported TARGETS list too long. " ) ;
}
bool gotReply = false ;
Atom bestTarget = 0 ;
sint bestTargetElect = 0 ;
do
// Elect best type
for ( uint i = 0 ; i < nitems ; i + + )
{
{
XEvent event ;
// nlwarning(" - Type=%s (%u)", XGetAtomName(_dpy, supportedTargets[i]), (uint)supportedTargets[i]);
usleep ( 500 ) ;
if ( supportedTargets [ i ] = = XA_UTF8_STRING )
gotReply = XCheckTypedWindowEvent ( _dpy , _win , SelectionNotify , & event ) ;
if ( gotReply )
{
{
return true ;
if ( bestTargetElect < 2 )
}
{
i + + ;
bestTarget = XA_UTF8_STRING ;
bestTargetElect = 2 ;
}
}
while ( i < 20 ) ;
return false ;
}
}
else if ( supportedTargets [ i ] = = XA_STRING )
bool CUnixEventEmitter : : copyTextToClipboard ( const ucstring & text )
{
_CopiedString = text ;
XSetSelectionOwner ( _dpy , XA_CLIPBOARD , _win , CurrentTime ) ;
{
{
Window selectionOwner = XGetSelectionOwner ( _dpy , XA_CLIPBOARD ) ;
if ( bestTargetElect < 1 )
if ( selectionOwner ! = _win )
{
{
nlwarning ( " Can't aquire selection " ) ;
bestTarget = XA_STRING ;
return false ;
bestTargetElect = 1 ;
}
}
}
_SelectionOwned = true ;
nlwarning ( " Owning selection " ) ;
return true ;
}
}
nlwarning ( " Paste: Can't acquire selection. " ) ;
XFree ( supportedTargets ) ;
if ( ! bestTargetElect )
{
nlwarning ( " Paste buffer is not a text buffer. " ) ;
return false ;
return false ;
}
}
bool CUnixEventEmitter : : pasteTextFromClipboard ( ucstring & text )
// request string conversion
{
XConvertSelection ( _dpy , XA_CLIPBOARD , bestTarget , XA_NEL_SEL , _win , CurrentTime ) ;
// check if we own the selection
if ( _SelectionOwned )
{
text = _CopiedString ;
return true ;
}
}
else if ( target = = XA_UTF8_STRING | | target = = XA_STRING )
Window selectionOwner = XGetSelectionOwner ( _dpy , XA_CLIPBOARD ) ;
if ( selectionOwner ! = None )
{
{
Atom * supportedTargets ;
uint8 * data = NULL ;
uint8 * data ;
sint result ;
unsigned long nitems , bytesLeft ;
Atom actualType ;
sint actualFormat ;
sint bestTargetElect = 0 , bestTarget = 0 ;
nlwarning ( " Selection owner is %u " , ( uint ) selectionOwner ) ;
// Find supported methods
// get selection
bool bres = prepareSelectionContent ( XA_CLIPBOARD , XA_TARGETS , XA_NEL_SEL ) ;
if ( XGetWindowProperty ( _dpy , _win , XA_NEL_SEL , 0 , XMaxRequestSize ( _dpy ) , False , AnyPropertyType , & actualType , & actualFormat , & nitems , & bytesLeft , ( unsigned char * * ) & data ) ! = Success )
if ( ! bres )
{
nlwarning ( " Paste: Cannot ennumerate TARGETS " ) ;
return false ;
return false ;
}
result = XGetWindowProperty ( _dpy , _win , XA_NEL_SEL , 0 , XMaxRequestSize ( _dpy ) , False , AnyPropertyType , & actualType , & actualFormat , & nitems , & bytesLeft , ( unsigned char * * ) & supportedTargets ) ;
ucstring text ;
std : : string tmpData = ( const char * ) data ;
XFree ( data ) ;
if ( result ! = Success )
// convert buffer to ucstring
if ( target = = XA_UTF8_STRING )
{
{
return false ;
text = ucstring : : makeFromUtf8 ( tmpData ) ;
}
}
else if ( target = = XA_STRING )
if ( bytesLeft > 0 )
{
{
nlwarning ( " Paste: Supported TARGETS list too long. " ) ; // We hope we find what we need in the first packet.
text = tmpData ;
}
}
else
// Elect best type
for ( uint i = 0 ; i < nitems ; i + + )
{
{
nldebug ( " - Type=%s " , XGetAtomName ( _dpy , supportedTargets [ i ] ) ) ;
nlwarning ( " Unknow format %u " , ( uint ) target ) ;
}
if ( supportedTargets [ i ] = = XA_STRING )
// sent string event to event server
{
server - > postEvent ( new CEventString ( text , this ) ) ;
if ( bestTargetElect < 1 )
{
bestTarget = XA_STRING ;
bestTargetElect = 1 ;
}
}
else
{
nlwarning ( " Unknow target %u " , ( uint ) target ) ;
}
}
if ( supportedTargets [ i ] = = XA_UTF8_STRING )
break ;
{
if ( bestTargetElect < 2 )
{
bestTarget = XA_UTF8_STRING ;
bestTargetElect = 2 ;
}
}
case FocusIn :
// keyboard focus
server - > postEvent ( new CEventSetFocus ( true , this ) ) ;
if ( _ic ) XSetICFocus ( _ic ) ;
break ;
case FocusOut :
// keyboard focus
server - > postEvent ( new CEventSetFocus ( false , this ) ) ;
if ( _ic ) XUnsetICFocus ( _ic ) ;
break ;
case KeymapNotify :
break ;
case MappingNotify :
// update keymap
XRefreshKeyboardMapping ( ( XMappingEvent * ) & event ) ;
break ;
case DestroyNotify :
// XIM server has crashed
createIM ( ) ;
break ;
case ClientMessage :
if ( ( xevent . xclient . format = = 32 ) & & ( xevent . xclient . data . l [ 0 ] = = videodata - > WM_DELETE_WINDOW ) )
{
server - > postEvent ( new CEventDestroyWindow ( this ) ) ;
}
}
break ;
default :
// nlinfo("UnknownEvent");
// XtDispatchEvent(&event);
return false ;
}
}
XFree ( supportedTargets ) ;
return true ;
}
if ( ! bestTargetElect )
bool CUnixEventEmitter : : copyTextToClipboard ( const ucstring & tex t)
{
{
nlwarning ( " Paste buffer is not a text buffer. " ) ;
_CopiedString = text ;
return false ;
}
// Ask for selection lenght && copy to buffer
// NeL window is the owner of clipboard
bres = prepareSelectionContent ( XA_CLIPBOARD , bestTarget , XA_NEL_SEL ) ;
XSetSelectionOwner ( _dpy , XA_CLIPBOARD , _win , CurrentTime ) ;
if ( ! bres )
// check we are owning the clipboard
if ( XGetSelectionOwner ( _dpy , XA_CLIPBOARD ) ! = _win )
{
{
nlwarning ( " Paste: cannot obtain data. Aborting. " ) ;
nlwarning ( " Can't aquire selection " ) ;
return false ;
return false ;
}
}
XGetWindowProperty ( _dpy , _win , XA_NEL_SEL , 0 , XMaxRequestSize ( _dpy ) , False , AnyPropertyType , & actualType , & actualFormat , & nitems , & bytesLeft , ( unsigned char * * ) & data ) ;
_SelectionOwned = true ;
std : : string tmpData = ( const char * ) data ;
XFree ( data ) ;
switch ( bestTargetElect )
{
case 1 : // XA_STRING
text = tmpData ;
return true ;
return true ;
}
case 2 : // XA_UTF8_STRING
bool CUnixEventEmitter : : pasteTextFromClipboard ( ucstring & text )
text = ucstring : : makeFromUtf8 ( tmpData ) ;
{
// check if we own the selection
if ( _SelectionOwned )
{
text = _CopiedString ;
return true ;
return true ;
default :
break ;
}
}
nlwarning ( " Paste: buffer is not a text buffer. " ) ;
// check if there is a data in clipboard
}
if ( XGetSelectionOwner ( _dpy , XA_CLIPBOARD ) = = None )
return false ;
nlwarning ( " Paste: error ! " ) ;
// request supported methods
XConvertSelection ( _dpy , XA_CLIPBOARD , XA_TARGETS , XA_NEL_SEL , _win , CurrentTime ) ;
// don't return result now
return false ;
return false ;
}
}
} // NLMISC
} // NLMISC
# endif // defined(NL_OS_UNIX) && !defined(NL_OS_MAC)
# endif // defined(NL_OS_UNIX) && !defined(NL_OS_MAC)