• 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 
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 and/or sell copies of the Software, and to permit persons to whom the
12 Software is furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 DEALINGS 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 Q_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 
54 class TDESelectionOwnerPrivate
55  : public QWidget
56  {
57  public:
58  TDESelectionOwnerPrivate( TDESelectionOwner* owner );
59  protected:
60  virtual bool x11Event( XEvent* ev );
61  private:
62  TDESelectionOwner* owner;
63  };
64 
65 TDESelectionOwnerPrivate::TDESelectionOwnerPrivate( TDESelectionOwner* owner_P )
66  : owner( owner_P )
67  {
68  kapp->installX11EventFilter( TQT_TQWIDGET(this) );
69  }
70 
71 bool TDESelectionOwnerPrivate::x11Event( XEvent* ev_P )
72  {
73  return owner->filterEvent( ev_P );
74  }
75 
76 TDESelectionOwner::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 
87 TDESelectionOwner::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 
98 TDESelectionOwner::~TDESelectionOwner()
99  {
100  release();
101  delete d;
102  }
103 
104 bool 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
182 void 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 
191 Window TDESelectionOwner::ownerWindow() const
192  {
193  if( timestamp == CurrentTime )
194  return None;
195  return window;
196  }
197 
198 void TDESelectionOwner::setData( long extra1_P, long extra2_P )
199  {
200  extra1 = extra1_P;
201  extra2 = extra2_P;
202  }
203 
204 bool 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 
247 bool TDESelectionOwner::handleMessage( XEvent* )
248  {
249  return false;
250  }
251 
252 void 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 
314 bool 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 
331 void 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 
339 bool TDESelectionOwner::genericReply( Atom, Atom, Window )
340  {
341  return false;
342  }
343 
344 void 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 
359 Atom TDESelectionOwner::manager_atom = None;
360 Atom TDESelectionOwner::xa_multiple = None;
361 Atom TDESelectionOwner::xa_targets = None;
362 Atom TDESelectionOwner::xa_timestamp = None;
363 
364 //*******************************************
365 // TDESelectionWatcher
366 //*******************************************
367 
368 
369 class TDESelectionWatcherPrivate
370  : public QWidget
371  {
372  public:
373  TDESelectionWatcherPrivate( TDESelectionWatcher* watcher );
374  protected:
375  virtual bool x11Event( XEvent* ev );
376  private:
377  TDESelectionWatcher* watcher;
378  };
379 
380 TDESelectionWatcherPrivate::TDESelectionWatcherPrivate( TDESelectionWatcher* watcher_P )
381  : watcher( watcher_P )
382  {
383  kapp->installX11EventFilter( TQT_TQWIDGET(this) );
384  }
385 
386 bool TDESelectionWatcherPrivate::x11Event( XEvent* ev_P )
387  {
388  watcher->filterEvent( ev_P );
389  return false;
390  }
391 
392 
393 TDESelectionWatcher::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 
403 TDESelectionWatcher::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 
413 TDESelectionWatcher::~TDESelectionWatcher()
414  {
415  delete d;
416  }
417 
418 void 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 
432 Window 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
454 void 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 
481 Atom TDESelectionWatcher::manager_atom = None;
482 
483 void TDESelectionOwner::virtual_hook( int, void* )
484 { /*BASE::virtual_hook( id, data );*/ }
485 
486 void TDESelectionWatcher::virtual_hook( int, void* )
487 { /*BASE::virtual_hook( id, data );*/ }
488 
489 #include "kmanagerselection.moc"
490 #endif
KXErrorHandler::error
bool error(bool sync) const
This function returns true if the error flag is set (i.e.
KXErrorHandler
This class simplifies handling of X errors.
Definition: kxerrorhandler.h:57

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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.8.8
This website is maintained by Timothy Pearson.