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