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( ev_P->xclient.data.l[ 2 ] == static_cast< long >( selection_owner ))
00464             {
00465 
00466             return; 
00467             }
00468         if( static_cast< long >( owner()) == ev_P->xclient.data.l[ 2 ] )
00469             {
00470 
00471             emit newOwner( selection_owner );
00472             }
00473         return;
00474         }
00475     if( ev_P->type == DestroyNotify )
00476         {
00477         if( selection_owner == None || ev_P->xdestroywindow.window != selection_owner )
00478             return;
00479         selection_owner = None; 
00480         if( owner() == None )
00481             emit lostOwner(); 
00482         return;
00483         }
00484     return;
00485     }
00486 
00487 Atom KSelectionWatcher::manager_atom = None;
00488 
00489 void KSelectionOwner::virtual_hook( int, void* )
00490 {  }
00491 
00492 void KSelectionWatcher::virtual_hook( int, void* )
00493 {  }
00494 
00495 #include "kmanagerselection.moc"
00496 #endif