kdecore Library: kmanagerselection.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# kmanagerselection.cpp

    00001 /****************************************************************************
    00002
    00003  $Id: kmanagerselection.cpp 282061 2004-01-23 16:22:46Z lunakl $
    00004
    00005  Copyright (C) 2003 Lubos Lunak        <l.lunak@kde.org>
    00006
    00007 Permission is hereby granted, free of charge, to any person obtaining a
    00008 copy of this software and associated documentation files (the "Software"),
    00009 to deal in the Software without restriction, including without limitation
    00010 the rights to use, copy, modify, merge, publish, distribute, sublicense,
    00011 and/or sell copies of the Software, and to permit persons to whom the
    00012 Software is furnished to do so, subject to the following conditions:
    00013
    00014 The above copyright notice and this permission notice shall be included in
    00015 all copies or substantial portions of the Software.
    00016
    00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
    00020 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    00022 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    00023 DEALINGS IN THE SOFTWARE.
    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 //            kdDebug() << "Selection already owned, failing" << endl;
    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 //    kdDebug() << "Using owner window " << window << endl;
    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 ); // get a timestamp
    00133     timestamp = ev.xproperty.time;
    00134     XSelectInput( dpy, window, StructureNotifyMask ); // for DestroyNotify
    00135     XSetSelectionOwner( dpy, selection, window, timestamp );
    00136     Window new_owner = XGetSelectionOwner( dpy, selection );
    00137     if( new_owner != window )
    00138         {
    00139 //        kdDebug() << "Failed to claim selection : " << new_owner << endl;
    00140         XDestroyWindow( dpy, window );
    00141         timestamp = CurrentTime;
    00142         return false;
    00143         }
    00144     if( prev_owner != None )
    00145         {
    00146 //        kdDebug() << "Waiting for previous owner to disown" << endl;
    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 }; // 50 ms
    00154             select( 0, NULL, NULL, NULL, &tm );
    00155             if( cnt == 19 )
    00156                 {
    00157                 if( force_kill_P )
    00158                     {
    00159 //                    kdDebug() << "Killing previous owner" << endl;
    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 //    kdDebug() << "Claimed selection" << endl;
    00178     return true;
    00179     }
    00180
    00181 // destroy resource first
    00182 void KSelectionOwner::release()
    00183     {
    00184     if( timestamp == CurrentTime )
    00185         return;
    00186     XDestroyWindow( qt_xdisplay(), window ); // also makes the selection not owned
    00187 //    kdDebug() << "Releasing selection" << endl;
    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 //      kdDebug() << "Lost selection" << endl;
    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 //      kdDebug() << "Lost selection (destroyed)" << endl;
    00230         emit lostOwnership();
    00231       return false;
    00232         }
    00233     case SelectionNotify:
    00234         {
    00235         if( timestamp == CurrentTime || ev_P->xselection.selection != selection )
    00236             return false;
    00237         // ignore?
    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; // too old or too new request
    00259 //    kdDebug() << "Got selection request" << endl;
    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; // no need to handle more?
    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 ) // obsolete client
    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 //        kdDebug() << "Handling timestamp request" << endl;
    00319         XChangeProperty( qt_xdisplay(), requestor_P, property_P, XA_INTEGER, 32,
    00320             PropModeReplace, reinterpret_cast< unsigned char* >( &timestamp ), 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         ; // handled
    00326     else
    00327         return false; // unknown
    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 //    kdDebug() << "Handling targets request" << endl;
    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 // KSelectionWatcher
    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         // StructureNotifyMask on the root window is needed
    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 //        kdDebug() << "isOwner: " << current_owner << endl;
    00445         selection_owner = current_owner;
    00446         emit newOwner( selection_owner );
    00447         }
    00448     else
    00449         selection_owner = None;
    00450     return selection_owner;
    00451     }
    00452
    00453 // void return value in order to allow more watchers in one process
    00454 void KSelectionWatcher::filterEvent( XEvent* ev_P )
    00455     {
    00456     if( ev_P->type == ClientMessage )
    00457         {
    00458 //        kdDebug() << "got ClientMessage" << endl;
    00459         if( ev_P->xclient.message_type != manager_atom
    00460             || ev_P->xclient.data.l[ 1 ] != static_cast< long >( selection ))
    00461             return;
    00462 //        kdDebug() << "handling message" << endl;
    00463         if( static_cast< long >( owner()) == ev_P->xclient.data.l[ 2 ] )
    00464             {
    00465             // owner() emits newOwner() if needed, no need to do it twice
    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; // in case the exactly same ID gets reused as the owner
    00474         if( owner() == None )
    00475             emit lostOwner(); // it must be safe to delete 'this' in a slot
    00476         return;
    00477         }
    00478     return;
    00479     }
    00480
    00481 Atom KSelectionWatcher::manager_atom = None;
    00482
    00483 void KSelectionOwner::virtual_hook( int, void* )
    00484 { /*BASE::virtual_hook( id, data );*/ }
    00485
    00486 void KSelectionWatcher::virtual_hook( int, void* )
    00487 { /*BASE::virtual_hook( id, data );*/ }
    00488
    00489 #include "kmanagerselection.moc"
    00490 #endif

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:09 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003