• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

  • tdecore
kmanagerselection.cpp
1/****************************************************************************
2
3 $Id$
4
5 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
6
7Permission is hereby granted, free of charge, to any person obtaining a
8copy of this software and associated documentation files (the "Software"),
9to deal in the Software without restriction, including without limitation
10the rights to use, copy, modify, merge, publish, distribute, sublicense,
11and/or sell copies of the Software, and to permit persons to whom the
12Software is furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in
15all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23DEALINGS IN THE SOFTWARE.
24
25****************************************************************************/
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#ifdef HAVE_SYS_TYPES_H
32#include <sys/types.h>
33#endif
34
35#ifdef HAVE_SYS_TIME_H
36#include <sys/time.h>
37#endif
38
39#ifdef HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42
43#include <tqobject.h>
44#ifdef TQ_WS_X11 // FIXME(E)
45
46#include "kmanagerselection.h"
47
48#include <kdebug.h>
49#include <tqwidget.h>
50#include <tdeapplication.h>
51#include <kxerrorhandler.h>
52#include <X11/Xatom.h>
53
54class TDESelectionOwnerPrivate
55 : public TQWidget
56 {
57 public:
58 TDESelectionOwnerPrivate( TDESelectionOwner* owner );
59 protected:
60 virtual bool x11Event( XEvent* ev );
61 private:
62 TDESelectionOwner* owner;
63 };
64
65TDESelectionOwnerPrivate::TDESelectionOwnerPrivate( TDESelectionOwner* owner_P )
66 : owner( owner_P )
67 {
68 tdeApp->installX11EventFilter( this );
69 }
70
71bool TDESelectionOwnerPrivate::x11Event( XEvent* ev_P )
72 {
73 return owner->filterEvent( ev_P );
74 }
75
76TDESelectionOwner::TDESelectionOwner( Atom selection_P, int screen_P, TQObject* parent_P )
77 : TQObject( parent_P ),
78 selection( selection_P ),
79 screen( screen_P >= 0 ? screen_P : DefaultScreen( tqt_xdisplay())),
80 window( None ),
81 timestamp( CurrentTime ),
82 extra1( 0 ), extra2( 0 ),
83 d( new TDESelectionOwnerPrivate( this ))
84 {
85 }
86
87TDESelectionOwner::TDESelectionOwner( const char* selection_P, int screen_P, TQObject* parent_P )
88 : TQObject( parent_P ),
89 selection( XInternAtom( tqt_xdisplay(), selection_P, False )),
90 screen( screen_P >= 0 ? screen_P : DefaultScreen( tqt_xdisplay())),
91 window( None ),
92 timestamp( CurrentTime ),
93 extra1( 0 ), extra2( 0 ),
94 d( new TDESelectionOwnerPrivate( this ))
95 {
96 }
97
98TDESelectionOwner::~TDESelectionOwner()
99 {
100 release();
101 delete d;
102 }
103
104bool TDESelectionOwner::claim( bool force_P, bool force_kill_P )
105 {
106 if( manager_atom == None )
107 getAtoms();
108 if( timestamp != CurrentTime )
109 release();
110 Display* const dpy = tqt_xdisplay();
111 Window prev_owner = XGetSelectionOwner( dpy, selection );
112 if( prev_owner != None )
113 {
114 if( !force_P )
115 {
116// kdDebug() << "Selection already owned, failing" << endl;
117 return false;
118 }
119 XSelectInput( dpy, prev_owner, StructureNotifyMask );
120 }
121 XSetWindowAttributes attrs;
122 attrs.override_redirect = True;
123 window = XCreateWindow( dpy, RootWindow( dpy, screen ), 0, 0, 1, 1,
124 0, CopyFromParent, InputOnly, CopyFromParent, CWOverrideRedirect, &attrs );
125// kdDebug() << "Using owner window " << window << endl;
126 Atom tmp = XA_ATOM;
127 XSelectInput( dpy, window, PropertyChangeMask );
128 XChangeProperty( dpy, window, XA_ATOM, XA_ATOM, 32, PropModeReplace,
129 reinterpret_cast< unsigned char* >( &tmp ), 1 );
130 XEvent ev;
131 XSync( dpy, False );
132 XCheckTypedWindowEvent( dpy, window, PropertyNotify, &ev ); // get a timestamp
133 timestamp = ev.xproperty.time;
134 XSelectInput( dpy, window, StructureNotifyMask ); // for DestroyNotify
135 XSetSelectionOwner( dpy, selection, window, timestamp );
136 Window new_owner = XGetSelectionOwner( dpy, selection );
137 if( new_owner != window )
138 {
139// kdDebug() << "Failed to claim selection : " << new_owner << endl;
140 XDestroyWindow( dpy, window );
141 timestamp = CurrentTime;
142 return false;
143 }
144 if( prev_owner != None )
145 {
146// kdDebug() << "Waiting for previous owner to disown" << endl;
147 for( int cnt = 0;
148 ;
149 ++cnt )
150 {
151 if( XCheckTypedWindowEvent( dpy, prev_owner, DestroyNotify, &ev ) == True )
152 break;
153 struct timeval tm = { 0, 50000 }; // 50 ms
154 select( 0, NULL, NULL, NULL, &tm );
155 if( cnt == 19 )
156 {
157 if( force_kill_P )
158 {
159// kdDebug() << "Killing previous owner" << endl;
160 XKillClient( dpy, prev_owner );
161 }
162 break;
163 }
164 }
165 }
166 ev.type = ClientMessage;
167 ev.xclient.window = RootWindow( dpy, screen );
168 ev.xclient.display = dpy;
169 ev.xclient.message_type = manager_atom;
170 ev.xclient.format = 32;
171 ev.xclient.data.l[ 0 ] = timestamp;
172 ev.xclient.data.l[ 1 ] = selection;
173 ev.xclient.data.l[ 2 ] = window;
174 ev.xclient.data.l[ 3 ] = extra1;
175 ev.xclient.data.l[ 4 ] = extra2;
176 XSendEvent( dpy, RootWindow( dpy, screen ), False, StructureNotifyMask, &ev );
177// kdDebug() << "Claimed selection" << endl;
178 return true;
179 }
180
181// destroy resource first
182void TDESelectionOwner::release()
183 {
184 if( timestamp == CurrentTime )
185 return;
186 XDestroyWindow( tqt_xdisplay(), window ); // also makes the selection not owned
187// kdDebug() << "Releasing selection" << endl;
188 timestamp = CurrentTime;
189 }
190
191Window TDESelectionOwner::ownerWindow() const
192 {
193 if( timestamp == CurrentTime )
194 return None;
195 return window;
196 }
197
198void TDESelectionOwner::setData( long extra1_P, long extra2_P )
199 {
200 extra1 = extra1_P;
201 extra2 = extra2_P;
202 }
203
204bool TDESelectionOwner::filterEvent( XEvent* ev_P )
205 {
206 if( timestamp != CurrentTime && ev_P->xany.window == window )
207 {
208 if( handleMessage( ev_P ))
209 return true;
210 }
211 switch( ev_P->type )
212 {
213 case SelectionClear:
214 {
215 if( timestamp == CurrentTime || ev_P->xselectionclear.selection != selection )
216 return false;
217 timestamp = CurrentTime;
218// kdDebug() << "Lost selection" << endl;
219 emit lostOwnership();
220 XSelectInput( tqt_xdisplay(), window, 0 );
221 XDestroyWindow( tqt_xdisplay(), window );
222 return false;
223 }
224 case DestroyNotify:
225 {
226 if( timestamp == CurrentTime || ev_P->xdestroywindow.window != window )
227 return false;
228 timestamp = CurrentTime;
229// kdDebug() << "Lost selection (destroyed)" << endl;
230 emit lostOwnership();
231 return false;
232 }
233 case SelectionNotify:
234 {
235 if( timestamp == CurrentTime || ev_P->xselection.selection != selection )
236 return false;
237 // ignore?
238 return false;
239 }
240 case SelectionRequest:
241 filter_selection_request( ev_P->xselectionrequest );
242 return false;
243 }
244 return false;
245 }
246
247bool TDESelectionOwner::handleMessage( XEvent* )
248 {
249 return false;
250 }
251
252void TDESelectionOwner::filter_selection_request( XSelectionRequestEvent& ev_P )
253 {
254 if( timestamp == CurrentTime || ev_P.selection != selection )
255 return;
256 if( ev_P.time != CurrentTime
257 && ev_P.time - timestamp > 1U << 31 )
258 return; // too old or too new request
259// kdDebug() << "Got selection request" << endl;
260 bool handled = false;
261 if( ev_P.target == xa_multiple )
262 {
263 if( ev_P.property != None )
264 {
265 const int MAX_ATOMS = 100; // no need to handle more?
266 int format;
267 Atom type;
268 unsigned long items;
269 unsigned long after;
270 unsigned char* data;
271 if( XGetWindowProperty( tqt_xdisplay(), ev_P.requestor, ev_P.property, 0,
272 MAX_ATOMS, False, AnyPropertyType, &type, &format, &items, &after,
273 &data ) == Success && format == 32 && items % 2 == 0 )
274 {
275 bool handled_array[ MAX_ATOMS ];
276 Atom* atoms = reinterpret_cast< Atom* >( data );
277 for( unsigned int i = 0;
278 i < items / 2;
279 ++i )
280 handled_array[ i ] = handle_selection(
281 atoms[ i * 2 ], atoms[ i * 2 + 1 ], ev_P.requestor );
282 bool all_handled = true;
283 for( unsigned int i = 0;
284 i < items / 2;
285 ++i )
286 if( !handled_array[ i ] )
287 {
288 all_handled = false;
289 atoms[ i * 2 + 1 ] = None;
290 }
291 if( !all_handled )
292 XChangeProperty( tqt_xdisplay(), ev_P.requestor, ev_P.property, XA_ATOM,
293 32, PropModeReplace, reinterpret_cast< unsigned char* >( atoms ), items );
294 handled = true;
295 XFree( data );
296 }
297 }
298 }
299 else
300 {
301 if( ev_P.property == None ) // obsolete client
302 ev_P.property = ev_P.target;
303 handled = handle_selection( ev_P.target, ev_P.property, ev_P.requestor );
304 }
305 XEvent ev;
306 ev.xselection.type = SelectionNotify;
307 ev.xselection.display = tqt_xdisplay();
308 ev.xselection.requestor = ev_P.requestor;
309 ev.xselection.target = ev_P.target;
310 ev.xselection.property = handled ? ev_P.property : None;
311 XSendEvent( tqt_xdisplay(), ev_P.requestor, False, 0, &ev );
312 }
313
314bool TDESelectionOwner::handle_selection( Atom target_P, Atom property_P, Window requestor_P )
315 {
316 if( target_P == xa_timestamp )
317 {
318// kdDebug() << "Handling timestamp request" << endl;
319 XChangeProperty( tqt_xdisplay(), requestor_P, property_P, XA_INTEGER, 32,
320 PropModeReplace, reinterpret_cast< unsigned char* >( &timestamp ), 1 );
321 }
322 else if( target_P == xa_targets )
323 replyTargets( property_P, requestor_P );
324 else if( genericReply( target_P, property_P, requestor_P ))
325 ; // handled
326 else
327 return false; // unknown
328 return true;
329 }
330
331void TDESelectionOwner::replyTargets( Atom property_P, Window requestor_P )
332 {
333 Atom atoms[ 3 ] = { xa_multiple, xa_timestamp, xa_targets };
334// kdDebug() << "Handling targets request" << endl;
335 XChangeProperty( tqt_xdisplay(), requestor_P, property_P, XA_ATOM, 32, PropModeReplace,
336 reinterpret_cast< unsigned char* >( atoms ), 3 );
337 }
338
339bool TDESelectionOwner::genericReply( Atom, Atom, Window )
340 {
341 return false;
342 }
343
344void TDESelectionOwner::getAtoms()
345 {
346 if( manager_atom == None )
347 {
348 Atom atoms[ 4 ];
349 const char* const names[] =
350 { "MANAGER", "MULTIPLE", "TARGETS", "TIMESTAMP" };
351 XInternAtoms( tqt_xdisplay(), const_cast< char** >( names ), 4, False, atoms );
352 manager_atom = atoms[ 0 ];
353 xa_multiple = atoms[ 1];
354 xa_targets = atoms[ 2 ];
355 xa_timestamp = atoms[ 3 ];
356 }
357 }
358
359Atom TDESelectionOwner::manager_atom = None;
360Atom TDESelectionOwner::xa_multiple = None;
361Atom TDESelectionOwner::xa_targets = None;
362Atom TDESelectionOwner::xa_timestamp = None;
363
364//*******************************************
365// TDESelectionWatcher
366//*******************************************
367
368
369class TDESelectionWatcherPrivate
370 : public TQWidget
371 {
372 public:
373 TDESelectionWatcherPrivate( TDESelectionWatcher* watcher );
374 protected:
375 virtual bool x11Event( XEvent* ev );
376 private:
377 TDESelectionWatcher* watcher;
378 };
379
380TDESelectionWatcherPrivate::TDESelectionWatcherPrivate( TDESelectionWatcher* watcher_P )
381 : watcher( watcher_P )
382 {
383 tdeApp->installX11EventFilter( this );
384 }
385
386bool TDESelectionWatcherPrivate::x11Event( XEvent* ev_P )
387 {
388 watcher->filterEvent( ev_P );
389 return false;
390 }
391
392
393TDESelectionWatcher::TDESelectionWatcher( Atom selection_P, int screen_P, TQObject* parent_P )
394 : TQObject( parent_P ),
395 selection( selection_P ),
396 screen( screen_P >= 0 ? screen_P : DefaultScreen( tqt_xdisplay())),
397 selection_owner( None ),
398 d( new TDESelectionWatcherPrivate( this ))
399 {
400 init();
401 }
402
403TDESelectionWatcher::TDESelectionWatcher( const char* selection_P, int screen_P, TQObject* parent_P )
404 : TQObject( parent_P ),
405 selection( XInternAtom( tqt_xdisplay(), selection_P, False )),
406 screen( screen_P >= 0 ? screen_P : DefaultScreen( tqt_xdisplay())),
407 selection_owner( None ),
408 d( new TDESelectionWatcherPrivate( this ))
409 {
410 init();
411 }
412
413TDESelectionWatcher::~TDESelectionWatcher()
414 {
415 delete d;
416 }
417
418void TDESelectionWatcher::init()
419 {
420 if( manager_atom == None )
421 {
422 Display* const dpy = tqt_xdisplay();
423 manager_atom = XInternAtom( dpy, "MANAGER", False );
424 XWindowAttributes attrs;
425 XGetWindowAttributes( dpy, RootWindow( dpy, screen ), &attrs );
426 long event_mask = attrs.your_event_mask;
427 // StructureNotifyMask on the root window is needed
428 XSelectInput( dpy, RootWindow( dpy, screen ), event_mask | StructureNotifyMask );
429 }
430 }
431
432Window TDESelectionWatcher::owner()
433 {
434 Display* const dpy = tqt_xdisplay();
435 KXErrorHandler handler;
436 Window current_owner = XGetSelectionOwner( dpy, selection );
437 if( current_owner == None )
438 return None;
439 if( current_owner == selection_owner )
440 return selection_owner;
441 XSelectInput( dpy, current_owner, StructureNotifyMask );
442 if( !handler.error( true ) && current_owner == XGetSelectionOwner( dpy, selection ))
443 {
444// kdDebug() << "isOwner: " << current_owner << endl;
445 selection_owner = current_owner;
446 emit newOwner( selection_owner );
447 }
448 else
449 selection_owner = None;
450 return selection_owner;
451 }
452
453// void return value in order to allow more watchers in one process
454void TDESelectionWatcher::filterEvent( XEvent* ev_P )
455 {
456 if( ev_P->type == ClientMessage )
457 {
458// kdDebug() << "got ClientMessage" << endl;
459 if( ev_P->xclient.message_type != manager_atom
460 || ev_P->xclient.data.l[ 1 ] != static_cast< long >( selection ))
461 return;
462// kdDebug() << "handling message" << endl;
463 if( static_cast< long >( owner()) == ev_P->xclient.data.l[ 2 ] )
464 {
465 // owner() emits newOwner() if needed, no need to do it twice
466 }
467 return;
468 }
469 if( ev_P->type == DestroyNotify )
470 {
471 if( selection_owner == None || ev_P->xdestroywindow.window != selection_owner )
472 return;
473 selection_owner = None; // in case the exactly same ID gets reused as the owner
474 if( owner() == None )
475 emit lostOwner(); // it must be safe to delete 'this' in a slot
476 return;
477 }
478 return;
479 }
480
481Atom TDESelectionWatcher::manager_atom = None;
482
483void TDESelectionOwner::virtual_hook( int, void* )
484{ /*BASE::virtual_hook( id, data );*/ }
485
486void TDESelectionWatcher::virtual_hook( int, void* )
487{ /*BASE::virtual_hook( id, data );*/ }
488
489#include "kmanagerselection.moc"
490#endif
KXErrorHandler
This class simplifies handling of X errors.
Definition: kxerrorhandler.h:58
KXErrorHandler::error
bool error(bool sync) const
This function returns true if the error flag is set (i.e.

tdecore

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

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.9.4
This website is maintained by Timothy Pearson.