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

twin

  • twin
events.cpp
1 /*****************************************************************
2  KWin - the KDE window manager
3  This file is part of the KDE project.
4 
5 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
7 
8 You can Freely distribute this program under the GNU General Public
9 License. See the file "COPYING" for the exact licensing terms.
10 ******************************************************************/
11 
12 /*
13 
14  This file contains things relevant to handling incoming events.
15 
16 */
17 
18 #include "client.h"
19 #include "workspace.h"
20 #include "atoms.h"
21 #include "tabbox.h"
22 #include "group.h"
23 #include "rules.h"
24 
25 #include <tqwhatsthis.h>
26 #include <kkeynative.h>
27 #include <tqapplication.h>
28 
29 #include <X11/extensions/shape.h>
30 #include <X11/Xatom.h>
31 #include <stdlib.h>
32 
33 extern Atom tqt_window_role;
34 
35 namespace KWinInternal
36 {
37 
38 // ****************************************
39 // WinInfo
40 // ****************************************
41 
42 WinInfo::WinInfo( Client * c, Display * display, Window window,
43  Window rwin, const unsigned long pr[], int pr_size )
44  : NETWinInfo( display, window, rwin, pr, pr_size, NET::WindowManager ), m_client( c )
45  {
46  }
47 
48 void WinInfo::changeDesktop(int desktop)
49  {
50  m_client->workspace()->sendClientToDesktop( m_client, desktop, true );
51  }
52 
53 void WinInfo::changeState( unsigned long state, unsigned long mask )
54  {
55  mask &= ~NET::Sticky; // KWin doesn't support large desktops, ignore
56  mask &= ~NET::Hidden; // clients are not allowed to change this directly
57  state &= mask; // for safety, clear all other bits
58 
59  if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) == 0 )
60  m_client->setFullScreen( false, false );
61  if ( (mask & NET::Max) == NET::Max )
62  m_client->setMaximize( state & NET::MaxVert, state & NET::MaxHoriz );
63  else if ( mask & NET::MaxVert )
64  m_client->setMaximize( state & NET::MaxVert, m_client->maximizeMode() & Client::MaximizeHorizontal );
65  else if ( mask & NET::MaxHoriz )
66  m_client->setMaximize( m_client->maximizeMode() & Client::MaximizeVertical, state & NET::MaxHoriz );
67 
68  if ( mask & NET::Shaded )
69  m_client->setShade( state & NET::Shaded ? ShadeNormal : ShadeNone );
70  if ( mask & NET::KeepAbove)
71  m_client->setKeepAbove( (state & NET::KeepAbove) != 0 );
72  if ( mask & NET::KeepBelow)
73  m_client->setKeepBelow( (state & NET::KeepBelow) != 0 );
74  if( mask & NET::SkipTaskbar )
75  m_client->setSkipTaskbar( ( state & NET::SkipTaskbar ) != 0, true );
76  if( mask & NET::SkipPager )
77  m_client->setSkipPager( ( state & NET::SkipPager ) != 0 );
78  if( mask & NET::DemandsAttention )
79  m_client->demandAttention(( state & NET::DemandsAttention ) != 0 );
80  if( mask & NET::Modal )
81  m_client->setModal( ( state & NET::Modal ) != 0 );
82  // unsetting fullscreen first, setting it last (because e.g. maximize works only for !isFullScreen() )
83  if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) != 0 )
84  m_client->setFullScreen( true, false );
85  }
86 
87 
88 // ****************************************
89 // RootInfo
90 // ****************************************
91 
92 RootInfo::RootInfo( Workspace* ws, Display *dpy, Window w, const char *name, unsigned long pr[], int pr_num, int scr )
93  : NETRootInfo4( dpy, w, name, pr, pr_num, scr )
94  {
95  workspace = ws;
96  }
97 
98 void RootInfo::changeNumberOfDesktops(int n)
99  {
100  workspace->setNumberOfDesktops( n );
101  }
102 
103 void RootInfo::changeCurrentDesktop(int d)
104  {
105  workspace->setCurrentDesktop( d );
106  }
107 
108 void RootInfo::changeActiveWindow( Window w, NET::RequestSource src, Time timestamp, Window active_window )
109  {
110  if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
111  {
112  if( timestamp == CurrentTime )
113  timestamp = c->userTime();
114  if( src != NET::FromApplication && src != FromTool )
115  src = NET::FromTool;
116  if( src == NET::FromTool )
117  workspace->activateClient( c, true ); // force
118  else // NET::FromApplication
119  {
120  Client* c2;
121  if( workspace->allowClientActivation( c, timestamp ))
122  workspace->activateClient( c );
123  // if activation of the requestor's window would be allowed, allow activation too
124  else if( active_window != None
125  && ( c2 = workspace->findClient( WindowMatchPredicate( active_window ))) != NULL
126  && workspace->allowClientActivation( c2,
127  timestampCompare( timestamp, c2->userTime() > 0 ? timestamp : c2->userTime())))
128  workspace->activateClient( c );
129  else
130  c->demandAttention();
131  }
132  }
133  }
134 
135 void RootInfo::restackWindow( Window w, RequestSource src, Window above, int detail, Time timestamp )
136  {
137  if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
138  {
139  if( timestamp == CurrentTime )
140  timestamp = c->userTime();
141  if( src != NET::FromApplication && src != FromTool )
142  src = NET::FromTool;
143  c->restackWindow( above, detail, src, timestamp, true );
144  }
145  }
146 
147 void RootInfo::gotTakeActivity( Window w, Time timestamp, long flags )
148  {
149  if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
150  workspace->handleTakeActivity( c, timestamp, flags );
151  }
152 
153 void RootInfo::closeWindow(Window w)
154  {
155  Client* c = workspace->findClient( WindowMatchPredicate( w ));
156  if ( c )
157  c->closeWindow();
158  }
159 
160 void RootInfo::moveResize(Window w, int x_root, int y_root, unsigned long direction)
161  {
162  Client* c = workspace->findClient( WindowMatchPredicate( w ));
163  if ( c )
164  {
165  updateXTime(); // otherwise grabbing may have old timestamp - this message should include timestamp
166  c->NETMoveResize( x_root, y_root, (Direction)direction);
167  }
168  }
169 
170 void RootInfo::moveResizeWindow(Window w, int flags, int x, int y, int width, int height )
171  {
172  Client* c = workspace->findClient( WindowMatchPredicate( w ));
173  if ( c )
174  c->NETMoveResizeWindow( flags, x, y, width, height );
175  }
176 
177 void RootInfo::gotPing( Window w, Time timestamp )
178  {
179  if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
180  c->gotPing( timestamp );
181  }
182 
183 void RootInfo::changeShowingDesktop( bool showing )
184  {
185  workspace->setShowingDesktop( showing );
186  }
187 
188 // ****************************************
189 // Workspace
190 // ****************************************
191 
195 bool Workspace::workspaceEvent( XEvent * e )
196  {
197  if ( mouse_emulation && (e->type == ButtonPress || e->type == ButtonRelease ) )
198  {
199  mouse_emulation = FALSE;
200  XUngrabKeyboard( tqt_xdisplay(), GET_QT_X_TIME() );
201  }
202 
203  if( e->type == PropertyNotify || e->type == ClientMessage )
204  {
205  unsigned long dirty[ NETRootInfo::PROPERTIES_SIZE ];
206  rootInfo->event( e, dirty, NETRootInfo::PROPERTIES_SIZE );
207  if( dirty[ NETRootInfo::PROTOCOLS ] & NET::DesktopNames )
208  saveDesktopSettings();
209  if( dirty[ NETRootInfo::PROTOCOLS2 ] & NET::WM2DesktopLayout )
210  updateDesktopLayout();
211  }
212 
213  // events that should be handled before Clients can get them
214  switch (e->type)
215  {
216  case ButtonPress:
217  case ButtonRelease:
218  was_user_interaction = true;
219  // fallthrough
220  case MotionNotify:
221  if ( tab_grab || control_grab )
222  {
223  tab_box->handleMouseEvent( e );
224  return TRUE;
225  }
226  break;
227  case KeyPress:
228  {
229  was_user_interaction = true;
230  KKeyNative keyX( (XEvent*)e );
231  uint keyQt = keyX.keyCodeQt();
232  kdDebug(125) << "Workspace::keyPress( " << keyX.key().toString() << " )" << endl;
233  if (movingClient)
234  {
235  movingClient->keyPressEvent(keyQt);
236  return true;
237  }
238  if( tab_grab || control_grab )
239  {
240  tabBoxKeyPress( keyX );
241  return true;
242  }
243  break;
244  }
245  case KeyRelease:
246  was_user_interaction = true;
247  if( tab_grab || control_grab )
248  {
249  tabBoxKeyRelease( e->xkey );
250  return true;
251  }
252  break;
253  };
254 
255  if( Client* c = findClient( WindowMatchPredicate( e->xany.window )))
256  {
257  if( c->windowEvent( e ))
258  return true;
259  }
260  else if( Client* c = findClient( WrapperIdMatchPredicate( e->xany.window )))
261  {
262  if( c->windowEvent( e ))
263  return true;
264  }
265  else if( Client* c = findClient( FrameIdMatchPredicate( e->xany.window )))
266  {
267  if( c->windowEvent( e ))
268  return true;
269  }
270  else
271  {
272  Window special = findSpecialEventWindow( e );
273  if( special != None )
274  if( Client* c = findClient( WindowMatchPredicate( special )))
275  {
276  if( c->windowEvent( e ))
277  return true;
278  }
279  }
280  if( movingClient != NULL && movingClient->moveResizeGrabWindow() == e->xany.window
281  && ( e->type == MotionNotify || e->type == ButtonPress || e->type == ButtonRelease ))
282  {
283  if( movingClient->windowEvent( e ))
284  return true;
285  }
286 
287  switch (e->type)
288  {
289  case CreateNotify:
290  if ( e->xcreatewindow.parent == root &&
291  !TQWidget::find( e->xcreatewindow.window) &&
292  !e->xcreatewindow.override_redirect )
293  {
294  // see comments for allowClientActivation()
295  Time my_qtx_time = GET_QT_X_TIME();
296  XChangeProperty(tqt_xdisplay(), e->xcreatewindow.window,
297  atoms->kde_net_wm_user_creation_time, XA_CARDINAL,
298  32, PropModeReplace, (unsigned char *)&my_qtx_time, 1);
299  SET_QT_X_TIME(my_qtx_time);
300  }
301  break;
302 
303  case UnmapNotify:
304  {
305  // check for system tray windows
306  if ( removeSystemTrayWin( e->xunmap.window, true ) )
307  {
308  // If the system tray gets destroyed, the system tray
309  // icons automatically get unmapped, reparented and mapped
310  // again to the closest non-client ancestor due to
311  // QXEmbed's SaveSet feature. Unfortunatly with kicker
312  // this closest ancestor is not the root window, but our
313  // decoration, so we reparent explicitely back to the root
314  // window.
315  XEvent ev;
316  WId w = e->xunmap.window;
317  if ( XCheckTypedWindowEvent (tqt_xdisplay(), w,
318  ReparentNotify, &ev) )
319  {
320  if ( ev.xreparent.parent != root )
321  {
322  XReparentWindow( tqt_xdisplay(), w, root, 0, 0 );
323  addSystemTrayWin( w );
324  }
325  }
326  return TRUE;
327  }
328 
329  return ( e->xunmap.event != e->xunmap.window ); // hide wm typical event from Qt
330  }
331  case MapNotify:
332 
333  return ( e->xmap.event != e->xmap.window ); // hide wm typical event from Qt
334 
335  case ReparentNotify:
336  {
337  //do not confuse Qt with these events. After all, _we_ are the
338  //window manager who does the reparenting.
339  return TRUE;
340  }
341  case DestroyNotify:
342  {
343  if ( removeSystemTrayWin( e->xdestroywindow.window, false ) )
344  return TRUE;
345  return false;
346  }
347  case MapRequest:
348  {
349  updateXTime();
350 
351  // e->xmaprequest.window is different from e->xany.window
352  // TODO this shouldn't be necessary now
353  Client* c = findClient( WindowMatchPredicate( e->xmaprequest.window ));
354  if ( !c )
355  {
356 // don't check for the parent being the root window, this breaks when some app unmaps
357 // a window, changes something and immediately maps it back, without giving KWin
358 // a chance to reparent it back to root
359 // since KWin can get MapRequest only for root window children and
360 // children of WindowWrapper (=clients), the check is AFAIK useless anyway
361 // Note: Now the save-set support in Client::mapRequestEvent() actually requires that
362 // this code doesn't check the parent to be root.
363 // if ( e->xmaprequest.parent == root ) { //###TODO store previously destroyed client ids
364  if ( addSystemTrayWin( e->xmaprequest.window ) )
365  return TRUE;
366  c = createClient( e->xmaprequest.window, false );
367  if ( c != NULL && root != tqt_xrootwin() )
368  { // TODO what is this?
369  // TODO may use TQWidget::create
370  XReparentWindow( tqt_xdisplay(), c->frameId(), root, 0, 0 );
371  }
372  if( c == NULL ) // refused to manage, simply map it (most probably override redirect)
373  XMapRaised( tqt_xdisplay(), e->xmaprequest.window );
374  return true;
375  }
376  if( c )
377  {
378  c->windowEvent( e );
379  updateFocusChains( c, FocusChainUpdate );
380  return true;
381  }
382  break;
383  }
384  case EnterNotify:
385  {
386  if ( TQWhatsThis::inWhatsThisMode() )
387  {
388  TQWidget* w = TQWidget::find( e->xcrossing.window );
389  if ( w )
390  TQWhatsThis::leaveWhatsThisMode();
391  }
392  if( electricBorder(e))
393  return true;
394  break;
395  }
396  case LeaveNotify:
397  {
398  if ( !TQWhatsThis::inWhatsThisMode() )
399  break;
400  // TODO is this cliente ever found, given that client events are searched above?
401  Client* c = findClient( FrameIdMatchPredicate( e->xcrossing.window ));
402  if ( c && e->xcrossing.detail != NotifyInferior )
403  TQWhatsThis::leaveWhatsThisMode();
404  break;
405  }
406  case ConfigureRequest:
407  {
408  if ( e->xconfigurerequest.parent == root )
409  {
410  XWindowChanges wc;
411  wc.border_width = e->xconfigurerequest.border_width;
412  wc.x = e->xconfigurerequest.x;
413  wc.y = e->xconfigurerequest.y;
414  wc.width = e->xconfigurerequest.width;
415  wc.height = e->xconfigurerequest.height;
416  wc.sibling = None;
417  wc.stack_mode = Above;
418  unsigned int value_mask = e->xconfigurerequest.value_mask
419  & ( CWX | CWY | CWWidth | CWHeight | CWBorderWidth );
420  XConfigureWindow( tqt_xdisplay(), e->xconfigurerequest.window, value_mask, &wc );
421  return true;
422  }
423  break;
424  }
425  case KeyPress:
426  if ( mouse_emulation )
427  return keyPressMouseEmulation( e->xkey );
428  break;
429  case KeyRelease:
430  if ( mouse_emulation )
431  return FALSE;
432  break;
433  case FocusIn:
434  if( e->xfocus.window == rootWin() && TQCString( getenv("TDE_MULTIHEAD")).lower() != "true"
435  && ( e->xfocus.detail == NotifyDetailNone || e->xfocus.detail == NotifyPointerRoot ))
436  {
437  updateXTime(); // focusToNull() uses tqt_x_time, which is old now (FocusIn has no timestamp)
438  Window focus;
439  int revert;
440  XGetInputFocus( tqt_xdisplay(), &focus, &revert );
441  if( focus == None || focus == PointerRoot )
442  {
443  //kdWarning( 1212 ) << "X focus set to None/PointerRoot, reseting focus" << endl;
444  Client *c = mostRecentlyActivatedClient();
445  if( c != NULL )
446  requestFocus( c, true );
447  else if( activateNextClient( NULL ))
448  ; // ok, activated
449  else
450  focusToNull();
451  }
452  }
453  // fall through
454  case FocusOut:
455  return true; // always eat these, they would tell Qt that KWin is the active app
456  case ClientMessage:
457  if( electricBorder( e ))
458  return true;
459  break;
460  default:
461  break;
462  }
463  return FALSE;
464  }
465 
466 // Some events don't have the actual window which caused the event
467 // as e->xany.window (e.g. ConfigureRequest), but as some other
468 // field in the XEvent structure.
469 Window Workspace::findSpecialEventWindow( XEvent* e )
470  {
471  switch( e->type )
472  {
473  case CreateNotify:
474  return e->xcreatewindow.window;
475  case DestroyNotify:
476  return e->xdestroywindow.window;
477  case UnmapNotify:
478  return e->xunmap.window;
479  case MapNotify:
480  return e->xmap.window;
481  case MapRequest:
482  return e->xmaprequest.window;
483  case ReparentNotify:
484  return e->xreparent.window;
485  case ConfigureNotify:
486  return e->xconfigure.window;
487  case GravityNotify:
488  return e->xgravity.window;
489  case ConfigureRequest:
490  return e->xconfigurerequest.window;
491  case CirculateNotify:
492  return e->xcirculate.window;
493  case CirculateRequest:
494  return e->xcirculaterequest.window;
495  default:
496  return None;
497  };
498  }
499 
500 // ****************************************
501 // Client
502 // ****************************************
503 
507 bool Client::windowEvent( XEvent* e )
508  {
509  if( e->xany.window == window()) // avoid doing stuff on frame or wrapper
510  {
511  unsigned long dirty[ 2 ];
512  info->event( e, dirty, 2 ); // pass through the NET stuff
513 
514  if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMName ) != 0 )
515  fetchName();
516  if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconName ) != 0 )
517  fetchIconicName();
518  if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMStrut ) != 0
519  || ( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2ExtendedStrut ) != 0 )
520  {
521  if( isTopMenu()) // the fallback mode of KMenuBar may alter the strut
522  checkWorkspacePosition(); // restore it
523  workspace()->updateClientArea();
524  }
525  if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
526  getIcons();
527  // Note there's a difference between userTime() and info->userTime()
528  // info->userTime() is the value of the property, userTime() also includes
529  // updates of the time done by KWin (ButtonPress on windowrapper etc.).
530  if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2UserTime ) != 0 )
531  {
532  workspace()->setWasUserInteraction();
533  updateUserTime( info->userTime());
534  }
535  if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
536  startupIdChanged();
537  if( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconGeometry )
538  {
539  if( demandAttentionKNotifyTimer != NULL )
540  demandAttentionKNotify();
541  }
542  }
543 
544 // TODO move all focus handling stuff to separate file?
545  switch (e->type)
546  {
547  case UnmapNotify:
548  unmapNotifyEvent( &e->xunmap );
549  break;
550  case DestroyNotify:
551  destroyNotifyEvent( &e->xdestroywindow );
552  break;
553  case MapRequest:
554  // this one may pass the event to workspace
555  return mapRequestEvent( &e->xmaprequest );
556  case ConfigureRequest:
557  configureRequestEvent( &e->xconfigurerequest );
558  break;
559  case PropertyNotify:
560  propertyNotifyEvent( &e->xproperty );
561  break;
562  case KeyPress:
563  updateUserTime();
564  workspace()->setWasUserInteraction();
565  break;
566  case ButtonPress:
567  updateUserTime();
568  workspace()->setWasUserInteraction();
569  buttonPressEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
570  e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
571  break;
572  case KeyRelease:
573  // don't update user time on releases
574  // e.g. if the user presses Alt+F2, the Alt release
575  // would appear as user input to the currently active window
576  break;
577  case ButtonRelease:
578  // don't update user time on releases
579  // e.g. if the user presses Alt+F2, the Alt release
580  // would appear as user input to the currently active window
581  buttonReleaseEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
582  e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
583  break;
584  case MotionNotify:
585  motionNotifyEvent( e->xmotion.window, e->xmotion.state,
586  e->xmotion.x, e->xmotion.y, e->xmotion.x_root, e->xmotion.y_root );
587  workspace()->updateFocusMousePosition( TQPoint( e->xmotion.x_root, e->xmotion.y_root ));
588  break;
589  case EnterNotify:
590  enterNotifyEvent( &e->xcrossing );
591  // MotionNotify is guaranteed to be generated only if the mouse
592  // move start and ends in the window; for cases when it only
593  // starts or only ends there, Enter/LeaveNotify are generated.
594  // Fake a MotionEvent in such cases to make handle of mouse
595  // events simpler (Qt does that too).
596  motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
597  e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
598  workspace()->updateFocusMousePosition( TQPoint( e->xcrossing.x_root, e->xcrossing.y_root ));
599  break;
600  case LeaveNotify:
601  motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
602  e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
603  leaveNotifyEvent( &e->xcrossing );
604  // not here, it'd break following enter notify handling
605  // workspace()->updateFocusMousePosition( TQPoint( e->xcrossing.x_root, e->xcrossing.y_root ));
606  break;
607  case FocusIn:
608  focusInEvent( &e->xfocus );
609  break;
610  case FocusOut:
611  focusOutEvent( &e->xfocus );
612  break;
613  case ReparentNotify:
614  break;
615  case ClientMessage:
616  clientMessageEvent( &e->xclient );
617  break;
618  case ColormapChangeMask:
619  if( e->xany.window == window())
620  {
621  cmap = e->xcolormap.colormap;
622  if ( isActive() )
623  workspace()->updateColormap();
624  }
625  break;
626  default:
627  if( e->xany.window == window())
628  {
629  if( e->type == Shape::shapeEvent() )
630  {
631  is_shape = Shape::hasShape( window()); // workaround for #19644
632  updateShape();
633  }
634  }
635  break;
636  }
637  return true; // eat all events
638  }
639 
643 bool Client::mapRequestEvent( XMapRequestEvent* e )
644  {
645  if( e->window != window())
646  {
647  // Special support for the save-set feature, which is a bit broken.
648  // If there's a window from one client embedded in another one,
649  // e.g. using XEMBED, and the embedder suddenly looses its X connection,
650  // save-set will reparent the embedded window to its closest ancestor
651  // that will remains. Unfortunately, with reparenting window managers,
652  // this is not the root window, but the frame (or in KWin's case,
653  // it's the wrapper for the client window). In this case,
654  // the wrapper will get ReparentNotify for a window it won't know,
655  // which will be ignored, and then it gets MapRequest, as save-set
656  // always maps. Returning true here means that Workspace::workspaceEvent()
657  // will handle this MapRequest and manage this window (i.e. act as if
658  // it was reparented to root window).
659  if( e->parent == wrapperId())
660  return false;
661  return true; // no messing with frame etc.
662  }
663  if( isTopMenu() && workspace()->managingTopMenus())
664  return true; // twin controls these
665  switch ( mappingState() )
666  {
667  case WithdrawnState:
668  assert( false ); // WMs are not supposed to manage clients in Withdrawn state,
669 // manage(); // after initial mapping manage() is called from createClient()
670  break;
671  case IconicState:
672  // also copied in clientMessage()
673  if( isMinimized())
674  unminimize();
675  if( isShade())
676  setShade( ShadeNone );
677  if( !isOnCurrentDesktop())
678  {
679  if( workspace()->allowClientActivation( this ))
680  workspace()->activateClient( this );
681  else
682  demandAttention();
683  }
684  break;
685  case NormalState:
686  // TODO fake MapNotify?
687  break;
688  }
689  return true;
690  }
691 
695 void Client::unmapNotifyEvent( XUnmapEvent* e )
696  {
697  if( e->window != window())
698  return;
699  if( e->event != wrapperId())
700  { // most probably event from root window when initially reparenting
701  bool ignore = true;
702  if( e->event == workspace()->rootWin() && e->send_event )
703  ignore = false; // XWithdrawWindow()
704  if( ignore )
705  return;
706  }
707  switch( mappingState())
708  {
709  case IconicState:
710  releaseWindow();
711  return;
712  case NormalState:
713  // maybe we will be destroyed soon. Check this first.
714  XEvent ev;
715  if( XCheckTypedWindowEvent (tqt_xdisplay(), window(),
716  DestroyNotify, &ev) ) // TODO I don't like this much
717  {
718  destroyClient(); // deletes this
719  return;
720  }
721  releaseWindow();
722  break;
723  default:
724  assert( false );
725  }
726  }
727 
728 void Client::destroyNotifyEvent( XDestroyWindowEvent* e )
729  {
730  if( e->window != window())
731  return;
732  destroyClient();
733  }
734 
735 
736 bool blockAnimation = FALSE;
737 
741 void Client::clientMessageEvent( XClientMessageEvent* e )
742  {
743  if( e->window != window())
744  return; // ignore frame/wrapper
745  // WM_STATE
746  if ( e->message_type == atoms->kde_wm_change_state )
747  {
748  if( isTopMenu() && workspace()->managingTopMenus())
749  return; // twin controls these
750  if( e->data.l[ 1 ] )
751  blockAnimation = true;
752  if( e->data.l[ 0 ] == IconicState )
753  minimize();
754  else if( e->data.l[ 0 ] == NormalState )
755  { // copied from mapRequest()
756  if( isMinimized())
757  unminimize();
758  if( isShade())
759  setShade( ShadeNone );
760  if( !isOnCurrentDesktop())
761  {
762  if( workspace()->allowClientActivation( this ))
763  workspace()->activateClient( this );
764  else
765  demandAttention();
766  }
767  }
768  blockAnimation = false;
769  }
770  else if ( e->message_type == atoms->wm_change_state)
771  {
772  if( isTopMenu() && workspace()->managingTopMenus())
773  return; // twin controls these
774  if ( e->data.l[0] == IconicState )
775  minimize();
776  return;
777  }
778  }
779 
780 
784 void Client::configureRequestEvent( XConfigureRequestEvent* e )
785  {
786  if( e->window != window())
787  return; // ignore frame/wrapper
788  if ( isResize() || isMove())
789  return; // we have better things to do right now
790 
791  if( fullscreen_mode == FullScreenNormal ) // refuse resizing of fullscreen windows
792  { // but allow resizing fullscreen hacks in order to let them cancel fullscreen mode
793  sendSyntheticConfigureNotify();
794  return;
795  }
796  if( isSplash() // no manipulations with splashscreens either
797  || isTopMenu()) // topmenus neither
798  {
799  sendSyntheticConfigureNotify();
800  return;
801  }
802 
803  if ( e->value_mask & CWBorderWidth )
804  {
805  // first, get rid of a window border
806  XWindowChanges wc;
807  unsigned int value_mask = 0;
808 
809  wc.border_width = 0;
810  value_mask = CWBorderWidth;
811  XConfigureWindow( tqt_xdisplay(), window(), value_mask, & wc );
812  }
813 
814  if( e->value_mask & ( CWX | CWY | CWHeight | CWWidth ))
815  configureRequest( e->value_mask, e->x, e->y, e->width, e->height, 0, false );
816 
817  if ( e->value_mask & CWStackMode )
818  restackWindow( e->above, e->detail, NET::FromApplication, userTime(), false );
819 
820  // TODO sending a synthetic configure notify always is fine, even in cases where
821  // the ICCCM doesn't require this - it can be though of as 'the WM decided to move
822  // the window later'. The client should not cause that many configure request,
823  // so this should not have any significant impact. With user moving/resizing
824  // the it should be optimized though (see also Client::setGeometry()/plainResize()/move()).
825  sendSyntheticConfigureNotify();
826 
827  // SELI TODO accept configure requests for isDesktop windows (because kdesktop
828  // may get XRANDR resize event before twin), but check it's still at the bottom?
829  }
830 
831 
835 void Client::propertyNotifyEvent( XPropertyEvent* e )
836  {
837  if( e->window != window())
838  return; // ignore frame/wrapper
839  switch ( e->atom )
840  {
841  case XA_WM_NORMAL_HINTS:
842  getWmNormalHints();
843  break;
844  case XA_WM_NAME:
845  fetchName();
846  break;
847  case XA_WM_ICON_NAME:
848  fetchIconicName();
849  break;
850  case XA_WM_TRANSIENT_FOR:
851  readTransient();
852  break;
853  case XA_WM_HINTS:
854  getWMHints();
855  getIcons(); // because KWin::icon() uses WMHints as fallback
856  break;
857  default:
858  if ( e->atom == atoms->wm_protocols )
859  getWindowProtocols();
860  else if (e->atom == atoms->wm_client_leader )
861  getWmClientLeader();
862  else if( e->atom == tqt_window_role )
863  window_role = staticWindowRole( window());
864  else if( e->atom == atoms->motif_wm_hints )
865  getMotifHints();
866  break;
867  }
868  }
869 
870 
871 void Client::enterNotifyEvent( XCrossingEvent* e )
872  {
873  if( e->window != frameId())
874  return; // care only about entering the whole frame
875  if( e->mode == NotifyNormal ||
876  ( !options->focusPolicyIsReasonable() &&
877  e->mode == NotifyUngrab ) )
878  {
879 
880  if (options->shadeHover && isShade())
881  {
882  delete shadeHoverTimer;
883  shadeHoverTimer = new TQTimer( this );
884  connect( shadeHoverTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( shadeHover() ));
885  shadeHoverTimer->start( options->shadeHoverInterval, TRUE );
886  }
887 
888  if ( options->focusPolicy == Options::ClickToFocus )
889  return;
890 
891  if ( options->autoRaise && !isDesktop() &&
892  !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() &&
893  workspace()->topClientOnDesktop( workspace()->currentDesktop()) != this )
894  {
895  delete autoRaiseTimer;
896  autoRaiseTimer = new TQTimer( this );
897  connect( autoRaiseTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( autoRaise() ) );
898  autoRaiseTimer->start( options->autoRaiseInterval, TRUE );
899  }
900 
901  TQPoint currentPos( e->x_root, e->y_root );
902  if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isTopMenu() ) )
903  return;
904  // for FocusFollowsMouse, change focus only if the mouse has actually been moved, not if the focus
905  // change came because of window changes (e.g. closing a window) - #92290
906  if( options->focusPolicy != Options::FocusFollowsMouse
907  || currentPos != workspace()->focusMousePosition())
908  {
909  if ( options->delayFocus )
910  workspace()->requestDelayFocus( this );
911  else
912  workspace()->requestFocus( this );
913  }
914  return;
915  }
916  }
917 
918 void Client::leaveNotifyEvent( XCrossingEvent* e )
919  {
920  if( e->window != frameId())
921  return; // care only about leaving the whole frame
922  if ( e->mode == NotifyNormal )
923  {
924  if ( !buttonDown )
925  {
926  mode = PositionCenter;
927  setCursor( tqarrowCursor );
928  }
929  bool lostMouse = !rect().contains( TQPoint( e->x, e->y ) );
930  // 'lostMouse' wouldn't work with e.g. B2 or Keramik, which have non-rectangular decorations
931  // (i.e. the LeaveNotify event comes before leaving the rect and no LeaveNotify event
932  // comes after leaving the rect) - so lets check if the pointer is really outside the window
933 
934  // TODO this still sucks if a window appears above this one - it should lose the mouse
935  // if this window is another client, but not if it's a popup ... maybe after KDE3.1 :(
936  // (repeat after me 'AARGHL!')
937  if ( !lostMouse && e->detail != NotifyInferior )
938  {
939  int d1, d2, d3, d4;
940  unsigned int d5;
941  Window w, child;
942  if( XQueryPointer( tqt_xdisplay(), frameId(), &w, &child, &d1, &d2, &d3, &d4, &d5 ) == False
943  || child == None )
944  lostMouse = true; // really lost the mouse
945  }
946  if ( lostMouse )
947  {
948  cancelAutoRaise();
949  workspace()->cancelDelayFocus();
950  cancelShadeHover();
951  if ( shade_mode == ShadeHover && !moveResizeMode && !buttonDown )
952  setShade( ShadeNormal );
953  }
954  if ( options->focusPolicy == Options::FocusStrictlyUnderMouse )
955  if ( isActive() && lostMouse )
956  workspace()->requestFocus( 0 ) ;
957  return;
958  }
959  }
960 
961 #define XCapL KKeyNative::modXLock()
962 #define XNumL KKeyNative::modXNumLock()
963 #define XScrL KKeyNative::modXScrollLock()
964 void Client::grabButton( int modifier )
965  {
966  unsigned int mods[ 8 ] =
967  {
968  0, XCapL, XNumL, XNumL | XCapL,
969  XScrL, XScrL | XCapL,
970  XScrL | XNumL, XScrL | XNumL | XCapL
971  };
972  for( int i = 0;
973  i < 8;
974  ++i )
975  XGrabButton( tqt_xdisplay(), AnyButton,
976  modifier | mods[ i ],
977  wrapperId(), FALSE, ButtonPressMask,
978  GrabModeSync, GrabModeAsync, None, None );
979  }
980 
981 void Client::ungrabButton( int modifier )
982  {
983  unsigned int mods[ 8 ] =
984  {
985  0, XCapL, XNumL, XNumL | XCapL,
986  XScrL, XScrL | XCapL,
987  XScrL | XNumL, XScrL | XNumL | XCapL
988  };
989  for( int i = 0;
990  i < 8;
991  ++i )
992  XUngrabButton( tqt_xdisplay(), AnyButton,
993  modifier | mods[ i ], wrapperId());
994  }
995 #undef XCapL
996 #undef XNumL
997 #undef XScrL
998 
999 /*
1000  Releases the passive grab for some modifier combinations when a
1001  window becomes active. This helps broken X programs that
1002  missinterpret LeaveNotify events in grab mode to work properly
1003  (Motif, AWT, Tk, ...)
1004  */
1005 void Client::updateMouseGrab()
1006  {
1007  if( workspace()->globalShortcutsDisabled())
1008  {
1009  XUngrabButton( tqt_xdisplay(), AnyButton, AnyModifier, wrapperId());
1010  // keep grab for the simple click without modifiers if needed (see below)
1011  bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
1012  if( !( !options->clickRaise || not_obscured ))
1013  grabButton( None );
1014  return;
1015  }
1016  if( isActive() && !workspace()->forcedGlobalMouseGrab()) // see Workspace::establishTabBoxGrab()
1017  {
1018  // first grab all modifier combinations
1019  XGrabButton(tqt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE,
1020  ButtonPressMask,
1021  GrabModeSync, GrabModeAsync,
1022  None, None );
1023  // remove the grab for no modifiers only if the window
1024  // is unobscured or if the user doesn't want click raise
1025  // (it is unobscured if it the topmost in the unconstrained stacking order, i.e. it is
1026  // the most recently raised window)
1027  bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
1028  if( !options->clickRaise || not_obscured )
1029  ungrabButton( None );
1030  else
1031  grabButton( None );
1032  ungrabButton( ShiftMask );
1033  ungrabButton( ControlMask );
1034  ungrabButton( ControlMask | ShiftMask );
1035  }
1036  else
1037  {
1038  XUngrabButton( tqt_xdisplay(), AnyButton, AnyModifier, wrapperId());
1039  // simply grab all modifier combinations
1040  XGrabButton(tqt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE,
1041  ButtonPressMask,
1042  GrabModeSync, GrabModeAsync,
1043  None, None );
1044  }
1045  }
1046 
1047 int qtToX11Button( TQt::ButtonState button )
1048  {
1049  if( button == Qt::LeftButton )
1050  return Button1;
1051  else if( button == Qt::MidButton )
1052  return Button2;
1053  else if( button == Qt::RightButton )
1054  return Button3;
1055  return AnyButton;
1056  }
1057 
1058 int qtToX11State( TQt::ButtonState state )
1059  {
1060  int ret = 0;
1061  if( state & Qt::LeftButton )
1062  ret |= Button1Mask;
1063  if( state & Qt::MidButton )
1064  ret |= Button2Mask;
1065  if( state & Qt::RightButton )
1066  ret |= Button3Mask;
1067  if( state & TQt::ShiftButton )
1068  ret |= ShiftMask;
1069  if( state & TQt::ControlButton )
1070  ret |= ControlMask;
1071  if( state & TQt::AltButton )
1072  ret |= KKeyNative::modX(KKey::ALT);
1073  if( state & TQt::MetaButton )
1074  ret |= KKeyNative::modX(KKey::WIN);
1075  return ret;
1076  }
1077 
1078 // Qt propagates mouse events up the widget hierachy, which means events
1079 // for the decoration window cannot be (easily) intercepted as X11 events
1080 bool Client::eventFilter( TQObject* o, TQEvent* e )
1081  {
1082  if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(shadowWidget))
1083  {
1084  if (e->type() == TQEvent::MouseButtonRelease)
1085  {
1086  int buttonMask, buttonPressed, x, y, x_root, y_root;
1087  unsigned int mask;
1088  TQMouseEvent *qe = (TQMouseEvent *)e;
1089  Window inner_window, parent_window, pointer_window, root_window;
1090  XButtonEvent xe;
1091 
1092  removeShadow();
1093  switch (qe->button())
1094  {
1095  case Qt::MidButton:
1096  buttonMask = Button2Mask;
1097  buttonPressed = Button2;
1098  break;
1099  case Qt::RightButton:
1100  buttonMask = Button3Mask;
1101  buttonPressed = Button3;
1102  break;
1103  default:
1104  buttonMask = Button1Mask;
1105  buttonPressed = Button1;
1106  break;
1107  }
1108 
1109  // find the window under the cursor that should receive the
1110  // simulated events
1111  root_window = tqt_xrootwin();
1112  XQueryPointer(tqt_xdisplay(), root_window, &root_window,
1113  &pointer_window, &x_root, &y_root, &x, &y, &mask);
1114 
1115  if (pointer_window != None)
1116  {
1117  // Save the child window immediately under the window
1118  // decoration, if any. This is so that we can send an event to
1119  // the immediate descendant of a window's window decoration,
1120  // which causes KWin to refocus windows properly
1121  parent_window = pointer_window;
1122  XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1123  &pointer_window, &x_root, &y_root, &x, &y, &mask);
1124  inner_window = pointer_window;
1125 
1126  while (pointer_window != None)
1127  {
1128  // Recursively query for the child window under the pointer,
1129  // using the returned child window as the parent window for
1130  // the subsequent query. When no child window is left, we've
1131  // found the child that will receive the simulated event
1132  parent_window = pointer_window;
1133  XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1134  &pointer_window, &x_root, &y_root, &x, &y, &mask);
1135  }
1136  pointer_window = parent_window;
1137  }
1138  else
1139  inner_window = None;
1140 
1141  // simulate a mouse button press
1142  xe.type = ButtonPress;
1143  xe.display = tqt_xdisplay();
1144  xe.root = tqt_xrootwin();
1145  xe.subwindow = None;
1146  xe.time = CurrentTime;
1147  xe.x = x;
1148  xe.y = y;
1149  xe.x_root = x_root;
1150  xe.y_root = y_root;
1151  xe.state = 0;
1152  xe.button = buttonPressed;
1153  xe.same_screen = True;
1154  if (inner_window != None && inner_window != pointer_window)
1155  {
1156  xe.window = inner_window;
1157  XSendEvent(tqt_xdisplay(), inner_window, True, ButtonPressMask,
1158  (XEvent *)&xe);
1159  }
1160  xe.window = pointer_window;
1161  XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonPressMask,
1162  (XEvent *)&xe);
1163 
1164  // simulate a mouse button release
1165  xe.type = ButtonRelease;
1166  xe.display = tqt_xdisplay();
1167  xe.root = tqt_xrootwin();
1168  xe.subwindow = None;
1169  xe.time = CurrentTime;
1170  xe.x = x;
1171  xe.y = y;
1172  xe.x_root = x_root;
1173  xe.y_root = y_root;
1174  xe.state = buttonMask;
1175  xe.button = buttonPressed;
1176  xe.same_screen = True;
1177  if (inner_window != None && inner_window != pointer_window)
1178  {
1179  xe.window = inner_window;
1180  XSendEvent(tqt_xdisplay(), inner_window, True, ButtonReleaseMask,
1181  (XEvent *)&xe);
1182  }
1183  xe.window = pointer_window;
1184  XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonReleaseMask,
1185  (XEvent *)&xe);
1186 
1187  drawDelayedShadow();
1188 
1189  return true;
1190  }
1191  else if (e->type() == TQEvent::Wheel)
1192  {
1193  int x, y, x_root, y_root;
1194  unsigned int buttonMask, buttonPressed, mask;
1195  TQWheelEvent *wheelEvent = (TQWheelEvent *)e;
1196  Window inner_window, parent_window, pointer_window,
1197  root_window;
1198  XButtonEvent xe;
1199 
1200  removeShadow();
1201 
1202  // state and button parameters passed to XSendEvent depend on the
1203  // direction in which the mouse wheel was rolled
1204  buttonMask = wheelEvent->delta() > 0 ? Button4Mask : Button5Mask;
1205  buttonPressed = wheelEvent->delta() > 0 ? Button4 : Button5;
1206 
1207  // find the window under the cursor that should receive the
1208  // simulated events
1209  root_window = tqt_xrootwin();
1210  XQueryPointer(tqt_xdisplay(), root_window, &root_window,
1211  &pointer_window, &x_root, &y_root, &x, &y, &mask);
1212 
1213  if (pointer_window != None)
1214  {
1215  // Save the child window immediately under the window
1216  // decoration, if any. This is so that we can send an event to
1217  // the immediate descendant of a window's window decoration,
1218  // which causes KWin to refocus windows properly
1219  parent_window = pointer_window;
1220  XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1221  &pointer_window, &x_root, &y_root, &x, &y, &mask);
1222  inner_window = pointer_window;
1223 
1224  while (pointer_window != None)
1225  {
1226  // Recursively query for the child window under the pointer,
1227  // using the returned child window as the parent window for
1228  // the subsequent query. When no child window is left, we've
1229  // found the child that will receive the simulated event
1230  parent_window = pointer_window;
1231  XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1232  &pointer_window, &x_root, &y_root, &x, &y, &mask);
1233  }
1234  pointer_window = parent_window;
1235  }
1236  else
1237  inner_window = None;
1238 
1239  // simulate a mouse button press
1240  xe.type = ButtonPress;
1241  xe.display = tqt_xdisplay();
1242  xe.root = tqt_xrootwin();
1243  xe.subwindow = None;
1244  xe.time = CurrentTime;
1245  xe.x = x;
1246  xe.y = y;
1247  xe.x_root = x_root;
1248  xe.y_root = y_root;
1249  xe.state = 0;
1250  xe.same_screen = True;
1251  if (inner_window != None && inner_window != pointer_window)
1252  {
1253  xe.button = buttonPressed;
1254  xe.window = inner_window;
1255  XSendEvent(tqt_xdisplay(), inner_window, True, ButtonPressMask,
1256  (XEvent *)&xe);
1257  }
1258  xe.button = buttonPressed;
1259  xe.window = pointer_window;
1260  XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonPressMask,
1261  (XEvent *)&xe);
1262 
1263  // simulate a mouse button release
1264  xe.type = ButtonRelease;
1265  xe.display = tqt_xdisplay();
1266  xe.root = tqt_xrootwin();
1267  xe.subwindow = None;
1268  xe.time = CurrentTime;
1269  xe.x = x;
1270  xe.y = y;
1271  xe.x_root = x_root;
1272  xe.y_root = y_root;
1273  xe.same_screen = True;
1274  if (inner_window != None && inner_window != pointer_window)
1275  {
1276  xe.window = inner_window;
1277  xe.state = buttonMask;
1278  xe.button = buttonPressed;
1279  XSendEvent(tqt_xdisplay(), inner_window, True, ButtonReleaseMask,
1280  (XEvent *)&xe);
1281  }
1282  xe.state = buttonMask;
1283  xe.button = buttonPressed;
1284  xe.window = pointer_window;
1285  XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonReleaseMask,
1286  (XEvent *)&xe);
1287 
1288  drawDelayedShadow();
1289 
1290  return true;
1291  }
1292  }
1293  if( decoration == NULL
1294  || TQT_BASE_OBJECT(o) != TQT_BASE_OBJECT(decoration->widget()))
1295  return false;
1296  if( e->type() == TQEvent::MouseButtonPress )
1297  {
1298  TQMouseEvent* ev = TQT_TQMOUSEEVENT( e );
1299  return buttonPressEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
1300  ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1301  }
1302  if( e->type() == TQEvent::MouseButtonRelease )
1303  {
1304  TQMouseEvent* ev = TQT_TQMOUSEEVENT( e );
1305  return buttonReleaseEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
1306  ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1307  }
1308  if( e->type() == TQEvent::MouseMove ) // FRAME i fake z enter/leave?
1309  {
1310  TQMouseEvent* ev = TQT_TQMOUSEEVENT( e );
1311  return motionNotifyEvent( decorationId(), qtToX11State( ev->state()),
1312  ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1313  }
1314  if( e->type() == TQEvent::Wheel )
1315  {
1316  TQWheelEvent* ev = TQT_TQWHEELEVENT( e );
1317  bool r = buttonPressEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->state()),
1318  ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1319  r = r || buttonReleaseEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->state()),
1320  ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1321  return r;
1322  }
1323  if( e->type() == TQEvent::Resize )
1324  {
1325  TQResizeEvent* ev = TQT_TQRESIZEEVENT( e );
1326  // Filter out resize events that inform about size different than frame size.
1327  // This will ensure that decoration->width() etc. and decoration->widget()->width() will be in sync.
1328  // These events only seem to be delayed events from initial resizing before show() was called
1329  // on the decoration widget.
1330  if( ev->size() != size())
1331  return true;
1332  }
1333  return false;
1334  }
1335 
1336 // return value matters only when filtering events before decoration gets them
1337 bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root )
1338  {
1339  if (buttonDown)
1340  {
1341  if( w == wrapperId())
1342  XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime ); //tqt_x_time);
1343  return true;
1344  }
1345 
1346  if( w == wrapperId() || w == frameId() || w == decorationId())
1347  { // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace
1348  // FRAME something out of this would be processed before it gets decorations
1349  updateUserTime();
1350  workspace()->setWasUserInteraction();
1351  uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ?
1352  KKeyNative::modX(KKey::WIN) :
1353  KKeyNative::modX(KKey::ALT);
1354  bool bModKeyHeld = keyModX != 0 && ( state & KKeyNative::accelModMaskX()) == keyModX;
1355 
1356  if( isSplash()
1357  && button == Button1 && !bModKeyHeld )
1358  { // hide splashwindow if the user clicks on it
1359  hideClient( true );
1360  if( w == wrapperId())
1361  XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime ); //tqt_x_time);
1362  return true;
1363  }
1364 
1365  Options::MouseCommand com = Options::MouseNothing;
1366  bool was_action = false;
1367  bool perform_handled = false;
1368  if ( bModKeyHeld )
1369  {
1370  was_action = true;
1371  switch (button)
1372  {
1373  case Button1:
1374  com = options->commandAll1();
1375  break;
1376  case Button2:
1377  com = options->commandAll2();
1378  break;
1379  case Button3:
1380  com = options->commandAll3();
1381  break;
1382  case Button4:
1383  case Button5:
1384  com = options->operationWindowMouseWheel( button == Button4 ? 120 : -120 );
1385  break;
1386  }
1387  }
1388  else
1389  { // inactive inner window
1390  if( !isActive() && w == wrapperId())
1391  {
1392  was_action = true;
1393  perform_handled = true;
1394  switch (button)
1395  {
1396  case Button1:
1397  com = options->commandWindow1();
1398  break;
1399  case Button2:
1400  com = options->commandWindow2();
1401  break;
1402  case Button3:
1403  com = options->commandWindow3();
1404  break;
1405  default:
1406  com = Options::MouseActivateAndPassClick;
1407  }
1408  }
1409  // active inner window
1410  if( isActive() && w == wrapperId()
1411  && options->clickRaise && button < 4 ) // exclude wheel
1412  {
1413  com = Options::MouseActivateRaiseAndPassClick;
1414  was_action = true;
1415  perform_handled = true;
1416  }
1417  }
1418  if( was_action )
1419  {
1420  bool replay = performMouseCommand( com, TQPoint( x_root, y_root), perform_handled );
1421 
1422  if ( isSpecialWindow())
1423  replay = TRUE;
1424 
1425  if( w == wrapperId()) // these can come only from a grab
1426  XAllowEvents(tqt_xdisplay(), replay? ReplayPointer : SyncPointer, CurrentTime ); //tqt_x_time);
1427  return true;
1428  }
1429  }
1430 
1431  if( w == wrapperId()) // these can come only from a grab
1432  {
1433  XAllowEvents(tqt_xdisplay(), ReplayPointer, CurrentTime ); //tqt_x_time);
1434  return true;
1435  }
1436  if( w == decorationId())
1437  return false; // don't eat decoration events
1438  if( w == frameId())
1439  processDecorationButtonPress( button, state, x, y, x_root, y_root );
1440  return true;
1441  }
1442 
1443 
1444 // this function processes button press events only after decoration decides not to handle them,
1445 // unlike buttonPressEvent(), which (when the window is decoration) filters events before decoration gets them
1446 void Client::processDecorationButtonPress( int button, int /*state*/, int x, int y, int x_root, int y_root )
1447  {
1448  Options::MouseCommand com = Options::MouseNothing;
1449  bool active = isActive();
1450  if ( !wantsInput() ) // we cannot be active, use it anyway
1451  active = TRUE;
1452 
1453  if ( button == Button1 )
1454  com = active ? options->commandActiveTitlebar1() : options->commandInactiveTitlebar1();
1455  else if ( button == Button2 )
1456  com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2();
1457  else if ( button == Button3 )
1458  com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3();
1459  if( button == Button1
1460  && com != Options::MouseOperationsMenu // actions where it's not possible to get the matching
1461  && com != Options::MouseMinimize ) // mouse release event
1462  {
1463  mode = mousePosition( TQPoint( x, y ));
1464  buttonDown = TRUE;
1465  moveOffset = TQPoint( x, y );
1466  invertedMoveOffset = rect().bottomRight() - moveOffset;
1467  unrestrictedMoveResize = false;
1468  setCursor( mode ); // update to sizeAllCursor if about to move
1469  }
1470  performMouseCommand( com, TQPoint( x_root, y_root ));
1471  }
1472 
1473 // called from decoration
1474 void Client::processMousePressEvent( TQMouseEvent* e )
1475  {
1476  if( e->type() != TQEvent::MouseButtonPress )
1477  {
1478  kdWarning() << "processMousePressEvent()" << endl;
1479  return;
1480  }
1481  int button;
1482  switch( e->button())
1483  {
1484  case Qt::LeftButton:
1485  button = Button1;
1486  break;
1487  case Qt::MidButton:
1488  button = Button2;
1489  break;
1490  case Qt::RightButton:
1491  button = Button3;
1492  break;
1493  default:
1494  return;
1495  }
1496  processDecorationButtonPress( button, e->state(), e->x(), e->y(), e->globalX(), e->globalY());
1497  }
1498 
1499 // return value matters only when filtering events before decoration gets them
1500 bool Client::buttonReleaseEvent( Window w, int /*button*/, int state, int x, int y, int x_root, int y_root )
1501  {
1502  if( w == decorationId() && !buttonDown)
1503  return false;
1504  if( w == wrapperId())
1505  {
1506  XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime ); //tqt_x_time);
1507  return true;
1508  }
1509  if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
1510  return true;
1511  x = this->x(); // translate from grab window to local coords
1512  y = this->y();
1513  if ( (state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 )
1514  {
1515  buttonDown = FALSE;
1516  if ( moveResizeMode )
1517  {
1518  finishMoveResize( false );
1519  // mouse position is still relative to old Client position, adjust it
1520  TQPoint mousepos( x_root - x, y_root - y );
1521  mode = mousePosition( mousepos );
1522  }
1523  setCursor( mode );
1524  }
1525  return true;
1526  }
1527 
1528 static bool was_motion = false;
1529 static Time next_motion_time = CurrentTime;
1530 // Check whole incoming X queue for MotionNotify events
1531 // checking whole queue is done by always returning False in the predicate.
1532 // If there are more MotionNotify events in the queue, all until the last
1533 // one may be safely discarded (if a ButtonRelease event comes, a MotionNotify
1534 // will be faked from it, so there's no need to check other events).
1535 // This helps avoiding being overloaded by being flooded from many events
1536 // from the XServer.
1537 static Bool motion_predicate( Display*, XEvent* ev, XPointer )
1538 {
1539  if( ev->type == MotionNotify )
1540  {
1541  was_motion = true;
1542  next_motion_time = ev->xmotion.time; // for setting time
1543  }
1544  return False;
1545 }
1546 
1547 static bool waitingMotionEvent()
1548  {
1549 // The queue doesn't need to be checked until the X timestamp
1550 // of processes events reaches the timestamp of the last suitable
1551 // MotionNotify event in the queue.
1552  if( next_motion_time != CurrentTime
1553  && timestampCompare( GET_QT_X_TIME(), next_motion_time ) < 0 )
1554  return true;
1555  was_motion = false;
1556  XSync( tqt_xdisplay(), False ); // this helps to discard more MotionNotify events
1557  XEvent dummy;
1558  XCheckIfEvent( tqt_xdisplay(), &dummy, motion_predicate, NULL );
1559  return was_motion;
1560  }
1561 
1562 // return value matters only when filtering events before decoration gets them
1563 bool Client::motionNotifyEvent( Window w, int /*state*/, int x, int y, int x_root, int y_root )
1564  {
1565  if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
1566  return true; // care only about the whole frame
1567  if ( !buttonDown )
1568  {
1569  Position newmode = mousePosition( TQPoint( x, y ));
1570  if( newmode != mode )
1571  setCursor( newmode );
1572  mode = newmode;
1573  // reset the timestamp for the optimization, otherwise with long passivity
1574  // the option in waitingMotionEvent() may be always true
1575  next_motion_time = CurrentTime;
1576  return false;
1577  }
1578  if( w == moveResizeGrabWindow())
1579  {
1580  x = this->x(); // translate from grab window to local coords
1581  y = this->y();
1582  }
1583  if( !waitingMotionEvent())
1584  handleMoveResize( x, y, x_root, y_root );
1585  return true;
1586  }
1587 
1588 void Client::focusInEvent( XFocusInEvent* e )
1589  {
1590  if( e->window != window())
1591  return; // only window gets focus
1592  if ( e->mode == NotifyUngrab )
1593  return; // we don't care
1594  if ( e->detail == NotifyPointer )
1595  return; // we don't care
1596  if( !isShown( false ) || !isOnCurrentDesktop()) // we unmapped it, but it got focus meanwhile ->
1597  return; // activateNextClient() already transferred focus elsewhere
1598  // check if this client is in should_get_focus list or if activation is allowed
1599  bool activate = workspace()->allowClientActivation( this, -1U, true );
1600  workspace()->gotFocusIn( this ); // remove from should_get_focus list
1601  if( activate )
1602  setActive( TRUE );
1603  else
1604  {
1605  workspace()->restoreFocus();
1606  demandAttention();
1607  }
1608  }
1609 
1610 // When a client loses focus, FocusOut events are usually immediatelly
1611 // followed by FocusIn events for another client that gains the focus
1612 // (unless the focus goes to another screen, or to the nofocus widget).
1613 // Without this check, the former focused client would have to be
1614 // deactivated, and after that, the new one would be activated, with
1615 // a short time when there would be no active client. This can cause
1616 // flicker sometimes, e.g. when a fullscreen is shown, and focus is transferred
1617 // from it to its transient, the fullscreen would be kept in the Active layer
1618 // at the beginning and at the end, but not in the middle, when the active
1619 // client would be temporarily none (see Client::belongToLayer() ).
1620 // Therefore, the events queue is checked, whether it contains the matching
1621 // FocusIn event, and if yes, deactivation of the previous client will
1622 // be skipped, as activation of the new one will automatically deactivate
1623 // previously active client.
1624 static bool follows_focusin = false;
1625 static bool follows_focusin_failed = false;
1626 static Bool predicate_follows_focusin( Display*, XEvent* e, XPointer arg )
1627  {
1628  if( follows_focusin || follows_focusin_failed )
1629  return False;
1630  Client* c = ( Client* ) arg;
1631  if( e->type == FocusIn && c->workspace()->findClient( WindowMatchPredicate( e->xfocus.window )))
1632  { // found FocusIn
1633  follows_focusin = true;
1634  return False;
1635  }
1636  // events that may be in the queue before the FocusIn event that's being
1637  // searched for
1638  if( e->type == FocusIn || e->type == FocusOut || e->type == KeymapNotify )
1639  return False;
1640  follows_focusin_failed = true; // a different event - stop search
1641  return False;
1642  }
1643 
1644 static bool check_follows_focusin( Client* c )
1645  {
1646  follows_focusin = follows_focusin_failed = false;
1647  XEvent dummy;
1648  // XCheckIfEvent() is used to make the search non-blocking, the predicate
1649  // always returns False, so nothing is removed from the events queue.
1650  // XPeekIfEvent() would block.
1651  XCheckIfEvent( tqt_xdisplay(), &dummy, predicate_follows_focusin, (XPointer)c );
1652  return follows_focusin;
1653  }
1654 
1655 
1656 void Client::focusOutEvent( XFocusOutEvent* e )
1657  {
1658  if( e->window != window())
1659  return; // only window gets focus
1660  if ( e->mode == NotifyGrab )
1661  return; // we don't care
1662  if ( isShade() )
1663  return; // here neither
1664  if ( e->detail != NotifyNonlinear
1665  && e->detail != NotifyNonlinearVirtual )
1666  // SELI check all this
1667  return; // hack for motif apps like netscape
1668  if ( TQApplication::activePopupWidget() )
1669  return;
1670  if( !check_follows_focusin( this ))
1671  setActive( FALSE );
1672  }
1673 
1674 // performs _NET_WM_MOVERESIZE
1675 void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction )
1676  {
1677  if( direction == NET::Move )
1678  performMouseCommand( Options::MouseMove, TQPoint( x_root, y_root ));
1679  else if( moveResizeMode && direction == NET::MoveResizeCancel )
1680  {
1681  finishMoveResize( true );
1682  buttonDown = FALSE;
1683  setCursor( mode );
1684  }
1685  else if( direction >= NET::TopLeft && direction <= NET::Left )
1686  {
1687  static const Position convert[] =
1688  {
1689  PositionTopLeft,
1690  PositionTop,
1691  PositionTopRight,
1692  PositionRight,
1693  PositionBottomRight,
1694  PositionBottom,
1695  PositionBottomLeft,
1696  PositionLeft
1697  };
1698  if(!isResizable() || isShade())
1699  return;
1700  if( moveResizeMode )
1701  finishMoveResize( false );
1702  buttonDown = TRUE;
1703  moveOffset = TQPoint( x_root - x(), y_root - y()); // map from global
1704  invertedMoveOffset = rect().bottomRight() - moveOffset;
1705  unrestrictedMoveResize = false;
1706  mode = convert[ direction ];
1707  setCursor( mode );
1708  if( !startMoveResize())
1709  {
1710  buttonDown = false;
1711  setCursor( mode );
1712  }
1713  }
1714  else if( direction == NET::KeyboardMove )
1715  { // ignore mouse coordinates given in the message, mouse position is used by the moving algorithm
1716  TQCursor::setPos( geometry().center() );
1717  performMouseCommand( Options::MouseUnrestrictedMove, geometry().center());
1718  }
1719  else if( direction == NET::KeyboardSize )
1720  { // ignore mouse coordinates given in the message, mouse position is used by the resizing algorithm
1721  TQCursor::setPos( geometry().bottomRight());
1722  performMouseCommand( Options::MouseUnrestrictedResize, geometry().bottomRight());
1723  }
1724  }
1725 
1726 void Client::keyPressEvent( uint key_code )
1727  {
1728  updateUserTime();
1729  if ( !isMove() && !isResize() )
1730  return;
1731  bool is_control = key_code & Qt::CTRL;
1732  bool is_alt = key_code & Qt::ALT;
1733  key_code = key_code & 0xffff;
1734  int delta = is_control?1:is_alt?32:8;
1735  TQPoint pos = TQCursor::pos();
1736  switch ( key_code )
1737  {
1738  case Key_Left:
1739  pos.rx() -= delta;
1740  break;
1741  case Key_Right:
1742  pos.rx() += delta;
1743  break;
1744  case Key_Up:
1745  pos.ry() -= delta;
1746  break;
1747  case Key_Down:
1748  pos.ry() += delta;
1749  break;
1750  case Key_Space:
1751  case Key_Return:
1752  case Key_Enter:
1753  finishMoveResize( false );
1754  buttonDown = FALSE;
1755  setCursor( mode );
1756  break;
1757  case Key_Escape:
1758  finishMoveResize( true );
1759  buttonDown = FALSE;
1760  setCursor( mode );
1761  break;
1762  default:
1763  return;
1764  }
1765  TQCursor::setPos( pos );
1766  }
1767 
1768 // ****************************************
1769 // Group
1770 // ****************************************
1771 
1772 bool Group::groupEvent( XEvent* e )
1773  {
1774  unsigned long dirty[ 2 ];
1775  leader_info->event( e, dirty, 2 ); // pass through the NET stuff
1776  if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
1777  getIcons();
1778  if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
1779  startupIdChanged();
1780  return false;
1781  }
1782 
1783 
1784 } // namespace

twin

Skip menu "twin"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members

twin

Skip menu "twin"
  • kate
  • libkonq
  • twin
  •   lib
Generated for twin by doxygen 1.8.1.2
This website is maintained by Timothy Pearson.