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"
bool error(bool sync) const
This function returns true if the error flag is set (i.e.
KSelectionOwner(Atom selection, int screen=-1, QObject *parent=NULL)
This constructor initializes the object, but doesn't perform any operation on the selection...
virtual ~KSelectionOwner()
Destructor.
virtual void replyTargets(Atom property, Window requestor)
Called to announce the supported targets, as described in the ICCCM section 2.6.
This class implements claiming and owning manager selections, as described in the ICCCM...
bool filterEvent(XEvent *ev_P)
Window owner()
Return the current owner of the manager selection, if any.
void release()
If the selection is owned, the ownership is given up.
void filterEvent(XEvent *ev_P)
void newOwner(Window owner)
This signal is emitted when the selection is successfully claimed by a new owner. ...
void lostOwnership()
This signal is emitted if the selection was owned and the ownership has been lost due to another clie...
void lostOwner()
This signal is emitted when the selection is given up, i.e.
This class implements watching manager selections, as described in the ICCCM section 2...
This class simplifies handling of X errors.
virtual bool genericReply(Atom target, Atom property, Window requestor)
Called when a SelectionRequest event is received.
KSelectionWatcher(Atom selection, int screen=-1, QObject *parent=NULL)
This constructor initializes the object, but doesn't perform any operation on the selection...
virtual void getAtoms()
Called to create atoms needed for claiming the selection and communication using the selection handli...
virtual bool handleMessage(XEvent *ev)
Called for every X event received on the window used for owning the selection.
virtual ~KSelectionWatcher()
Window ownerWindow() const
If the selection is owned, returns the window used internally for owning the selection.
bool claim(bool force, bool force_kill=true)
This function attemps to claim ownership of the manager selection, using the current X timestamp...
void setData(long extra1, long extra2)
Sets extra data to be sent in the message sent to root window after successfully claiming a selection...