• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

kmanagerselection.cpp

Go to the documentation of this file.
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

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal