00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #ifdef HAVE_CONFIG_H
00028 #include "config.h"
00029 #endif
00030
00031 #ifdef HAVE_SYS_TYPES_H
00032 #include <sys/types.h>
00033 #endif
00034
00035 #ifdef HAVE_SYS_TIME_H
00036 #include <sys/time.h>
00037 #endif
00038
00039 #ifdef HAVE_UNISTD_H
00040 #include <unistd.h>
00041 #endif
00042
00043 #include <qobject.h>
00044 #ifdef Q_WS_X11 // FIXME(E)
00045
00046 #include "kmanagerselection.h"
00047
00048 #include <kdebug.h>
00049 #include <qwidget.h>
00050 #include <kapplication.h>
00051 #include <kxerrorhandler.h>
00052 #include <X11/Xatom.h>
00053
00054 class KSelectionOwnerPrivate
00055 : public QWidget
00056 {
00057 public:
00058 KSelectionOwnerPrivate( KSelectionOwner* owner );
00059 protected:
00060 virtual bool x11Event( XEvent* ev );
00061 private:
00062 KSelectionOwner* owner;
00063 };
00064
00065 KSelectionOwnerPrivate::KSelectionOwnerPrivate( KSelectionOwner* owner_P )
00066 : owner( owner_P )
00067 {
00068 kapp->installX11EventFilter( this );
00069 }
00070
00071 bool KSelectionOwnerPrivate::x11Event( XEvent* ev_P )
00072 {
00073 return owner->filterEvent( ev_P );
00074 }
00075
00076 KSelectionOwner::KSelectionOwner( Atom selection_P, int screen_P, QObject* parent_P )
00077 : QObject( parent_P ),
00078 selection( selection_P ),
00079 screen( screen_P >= 0 ? screen_P : DefaultScreen( qt_xdisplay())),
00080 window( None ),
00081 timestamp( CurrentTime ),
00082 extra1( 0 ), extra2( 0 ),
00083 d( new KSelectionOwnerPrivate( this ))
00084 {
00085 }
00086
00087 KSelectionOwner::KSelectionOwner( const char* selection_P, int screen_P, QObject* parent_P )
00088 : QObject( parent_P ),
00089 selection( XInternAtom( qt_xdisplay(), selection_P, False )),
00090 screen( screen_P >= 0 ? screen_P : DefaultScreen( qt_xdisplay())),
00091 window( None ),
00092 timestamp( CurrentTime ),
00093 extra1( 0 ), extra2( 0 ),
00094 d( new KSelectionOwnerPrivate( this ))
00095 {
00096 }
00097
00098 KSelectionOwner::~KSelectionOwner()
00099 {
00100 release();
00101 delete d;
00102 }
00103
00104 bool KSelectionOwner::claim( bool force_P, bool force_kill_P )
00105 {
00106 if( manager_atom == None )
00107 getAtoms();
00108 if( timestamp != CurrentTime )
00109 release();
00110 Display* const dpy = qt_xdisplay();
00111 Window prev_owner = XGetSelectionOwner( dpy, selection );
00112 if( prev_owner != None )
00113 {
00114 if( !force_P )
00115 {
00116
00117 return false;
00118 }
00119 XSelectInput( dpy, prev_owner, StructureNotifyMask );
00120 }
00121 XSetWindowAttributes attrs;
00122 attrs.override_redirect = True;
00123 window = XCreateWindow( dpy, RootWindow( dpy, screen ), 0, 0, 1, 1,
00124 0, CopyFromParent, InputOnly, CopyFromParent, CWOverrideRedirect, &attrs );
00125
00126 Atom tmp = XA_ATOM;
00127 XSelectInput( dpy, window, PropertyChangeMask );
00128 XChangeProperty( dpy, window, XA_ATOM, XA_ATOM, 32, PropModeReplace,
00129 reinterpret_cast< unsigned char* >( &tmp ), 1 );
00130 XEvent ev;
00131 XSync( dpy, False );
00132 XCheckTypedWindowEvent( dpy, window, PropertyNotify, &ev );
00133 timestamp = ev.xproperty.time;
00134 XSelectInput( dpy, window, StructureNotifyMask );
00135 XSetSelectionOwner( dpy, selection, window, timestamp );
00136 Window new_owner = XGetSelectionOwner( dpy, selection );
00137 if( new_owner != window )
00138 {
00139
00140 XDestroyWindow( dpy, window );
00141 timestamp = CurrentTime;
00142 return false;
00143 }
00144 if( prev_owner != None )
00145 {
00146
00147 for( int cnt = 0;
00148 ;
00149 ++cnt )
00150 {
00151 if( XCheckTypedWindowEvent( dpy, prev_owner, DestroyNotify, &ev ) == True )
00152 break;
00153 struct timeval tm = { 0, 50000 };
00154 select( 0, NULL, NULL, NULL, &tm );
00155 if( cnt == 19 )
00156 {
00157 if( force_kill_P )
00158 {
00159
00160 XKillClient( dpy, prev_owner );
00161 }
00162 break;
00163 }
00164 }
00165 }
00166 ev.type = ClientMessage;
00167 ev.xclient.window = RootWindow( dpy, screen );
00168 ev.xclient.display = dpy;
00169 ev.xclient.message_type = manager_atom;
00170 ev.xclient.format = 32;
00171 ev.xclient.data.l[ 0 ] = timestamp;
00172 ev.xclient.data.l[ 1 ] = selection;
00173 ev.xclient.data.l[ 2 ] = window;
00174 ev.xclient.data.l[ 3 ] = extra1;
00175 ev.xclient.data.l[ 4 ] = extra2;
00176 XSendEvent( dpy, RootWindow( dpy, screen ), False, StructureNotifyMask, &ev );
00177
00178 return true;
00179 }
00180
00181
00182 void KSelectionOwner::release()
00183 {
00184 if( timestamp == CurrentTime )
00185 return;
00186 XDestroyWindow( qt_xdisplay(), window );
00187
00188 timestamp = CurrentTime;
00189 }
00190
00191 Window KSelectionOwner::ownerWindow() const
00192 {
00193 if( timestamp == CurrentTime )
00194 return None;
00195 return window;
00196 }
00197
00198 void KSelectionOwner::setData( long extra1_P, long extra2_P )
00199 {
00200 extra1 = extra1_P;
00201 extra2 = extra2_P;
00202 }
00203
00204 bool KSelectionOwner::filterEvent( XEvent* ev_P )
00205 {
00206 if( timestamp != CurrentTime && ev_P->xany.window == window )
00207 {
00208 if( handleMessage( ev_P ))
00209 return true;
00210 }
00211 switch( ev_P->type )
00212 {
00213 case SelectionClear:
00214 {
00215 if( timestamp == CurrentTime || ev_P->xselectionclear.selection != selection )
00216 return false;
00217 timestamp = CurrentTime;
00218
00219 emit lostOwnership();
00220 XSelectInput( qt_xdisplay(), window, 0 );
00221 XDestroyWindow( qt_xdisplay(), window );
00222 return false;
00223 }
00224 case DestroyNotify:
00225 {
00226 if( timestamp == CurrentTime || ev_P->xdestroywindow.window != window )
00227 return false;
00228 timestamp = CurrentTime;
00229
00230 emit lostOwnership();
00231 return false;
00232 }
00233 case SelectionNotify:
00234 {
00235 if( timestamp == CurrentTime || ev_P->xselection.selection != selection )
00236 return false;
00237
00238 return false;
00239 }
00240 case SelectionRequest:
00241 filter_selection_request( ev_P->xselectionrequest );
00242 return false;
00243 }
00244 return false;
00245 }
00246
00247 bool KSelectionOwner::handleMessage( XEvent* )
00248 {
00249 return false;
00250 }
00251
00252 void KSelectionOwner::filter_selection_request( XSelectionRequestEvent& ev_P )
00253 {
00254 if( timestamp == CurrentTime || ev_P.selection != selection )
00255 return;
00256 if( ev_P.time != CurrentTime
00257 && ev_P.time - timestamp > 1U << 31 )
00258 return;
00259
00260 bool handled = false;
00261 if( ev_P.target == xa_multiple )
00262 {
00263 if( ev_P.property != None )
00264 {
00265 const int MAX_ATOMS = 100;
00266 int format;
00267 Atom type;
00268 unsigned long items;
00269 unsigned long after;
00270 unsigned char* data;
00271 if( XGetWindowProperty( qt_xdisplay(), ev_P.requestor, ev_P.property, 0,
00272 MAX_ATOMS, False, AnyPropertyType, &type, &format, &items, &after,
00273 &data ) == Success && format == 32 && items % 2 == 0 )
00274 {
00275 bool handled_array[ MAX_ATOMS ];
00276 Atom* atoms = reinterpret_cast< Atom* >( data );
00277 for( unsigned int i = 0;
00278 i < items / 2;
00279 ++i )
00280 handled_array[ i ] = handle_selection(
00281 atoms[ i * 2 ], atoms[ i * 2 + 1 ], ev_P.requestor );
00282 bool all_handled = true;
00283 for( unsigned int i = 0;
00284 i < items / 2;
00285 ++i )
00286 if( !handled_array[ i ] )
00287 {
00288 all_handled = false;
00289 atoms[ i * 2 + 1 ] = None;
00290 }
00291 if( !all_handled )
00292 XChangeProperty( qt_xdisplay(), ev_P.requestor, ev_P.property, XA_ATOM,
00293 32, PropModeReplace, reinterpret_cast< unsigned char* >( atoms ), items );
00294 handled = true;
00295 XFree( data );
00296 }
00297 }
00298 }
00299 else
00300 {
00301 if( ev_P.property == None )
00302 ev_P.property = ev_P.target;
00303 handled = handle_selection( ev_P.target, ev_P.property, ev_P.requestor );
00304 }
00305 XEvent ev;
00306 ev.xselection.type = SelectionNotify;
00307 ev.xselection.display = qt_xdisplay();
00308 ev.xselection.requestor = ev_P.requestor;
00309 ev.xselection.target = ev_P.target;
00310 ev.xselection.property = handled ? ev_P.property : None;
00311 XSendEvent( qt_xdisplay(), ev_P.requestor, False, 0, &ev );
00312 }
00313
00314 bool KSelectionOwner::handle_selection( Atom target_P, Atom property_P, Window requestor_P )
00315 {
00316 if( target_P == xa_timestamp )
00317 {
00318
00319 XChangeProperty( qt_xdisplay(), requestor_P, property_P, XA_INTEGER, 32,
00320 PropModeReplace, reinterpret_cast< unsigned char* >( ×tamp ), 1 );
00321 }
00322 else if( target_P == xa_targets )
00323 replyTargets( property_P, requestor_P );
00324 else if( genericReply( target_P, property_P, requestor_P ))
00325 ;
00326 else
00327 return false;
00328 return true;
00329 }
00330
00331 void KSelectionOwner::replyTargets( Atom property_P, Window requestor_P )
00332 {
00333 Atom atoms[ 3 ] = { xa_multiple, xa_timestamp, xa_targets };
00334
00335 XChangeProperty( qt_xdisplay(), requestor_P, property_P, XA_ATOM, 32, PropModeReplace,
00336 reinterpret_cast< unsigned char* >( atoms ), 3 );
00337 }
00338
00339 bool KSelectionOwner::genericReply( Atom, Atom, Window )
00340 {
00341 return false;
00342 }
00343
00344 void KSelectionOwner::getAtoms()
00345 {
00346 if( manager_atom == None )
00347 {
00348 Atom atoms[ 4 ];
00349 const char* const names[] =
00350 { "MANAGER", "MULTIPLE", "TARGETS", "TIMESTAMP" };
00351 XInternAtoms( qt_xdisplay(), const_cast< char** >( names ), 4, False, atoms );
00352 manager_atom = atoms[ 0 ];
00353 xa_multiple = atoms[ 1];
00354 xa_targets = atoms[ 2 ];
00355 xa_timestamp = atoms[ 3 ];
00356 }
00357 }
00358
00359 Atom KSelectionOwner::manager_atom = None;
00360 Atom KSelectionOwner::xa_multiple = None;
00361 Atom KSelectionOwner::xa_targets = None;
00362 Atom KSelectionOwner::xa_timestamp = None;
00363
00364
00365
00366
00367
00368
00369 class KSelectionWatcherPrivate
00370 : public QWidget
00371 {
00372 public:
00373 KSelectionWatcherPrivate( KSelectionWatcher* watcher );
00374 protected:
00375 virtual bool x11Event( XEvent* ev );
00376 private:
00377 KSelectionWatcher* watcher;
00378 };
00379
00380 KSelectionWatcherPrivate::KSelectionWatcherPrivate( KSelectionWatcher* watcher_P )
00381 : watcher( watcher_P )
00382 {
00383 kapp->installX11EventFilter( this );
00384 }
00385
00386 bool KSelectionWatcherPrivate::x11Event( XEvent* ev_P )
00387 {
00388 watcher->filterEvent( ev_P );
00389 return false;
00390 }
00391
00392
00393 KSelectionWatcher::KSelectionWatcher( Atom selection_P, int screen_P, QObject* parent_P )
00394 : QObject( parent_P ),
00395 selection( selection_P ),
00396 screen( screen_P >= 0 ? screen_P : DefaultScreen( qt_xdisplay())),
00397 selection_owner( None ),
00398 d( new KSelectionWatcherPrivate( this ))
00399 {
00400 init();
00401 }
00402
00403 KSelectionWatcher::KSelectionWatcher( const char* selection_P, int screen_P, QObject* parent_P )
00404 : QObject( parent_P ),
00405 selection( XInternAtom( qt_xdisplay(), selection_P, False )),
00406 screen( screen_P >= 0 ? screen_P : DefaultScreen( qt_xdisplay())),
00407 selection_owner( None ),
00408 d( new KSelectionWatcherPrivate( this ))
00409 {
00410 init();
00411 }
00412
00413 KSelectionWatcher::~KSelectionWatcher()
00414 {
00415 delete d;
00416 }
00417
00418 void KSelectionWatcher::init()
00419 {
00420 if( manager_atom == None )
00421 {
00422 Display* const dpy = qt_xdisplay();
00423 manager_atom = XInternAtom( dpy, "MANAGER", False );
00424 XWindowAttributes attrs;
00425 XGetWindowAttributes( dpy, RootWindow( dpy, screen ), &attrs );
00426 long event_mask = attrs.your_event_mask;
00427
00428 XSelectInput( dpy, RootWindow( dpy, screen ), event_mask | StructureNotifyMask );
00429 }
00430 }
00431
00432 Window KSelectionWatcher::owner()
00433 {
00434 Display* const dpy = qt_xdisplay();
00435 KXErrorHandler handler;
00436 Window current_owner = XGetSelectionOwner( dpy, selection );
00437 if( current_owner == None )
00438 return None;
00439 if( current_owner == selection_owner )
00440 return selection_owner;
00441 XSelectInput( dpy, current_owner, StructureNotifyMask );
00442 if( !handler.error( true ) && current_owner == XGetSelectionOwner( dpy, selection ))
00443 {
00444
00445 selection_owner = current_owner;
00446 emit newOwner( selection_owner );
00447 }
00448 else
00449 selection_owner = None;
00450 return selection_owner;
00451 }
00452
00453
00454 void KSelectionWatcher::filterEvent( XEvent* ev_P )
00455 {
00456 if( ev_P->type == ClientMessage )
00457 {
00458
00459 if( ev_P->xclient.message_type != manager_atom
00460 || ev_P->xclient.data.l[ 1 ] != static_cast< long >( selection ))
00461 return;
00462
00463 if( static_cast< long >( owner()) == ev_P->xclient.data.l[ 2 ] )
00464 {
00465
00466 }
00467 return;
00468 }
00469 if( ev_P->type == DestroyNotify )
00470 {
00471 if( selection_owner == None || ev_P->xdestroywindow.window != selection_owner )
00472 return;
00473 selection_owner = None;
00474 if( owner() == None )
00475 emit lostOwner();
00476 return;
00477 }
00478 return;
00479 }
00480
00481 Atom KSelectionWatcher::manager_atom = None;
00482
00483 void KSelectionOwner::virtual_hook( int, void* )
00484 { }
00485
00486 void KSelectionWatcher::virtual_hook( int, void* )
00487 { }
00488
00489 #include "kmanagerselection.moc"
00490 #endif