29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
33 #ifdef HAVE_SYS_TIME_H
41 #include <QtCore/QObject>
42 #ifdef Q_WS_X11 // FIXME(E)
44 #include <qx11info_x11.h>
49 #include <X11/Xatom.h>
52 class KSelectionOwner::Private :
public QWidget
56 : selection( selection_P ),
57 screen( screen_P >= 0 ? screen_P : DefaultScreen( QX11Info::display() ) ),
59 timestamp( CurrentTime ),
64 kapp->installX11EventFilter(
this );
72 static Atom manager_atom;
73 static Atom xa_multiple;
74 static Atom xa_targets;
75 static Atom xa_timestamp;
78 virtual bool x11Event( XEvent* ev_P )
80 return owner->filterEvent( ev_P );
90 d( new Private( this, selection_P, screen_P ) )
96 d( new Private( this, XInternAtom( QX11Info::display(), selection_P, False ), screen_P ) )
108 if( Private::manager_atom ==
None )
110 if( d->timestamp != CurrentTime )
112 Display*
const dpy = QX11Info::display();
113 Window prev_owner = XGetSelectionOwner( dpy, d->selection );
114 if( prev_owner !=
None )
121 XSelectInput( dpy, prev_owner, StructureNotifyMask );
123 XSetWindowAttributes attrs;
124 attrs.override_redirect = True;
125 d->window = XCreateWindow( dpy, RootWindow( dpy, d->screen ), 0, 0, 1, 1,
126 0, CopyFromParent, InputOnly, CopyFromParent, CWOverrideRedirect, &attrs );
129 XSelectInput( dpy, d->window, PropertyChangeMask );
130 XChangeProperty( dpy, d->window, XA_ATOM, XA_ATOM, 32, PropModeReplace,
131 reinterpret_cast< unsigned char*
>( &tmp ), 1 );
134 XCheckTypedWindowEvent( dpy, d->window, PropertyNotify, &ev );
135 d->timestamp = ev.xproperty.time;
136 XSelectInput( dpy, d->window, StructureNotifyMask );
137 XSetSelectionOwner( dpy, d->selection, d->window, d->timestamp );
138 Window new_owner = XGetSelectionOwner( dpy, d->selection );
139 if( new_owner != d->window )
142 XDestroyWindow( dpy, d->window );
143 d->timestamp = CurrentTime;
146 if( prev_owner !=
None )
153 if( XCheckTypedWindowEvent( dpy, prev_owner, DestroyNotify, &ev ) == True )
155 struct timeval tm = { 0, 50000 };
156 select( 0, NULL, NULL, NULL, &tm );
163 XKillClient( dpy, prev_owner );
170 ev.type = ClientMessage;
171 ev.xclient.window = RootWindow( dpy, d->screen );
172 ev.xclient.display = dpy;
173 ev.xclient.message_type = Private::manager_atom;
174 ev.xclient.format = 32;
175 ev.xclient.data.l[ 0 ] = d->timestamp;
176 ev.xclient.data.l[ 1 ] = d->selection;
177 ev.xclient.data.l[ 2 ] = d->window;
178 ev.xclient.data.l[ 3 ] = d->extra1;
179 ev.xclient.data.l[ 4 ] = d->extra2;
180 XSendEvent( dpy, RootWindow( dpy, d->screen ), False, StructureNotifyMask, &ev );
188 if( d->timestamp == CurrentTime )
190 XDestroyWindow( QX11Info::display(), d->window );
192 d->timestamp = CurrentTime;
197 if( d->timestamp == CurrentTime )
204 d->extra1 = extra1_P;
205 d->extra2 = extra2_P;
210 if( d->timestamp != CurrentTime && ev_P->xany.window == d->window )
219 if( d->timestamp == CurrentTime || ev_P->xselectionclear.selection != d->selection )
221 d->timestamp = CurrentTime;
223 Window window = d->window;
225 XSelectInput( QX11Info::display(), window, 0 );
226 XDestroyWindow( QX11Info::display(), window );
231 if( d->timestamp == CurrentTime || ev_P->xdestroywindow.window != d->window )
233 d->timestamp = CurrentTime;
238 case SelectionNotify:
240 if( d->timestamp == CurrentTime || ev_P->xselection.selection != d->selection )
245 case SelectionRequest:
246 filter_selection_request( ev_P->xselectionrequest );
257 void KSelectionOwner::filter_selection_request( XSelectionRequestEvent& ev_P )
259 if( d->timestamp == CurrentTime || ev_P.selection != d->selection )
261 if( ev_P.time != CurrentTime
262 && ev_P.time - d->timestamp > 1U << 31 )
265 bool handled =
false;
266 if( ev_P.target == Private::xa_multiple )
268 if( ev_P.property != None )
270 const int MAX_ATOMS = 100;
276 if( XGetWindowProperty( QX11Info::display(), ev_P.requestor, ev_P.property, 0,
277 MAX_ATOMS, False, AnyPropertyType, &type, &format, &items, &after,
278 &data ) == Success && format == 32 && items % 2 == 0 )
280 bool handled_array[ MAX_ATOMS ];
281 Atom* atoms =
reinterpret_cast< Atom*
>( data );
282 for(
unsigned int i = 0;
285 handled_array[ i ] = handle_selection(
286 atoms[ i * 2 ], atoms[ i * 2 + 1 ], ev_P.requestor );
287 bool all_handled =
true;
288 for(
unsigned int i = 0;
291 if( !handled_array[ i ] )
294 atoms[ i * 2 + 1 ] =
None;
297 XChangeProperty( QX11Info::display(), ev_P.requestor, ev_P.property, XA_ATOM,
298 32, PropModeReplace,
reinterpret_cast< unsigned char*
>( atoms ), items );
306 if( ev_P.property == None )
307 ev_P.property = ev_P.target;
308 handled = handle_selection( ev_P.target, ev_P.property, ev_P.requestor );
311 ev.xselection.selection = ev_P.selection;
312 ev.xselection.type = SelectionNotify;
313 ev.xselection.display = QX11Info::display();
314 ev.xselection.requestor = ev_P.requestor;
315 ev.xselection.target = ev_P.target;
316 ev.xselection.property = handled ? ev_P.property :
None;
317 XSendEvent( QX11Info::display(), ev_P.requestor, False, 0, &ev );
320 bool KSelectionOwner::handle_selection(
Atom target_P,
Atom property_P, Window requestor_P )
322 if( target_P == Private::xa_timestamp )
325 XChangeProperty( QX11Info::display(), requestor_P, property_P, XA_INTEGER, 32,
326 PropModeReplace,
reinterpret_cast< unsigned char*
>( &d->timestamp ), 1 );
328 else if( target_P == Private::xa_targets )
330 else if(
genericReply( target_P, property_P, requestor_P ))
339 Atom atoms[ 3 ] = { Private::xa_multiple, Private::xa_timestamp, Private::xa_targets };
341 XChangeProperty( QX11Info::display(), requestor_P, property_P, XA_ATOM, 32, PropModeReplace,
342 reinterpret_cast< unsigned char*
>( atoms ), 3 );
352 if( Private::manager_atom ==
None )
355 const char*
const names[] =
356 {
"MANAGER",
"MULTIPLE",
"TARGETS",
"TIMESTAMP" };
357 XInternAtoms( QX11Info::display(),
const_cast< char**
>( names ), 4, False, atoms );
358 Private::manager_atom = atoms[ 0 ];
359 Private::xa_multiple = atoms[ 1];
360 Private::xa_targets = atoms[ 2 ];
361 Private::xa_timestamp = atoms[ 3 ];
365 Atom KSelectionOwner::Private::manager_atom =
None;
366 Atom KSelectionOwner::Private::xa_multiple =
None;
367 Atom KSelectionOwner::Private::xa_targets =
None;
368 Atom KSelectionOwner::Private::xa_timestamp =
None;
375 class KSelectionWatcher::Private :
public QWidget
379 : selection( selection_P ),
380 screen( screen_P >= 0 ? screen_P : DefaultScreen( QX11Info::display())),
381 selection_owner(
None ),
384 kapp->installX11EventFilter(
this );
387 const Atom selection;
390 static Atom manager_atom;
393 virtual bool x11Event( XEvent* ev_P )
395 watcher->filterEvent( ev_P );
405 d( new Private( this, selection_P, screen_P ))
412 d( new Private( this, XInternAtom( QX11Info::display(), selection_P, False ), screen_P ))
422 void KSelectionWatcher::init()
424 if( Private::manager_atom == None )
426 Display*
const dpy = QX11Info::display();
427 Private::manager_atom = XInternAtom( dpy,
"MANAGER", False );
428 XWindowAttributes attrs;
429 XGetWindowAttributes( dpy, RootWindow( dpy, d->screen ), &attrs );
430 long event_mask = attrs.your_event_mask;
432 XSelectInput( dpy, RootWindow( dpy, d->screen ), event_mask | StructureNotifyMask );
439 Display*
const dpy = QX11Info::display();
441 Window current_owner = XGetSelectionOwner( dpy, d->selection );
442 if( current_owner ==
None )
444 if( current_owner == d->selection_owner )
445 return d->selection_owner;
446 XSelectInput( dpy, current_owner, StructureNotifyMask );
447 if( !handler.
error(
true ) && current_owner == XGetSelectionOwner( dpy, d->selection ))
450 d->selection_owner = current_owner;
451 emit
newOwner( d->selection_owner );
454 d->selection_owner =
None;
455 return d->selection_owner;
461 if( ev_P->type == ClientMessage )
464 if( ev_P->xclient.message_type != Private::manager_atom
465 || ev_P->xclient.data.l[ 1 ] !=
static_cast< long >( d->selection ))
468 if(
static_cast< long >(
owner()) == ev_P->xclient.data.l[ 2 ] )
474 if( ev_P->type == DestroyNotify )
476 if( d->selection_owner ==
None || ev_P->xdestroywindow.window != d->selection_owner )
478 d->selection_owner =
None;
486 Atom KSelectionWatcher::Private::manager_atom =
None;
488 #include "kmanagerselection.moc"