kdecore Library API Documentation

kmanagerselection.cpp

00001 /**************************************************************************** 00002 00003 $Id: kmanagerselection.cpp,v 1.12.2.1 2004/01/27 09:29:42 lunakl Exp $ 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
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 20 09:48:26 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003