• 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_tqt_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_tqt_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_tqt_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 (activeBorderEvent(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 (activeBorderEvent(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() || inhibitConfigureRequests)
789  {
790  // Send a synthetic configure notification to make sure the
791  // window contents get updated by the application
792  sendSyntheticConfigureNotify();
793  return; // we have better things to do right now
794  }
795 
796  if( fullscreen_mode == FullScreenNormal ) // refuse resizing of fullscreen windows
797  { // but allow resizing fullscreen hacks in order to let them cancel fullscreen mode
798  sendSyntheticConfigureNotify();
799  return;
800  }
801  if( isSplash() // no manipulations with splashscreens either
802  || isTopMenu()) // topmenus neither
803  {
804  sendSyntheticConfigureNotify();
805  return;
806  }
807 
808  if ( e->value_mask & CWBorderWidth )
809  {
810  // first, get rid of a window border
811  XWindowChanges wc;
812  unsigned int value_mask = 0;
813 
814  wc.border_width = 0;
815  value_mask = CWBorderWidth;
816  XConfigureWindow( tqt_xdisplay(), window(), value_mask, & wc );
817  }
818 
819  if( e->value_mask & ( CWX | CWY | CWHeight | CWWidth ))
820  configureRequest( e->value_mask, e->x, e->y, e->width, e->height, 0, false );
821 
822  if ( e->value_mask & CWStackMode )
823  restackWindow( e->above, e->detail, NET::FromApplication, userTime(), false );
824 
825  // TODO sending a synthetic configure notify always is fine, even in cases where
826  // the ICCCM doesn't require this - it can be thought of as 'the WM decided to move
827  // the window later'. The client should not cause that many configure request,
828  // so this should not have any significant impact. With user moving/resizing
829  // the it should be optimized though (see also Client::setGeometry()/plainResize()/move()).
830  sendSyntheticConfigureNotify();
831 
832  // SELI TODO accept configure requests for isDesktop windows (because kdesktop
833  // may get XRANDR resize event before twin), but check it's still at the bottom?
834  }
835 
836 
840 void Client::propertyNotifyEvent( XPropertyEvent* e )
841  {
842  if( e->window != window())
843  return; // ignore frame/wrapper
844  switch ( e->atom )
845  {
846  case XA_WM_NORMAL_HINTS:
847  getWmNormalHints();
848  break;
849  case XA_WM_NAME:
850  fetchName();
851  break;
852  case XA_WM_ICON_NAME:
853  fetchIconicName();
854  break;
855  case XA_WM_TRANSIENT_FOR:
856  readTransient();
857  break;
858  case XA_WM_HINTS:
859  getWMHints();
860  getIcons(); // because KWin::icon() uses WMHints as fallback
861  break;
862  default:
863  if ( e->atom == atoms->wm_protocols )
864  getWindowProtocols();
865  else if (e->atom == atoms->wm_client_leader )
866  getWmClientLeader();
867  else if( e->atom == tqt_window_role )
868  window_role = staticWindowRole( window());
869  else if( e->atom == atoms->motif_wm_hints )
870  getMotifHints();
871  break;
872  }
873  }
874 
875 
876 void Client::enterNotifyEvent( XCrossingEvent* e )
877  {
878  if( e->window != frameId())
879  return; // care only about entering the whole frame
880  if( e->mode == NotifyNormal ||
881  ( !options->focusPolicyIsReasonable() &&
882  e->mode == NotifyUngrab ) )
883  {
884 
885  if (options->shadeHover && isShade())
886  {
887  delete shadeHoverTimer;
888  shadeHoverTimer = new TQTimer( this );
889  connect( shadeHoverTimer, TQ_SIGNAL( timeout() ), this, TQ_SLOT( shadeHover() ));
890  shadeHoverTimer->start( options->shadeHoverInterval, TRUE );
891  }
892 
893  if ( options->focusPolicy == Options::ClickToFocus )
894  return;
895 
896  if ( options->autoRaise && !isDesktop() &&
897  !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() &&
898  workspace()->topClientOnDesktop( workspace()->currentDesktop()) != this )
899  {
900  delete autoRaiseTimer;
901  autoRaiseTimer = new TQTimer( this );
902  connect( autoRaiseTimer, TQ_SIGNAL( timeout() ), this, TQ_SLOT( autoRaise() ) );
903  autoRaiseTimer->start( options->autoRaiseInterval, TRUE );
904  }
905 
906  TQPoint currentPos( e->x_root, e->y_root );
907  if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isTopMenu() ) )
908  return;
909  // for FocusFollowsMouse, change focus only if the mouse has actually been moved, not if the focus
910  // change came because of window changes (e.g. closing a window) - #92290
911  if( options->focusPolicy != Options::FocusFollowsMouse
912  || currentPos != workspace()->focusMousePosition())
913  {
914  if ( options->delayFocus )
915  workspace()->requestDelayFocus( this );
916  else
917  workspace()->requestFocus( this );
918  }
919  return;
920  }
921  }
922 
923 void Client::leaveNotifyEvent( XCrossingEvent* e )
924  {
925  if( e->window != frameId())
926  return; // care only about leaving the whole frame
927  if ( e->mode == NotifyNormal )
928  {
929  if ( !buttonDown )
930  {
931  mode = PositionCenter;
932  setCursor( TQt::arrowCursor );
933  }
934  bool lostMouse = !rect().contains( TQPoint( e->x, e->y ) );
935  // 'lostMouse' wouldn't work with e.g. B2 or Keramik, which have non-rectangular decorations
936  // (i.e. the LeaveNotify event comes before leaving the rect and no LeaveNotify event
937  // comes after leaving the rect) - so lets check if the pointer is really outside the window
938 
939  // TODO this still sucks if a window appears above this one - it should lose the mouse
940  // if this window is another client, but not if it's a popup ... maybe after KDE3.1 :(
941  // (repeat after me 'AARGHL!')
942  if ( !lostMouse && e->detail != NotifyInferior )
943  {
944  int d1, d2, d3, d4;
945  unsigned int d5;
946  Window w, child;
947  if( XQueryPointer( tqt_xdisplay(), frameId(), &w, &child, &d1, &d2, &d3, &d4, &d5 ) == False
948  || child == None )
949  lostMouse = true; // really lost the mouse
950  }
951  if ( lostMouse )
952  {
953  cancelAutoRaise();
954  workspace()->cancelDelayFocus();
955  cancelShadeHover();
956  if ( shade_mode == ShadeHover && !moveResizeMode && !buttonDown )
957  setShade( ShadeNormal );
958  }
959  if ( options->focusPolicy == Options::FocusStrictlyUnderMouse )
960  if ( isActive() && lostMouse )
961  workspace()->requestFocus( 0 ) ;
962  return;
963  }
964  }
965 
966 #define XCapL KKeyNative::modXLock()
967 #define XNumL KKeyNative::modXNumLock()
968 #define XScrL KKeyNative::modXScrollLock()
969 void Client::grabButton( int modifier )
970  {
971  unsigned int mods[ 8 ] =
972  {
973  0, XCapL, XNumL, XNumL | XCapL,
974  XScrL, XScrL | XCapL,
975  XScrL | XNumL, XScrL | XNumL | XCapL
976  };
977  for( int i = 0;
978  i < 8;
979  ++i )
980  XGrabButton( tqt_xdisplay(), AnyButton,
981  modifier | mods[ i ],
982  wrapperId(), FALSE, ButtonPressMask,
983  GrabModeSync, GrabModeAsync, None, None );
984  }
985 
986 void Client::ungrabButton( int modifier )
987  {
988  unsigned int mods[ 8 ] =
989  {
990  0, XCapL, XNumL, XNumL | XCapL,
991  XScrL, XScrL | XCapL,
992  XScrL | XNumL, XScrL | XNumL | XCapL
993  };
994  for( int i = 0;
995  i < 8;
996  ++i )
997  XUngrabButton( tqt_xdisplay(), AnyButton,
998  modifier | mods[ i ], wrapperId());
999  }
1000 #undef XCapL
1001 #undef XNumL
1002 #undef XScrL
1003 
1004 /*
1005  Releases the passive grab for some modifier combinations when a
1006  window becomes active. This helps broken X programs that
1007  missinterpret LeaveNotify events in grab mode to work properly
1008  (Motif, AWT, Tk, ...)
1009  */
1010 void Client::updateMouseGrab()
1011  {
1012  if( workspace()->globalShortcutsDisabled())
1013  {
1014  XUngrabButton( tqt_xdisplay(), AnyButton, AnyModifier, wrapperId());
1015  // keep grab for the simple click without modifiers if needed (see below)
1016  bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
1017  if( !( !options->clickRaise || not_obscured ))
1018  grabButton( None );
1019  return;
1020  }
1021  if( isActive() && !workspace()->forcedGlobalMouseGrab()) // see Workspace::establishTabBoxGrab()
1022  {
1023  // first grab all modifier combinations
1024  XGrabButton(tqt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE,
1025  ButtonPressMask,
1026  GrabModeSync, GrabModeAsync,
1027  None, None );
1028  // remove the grab for no modifiers only if the window
1029  // is unobscured or if the user doesn't want click raise
1030  // (it is unobscured if it the topmost in the unconstrained stacking order, i.e. it is
1031  // the most recently raised window)
1032  bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
1033  if( !options->clickRaise || not_obscured )
1034  ungrabButton( None );
1035  else
1036  grabButton( None );
1037  ungrabButton( ShiftMask );
1038  ungrabButton( ControlMask );
1039  ungrabButton( ControlMask | ShiftMask );
1040  }
1041  else
1042  {
1043  XUngrabButton( tqt_xdisplay(), AnyButton, AnyModifier, wrapperId());
1044  // simply grab all modifier combinations
1045  XGrabButton(tqt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE,
1046  ButtonPressMask,
1047  GrabModeSync, GrabModeAsync,
1048  None, None );
1049  }
1050  }
1051 
1052 int qtToX11Button( TQt::ButtonState button )
1053  {
1054  if( button == TQt::LeftButton )
1055  return Button1;
1056  else if( button == TQt::MidButton )
1057  return Button2;
1058  else if( button == TQt::RightButton )
1059  return Button3;
1060  return AnyButton;
1061  }
1062 
1063 int qtToX11State( TQt::ButtonState state )
1064  {
1065  int ret = 0;
1066  if( state & TQt::LeftButton )
1067  ret |= Button1Mask;
1068  if( state & TQt::MidButton )
1069  ret |= Button2Mask;
1070  if( state & TQt::RightButton )
1071  ret |= Button3Mask;
1072  if( state & TQt::ShiftButton )
1073  ret |= ShiftMask;
1074  if( state & TQt::ControlButton )
1075  ret |= ControlMask;
1076  if( state & TQt::AltButton )
1077  ret |= KKeyNative::modX(KKey::ALT);
1078  if( state & TQt::MetaButton )
1079  ret |= KKeyNative::modX(KKey::WIN);
1080  return ret;
1081  }
1082 
1083 // Qt propagates mouse events up the widget hierachy, which means events
1084 // for the decoration window cannot be (easily) intercepted as X11 events
1085 bool Client::eventFilter( TQObject* o, TQEvent* e )
1086  {
1087  if (o == shadowWidget)
1088  {
1089  if (e->type() == TQEvent::MouseButtonRelease)
1090  {
1091  int buttonMask, buttonPressed, x, y, x_root, y_root;
1092  unsigned int mask;
1093  TQMouseEvent *qe = (TQMouseEvent *)e;
1094  Window inner_window, parent_window, pointer_window, root_window;
1095  XButtonEvent xe;
1096 
1097  removeShadow();
1098  switch (qe->button())
1099  {
1100  case TQt::MidButton:
1101  buttonMask = Button2Mask;
1102  buttonPressed = Button2;
1103  break;
1104  case TQt::RightButton:
1105  buttonMask = Button3Mask;
1106  buttonPressed = Button3;
1107  break;
1108  default:
1109  buttonMask = Button1Mask;
1110  buttonPressed = Button1;
1111  break;
1112  }
1113 
1114  // find the window under the cursor that should receive the
1115  // simulated events
1116  root_window = tqt_xrootwin();
1117  XQueryPointer(tqt_xdisplay(), root_window, &root_window,
1118  &pointer_window, &x_root, &y_root, &x, &y, &mask);
1119 
1120  if (pointer_window != None)
1121  {
1122  // Save the child window immediately under the window
1123  // decoration, if any. This is so that we can send an event to
1124  // the immediate descendant of a window's window decoration,
1125  // which causes KWin to refocus windows properly
1126  parent_window = pointer_window;
1127  XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1128  &pointer_window, &x_root, &y_root, &x, &y, &mask);
1129  inner_window = pointer_window;
1130 
1131  while (pointer_window != None)
1132  {
1133  // Recursively query for the child window under the pointer,
1134  // using the returned child window as the parent window for
1135  // the subsequent query. When no child window is left, we've
1136  // found the child that will receive the simulated event
1137  parent_window = pointer_window;
1138  XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1139  &pointer_window, &x_root, &y_root, &x, &y, &mask);
1140  }
1141  pointer_window = parent_window;
1142  }
1143  else
1144  inner_window = None;
1145 
1146  // simulate a mouse button press
1147  xe.type = ButtonPress;
1148  xe.display = tqt_xdisplay();
1149  xe.root = tqt_xrootwin();
1150  xe.subwindow = None;
1151  xe.time = CurrentTime;
1152  xe.x = x;
1153  xe.y = y;
1154  xe.x_root = x_root;
1155  xe.y_root = y_root;
1156  xe.state = 0;
1157  xe.button = buttonPressed;
1158  xe.same_screen = True;
1159  if (inner_window != None && inner_window != pointer_window)
1160  {
1161  xe.window = inner_window;
1162  XSendEvent(tqt_xdisplay(), inner_window, True, ButtonPressMask,
1163  (XEvent *)&xe);
1164  }
1165  xe.window = pointer_window;
1166  XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonPressMask,
1167  (XEvent *)&xe);
1168 
1169  // simulate a mouse button release
1170  xe.type = ButtonRelease;
1171  xe.display = tqt_xdisplay();
1172  xe.root = tqt_xrootwin();
1173  xe.subwindow = None;
1174  xe.time = CurrentTime;
1175  xe.x = x;
1176  xe.y = y;
1177  xe.x_root = x_root;
1178  xe.y_root = y_root;
1179  xe.state = buttonMask;
1180  xe.button = buttonPressed;
1181  xe.same_screen = True;
1182  if (inner_window != None && inner_window != pointer_window)
1183  {
1184  xe.window = inner_window;
1185  XSendEvent(tqt_xdisplay(), inner_window, True, ButtonReleaseMask,
1186  (XEvent *)&xe);
1187  }
1188  xe.window = pointer_window;
1189  XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonReleaseMask,
1190  (XEvent *)&xe);
1191 
1192  drawDelayedShadow();
1193 
1194  return true;
1195  }
1196  else if (e->type() == TQEvent::Wheel)
1197  {
1198  int x, y, x_root, y_root;
1199  unsigned int buttonMask, buttonPressed, mask;
1200  TQWheelEvent *wheelEvent = (TQWheelEvent *)e;
1201  Window inner_window, parent_window, pointer_window,
1202  root_window;
1203  XButtonEvent xe;
1204 
1205  removeShadow();
1206 
1207  // state and button parameters passed to XSendEvent depend on the
1208  // direction in which the mouse wheel was rolled
1209  buttonMask = wheelEvent->delta() > 0 ? Button4Mask : Button5Mask;
1210  buttonPressed = wheelEvent->delta() > 0 ? Button4 : Button5;
1211 
1212  // find the window under the cursor that should receive the
1213  // simulated events
1214  root_window = tqt_xrootwin();
1215  XQueryPointer(tqt_xdisplay(), root_window, &root_window,
1216  &pointer_window, &x_root, &y_root, &x, &y, &mask);
1217 
1218  if (pointer_window != None)
1219  {
1220  // Save the child window immediately under the window
1221  // decoration, if any. This is so that we can send an event to
1222  // the immediate descendant of a window's window decoration,
1223  // which causes KWin to refocus windows properly
1224  parent_window = pointer_window;
1225  XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1226  &pointer_window, &x_root, &y_root, &x, &y, &mask);
1227  inner_window = pointer_window;
1228 
1229  while (pointer_window != None)
1230  {
1231  // Recursively query for the child window under the pointer,
1232  // using the returned child window as the parent window for
1233  // the subsequent query. When no child window is left, we've
1234  // found the child that will receive the simulated event
1235  parent_window = pointer_window;
1236  XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1237  &pointer_window, &x_root, &y_root, &x, &y, &mask);
1238  }
1239  pointer_window = parent_window;
1240  }
1241  else
1242  inner_window = None;
1243 
1244  // simulate a mouse button press
1245  xe.type = ButtonPress;
1246  xe.display = tqt_xdisplay();
1247  xe.root = tqt_xrootwin();
1248  xe.subwindow = None;
1249  xe.time = CurrentTime;
1250  xe.x = x;
1251  xe.y = y;
1252  xe.x_root = x_root;
1253  xe.y_root = y_root;
1254  xe.state = 0;
1255  xe.same_screen = True;
1256  if (inner_window != None && inner_window != pointer_window)
1257  {
1258  xe.button = buttonPressed;
1259  xe.window = inner_window;
1260  XSendEvent(tqt_xdisplay(), inner_window, True, ButtonPressMask,
1261  (XEvent *)&xe);
1262  }
1263  xe.button = buttonPressed;
1264  xe.window = pointer_window;
1265  XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonPressMask,
1266  (XEvent *)&xe);
1267 
1268  // simulate a mouse button release
1269  xe.type = ButtonRelease;
1270  xe.display = tqt_xdisplay();
1271  xe.root = tqt_xrootwin();
1272  xe.subwindow = None;
1273  xe.time = CurrentTime;
1274  xe.x = x;
1275  xe.y = y;
1276  xe.x_root = x_root;
1277  xe.y_root = y_root;
1278  xe.same_screen = True;
1279  if (inner_window != None && inner_window != pointer_window)
1280  {
1281  xe.window = inner_window;
1282  xe.state = buttonMask;
1283  xe.button = buttonPressed;
1284  XSendEvent(tqt_xdisplay(), inner_window, True, ButtonReleaseMask,
1285  (XEvent *)&xe);
1286  }
1287  xe.state = buttonMask;
1288  xe.button = buttonPressed;
1289  xe.window = pointer_window;
1290  XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonReleaseMask,
1291  (XEvent *)&xe);
1292 
1293  drawDelayedShadow();
1294 
1295  return true;
1296  }
1297  }
1298  if( decoration == NULL
1299  || o != decoration->widget())
1300  return false;
1301  if( e->type() == TQEvent::MouseButtonPress )
1302  {
1303  TQMouseEvent* ev = static_cast<TQMouseEvent*>( e );
1304  return buttonPressEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
1305  ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1306  }
1307  if( e->type() == TQEvent::MouseButtonRelease )
1308  {
1309  TQMouseEvent* ev = static_cast<TQMouseEvent*>( e );
1310  return buttonReleaseEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
1311  ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1312  }
1313  if( e->type() == TQEvent::MouseMove ) // FRAME i fake z enter/leave?
1314  {
1315  TQMouseEvent* ev = static_cast<TQMouseEvent*>( e );
1316  return motionNotifyEvent( decorationId(), qtToX11State( ev->state()),
1317  ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1318  }
1319  if( e->type() == TQEvent::Wheel )
1320  {
1321  TQWheelEvent* ev = static_cast<TQWheelEvent*>( e );
1322  bool r = buttonPressEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->state()),
1323  ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1324  r = r || buttonReleaseEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->state()),
1325  ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1326  return r;
1327  }
1328  if( e->type() == TQEvent::Resize )
1329  {
1330  TQResizeEvent* ev = static_cast<TQResizeEvent*>( e );
1331  // Filter out resize events that inform about size different than frame size.
1332  // This will ensure that decoration->width() etc. and decoration->widget()->width() will be in sync.
1333  // These events only seem to be delayed events from initial resizing before show() was called
1334  // on the decoration widget.
1335  if( ev->size() != size())
1336  return true;
1337  }
1338  return false;
1339  }
1340 
1341 // return value matters only when filtering events before decoration gets them
1342 bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root )
1343  {
1344  if (buttonDown)
1345  {
1346  if( w == wrapperId())
1347  XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime ); //tqt_x_time);
1348  return true;
1349  }
1350 
1351  if( w == wrapperId() || w == frameId() || w == decorationId())
1352  { // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace
1353  // FRAME something out of this would be processed before it gets decorations
1354  updateUserTime();
1355  workspace()->setWasUserInteraction();
1356  uint keyModX = (options->keyCmdAllModKey() == TQt::Key_Meta) ?
1357  KKeyNative::modX(KKey::WIN) :
1358  KKeyNative::modX(KKey::ALT);
1359  bool bModKeyHeld = keyModX != 0 && ( state & KKeyNative::accelModMaskX()) == keyModX;
1360 
1361  if( isSplash()
1362  && button == Button1 && !bModKeyHeld )
1363  { // hide splashwindow if the user clicks on it
1364  hideClient( true );
1365  if( w == wrapperId())
1366  XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime ); //tqt_x_time);
1367  return true;
1368  }
1369 
1370  Options::MouseCommand com = Options::MouseNothing;
1371  bool was_action = false;
1372  bool perform_handled = false;
1373  if ( bModKeyHeld )
1374  {
1375  was_action = true;
1376  switch (button)
1377  {
1378  case Button1:
1379  com = options->commandAll1();
1380  break;
1381  case Button2:
1382  com = options->commandAll2();
1383  break;
1384  case Button3:
1385  com = options->commandAll3();
1386  break;
1387  case Button4:
1388  case Button5:
1389  com = options->operationWindowMouseWheel( button == Button4 ? 120 : -120 );
1390  break;
1391  }
1392  }
1393  else
1394  { // inactive inner window
1395  if( !isActive() && w == wrapperId())
1396  {
1397  was_action = true;
1398  perform_handled = true;
1399  switch (button)
1400  {
1401  case Button1:
1402  com = options->commandWindow1();
1403  break;
1404  case Button2:
1405  com = options->commandWindow2();
1406  break;
1407  case Button3:
1408  com = options->commandWindow3();
1409  break;
1410  default:
1411  com = Options::MouseActivateAndPassClick;
1412  }
1413  }
1414  // active inner window
1415  if( isActive() && w == wrapperId()
1416  && options->clickRaise && button < 4 ) // exclude wheel
1417  {
1418  com = Options::MouseActivateRaiseAndPassClick;
1419  was_action = true;
1420  perform_handled = true;
1421  }
1422  }
1423  if( was_action )
1424  {
1425  bool replay = performMouseCommand( com, TQPoint( x_root, y_root), perform_handled );
1426 
1427  if ( isSpecialWindow())
1428  replay = TRUE;
1429 
1430  if( w == wrapperId()) // these can come only from a grab
1431  XAllowEvents(tqt_xdisplay(), replay? ReplayPointer : SyncPointer, CurrentTime ); //tqt_x_time);
1432  return true;
1433  }
1434  }
1435 
1436  if( w == wrapperId()) // these can come only from a grab
1437  {
1438  XAllowEvents(tqt_xdisplay(), ReplayPointer, CurrentTime ); //tqt_x_time);
1439  return true;
1440  }
1441  if( w == decorationId())
1442  return false; // don't eat decoration events
1443  if( w == frameId())
1444  processDecorationButtonPress( button, state, x, y, x_root, y_root );
1445  return true;
1446  }
1447 
1448 
1449 // this function processes button press events only after decoration decides not to handle them,
1450 // unlike buttonPressEvent(), which (when the window is decoration) filters events before decoration gets them
1451 void Client::processDecorationButtonPress( int button, int /*state*/, int x, int y, int x_root, int y_root )
1452  {
1453  Options::MouseCommand com = Options::MouseNothing;
1454  bool active = isActive();
1455  if ( !wantsInput() ) // we cannot be active, use it anyway
1456  active = TRUE;
1457 
1458  if ( button == Button1 )
1459  com = active ? options->commandActiveTitlebar1() : options->commandInactiveTitlebar1();
1460  else if ( button == Button2 )
1461  com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2();
1462  else if ( button == Button3 )
1463  com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3();
1464  if( button == Button1
1465  && com != Options::MouseOperationsMenu // actions where it's not possible to get the matching
1466  && com != Options::MouseMinimize ) // mouse release event
1467  {
1468  mode = mousePosition( TQPoint( x, y ));
1469  buttonDown = TRUE;
1470  moveOffset = TQPoint( x, y );
1471  invertedMoveOffset = rect().bottomRight() - moveOffset;
1472  unrestrictedMoveResize = false;
1473  setCursor( mode ); // update to sizeAllCursor if about to move
1474  }
1475  performMouseCommand( com, TQPoint( x_root, y_root ));
1476  }
1477 
1478 // called from decoration
1479 void Client::processMousePressEvent( TQMouseEvent* e )
1480  {
1481  if( e->type() != TQEvent::MouseButtonPress )
1482  {
1483  kdWarning() << "processMousePressEvent()" << endl;
1484  return;
1485  }
1486  int button;
1487  switch( e->button())
1488  {
1489  case TQt::LeftButton:
1490  button = Button1;
1491  break;
1492  case TQt::MidButton:
1493  button = Button2;
1494  break;
1495  case TQt::RightButton:
1496  button = Button3;
1497  break;
1498  default:
1499  return;
1500  }
1501  processDecorationButtonPress( button, e->state(), e->x(), e->y(), e->globalX(), e->globalY());
1502  }
1503 
1504 // return value matters only when filtering events before decoration gets them
1505 bool Client::buttonReleaseEvent( Window w, int /*button*/, int state, int x, int y, int x_root, int y_root )
1506  {
1507  if( w == decorationId() && !buttonDown)
1508  return false;
1509  if( w == wrapperId())
1510  {
1511  XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime ); //tqt_x_time);
1512  return true;
1513  }
1514  if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
1515  return true;
1516  x = this->x(); // translate from grab window to local coords
1517  y = this->y();
1518  if ( (state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 )
1519  {
1520  buttonDown = FALSE;
1521  if ( moveResizeMode )
1522  {
1523  finishMoveResize( false );
1524  // mouse position is still relative to old Client position, adjust it
1525  TQPoint mousepos( x_root - x, y_root - y );
1526  mode = mousePosition( mousepos );
1527  }
1528  setCursor( mode );
1529  }
1530  return true;
1531  }
1532 
1533 static bool was_motion = false;
1534 static Time next_motion_time = CurrentTime;
1535 // Check whole incoming X queue for MotionNotify events
1536 // checking whole queue is done by always returning False in the predicate.
1537 // If there are more MotionNotify events in the queue, all until the last
1538 // one may be safely discarded (if a ButtonRelease event comes, a MotionNotify
1539 // will be faked from it, so there's no need to check other events).
1540 // This helps avoiding being overloaded by being flooded from many events
1541 // from the XServer.
1542 static Bool motion_predicate( Display*, XEvent* ev, XPointer )
1543 {
1544  if( ev->type == MotionNotify )
1545  {
1546  was_motion = true;
1547  next_motion_time = ev->xmotion.time; // for setting time
1548  }
1549  return False;
1550 }
1551 
1552 static bool waitingMotionEvent()
1553  {
1554 // The queue doesn't need to be checked until the X timestamp
1555 // of processes events reaches the timestamp of the last suitable
1556 // MotionNotify event in the queue.
1557  if( next_motion_time != CurrentTime
1558  && timestampCompare( get_tqt_x_time(), next_motion_time ) < 0 )
1559  return true;
1560  was_motion = false;
1561  XSync( tqt_xdisplay(), False ); // this helps to discard more MotionNotify events
1562  XEvent dummy;
1563  XCheckIfEvent( tqt_xdisplay(), &dummy, motion_predicate, NULL );
1564  return was_motion;
1565  }
1566 
1567 // return value matters only when filtering events before decoration gets them
1568 bool Client::motionNotifyEvent( Window w, int /*state*/, int x, int y, int x_root, int y_root )
1569  {
1570  if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
1571  return true; // care only about the whole frame
1572  if ( !buttonDown )
1573  {
1574  Position newmode = mousePosition( TQPoint( x, y ));
1575  if( newmode != mode )
1576  setCursor( newmode );
1577  mode = newmode;
1578  // reset the timestamp for the optimization, otherwise with long passivity
1579  // the option in waitingMotionEvent() may be always true
1580  next_motion_time = CurrentTime;
1581  return false;
1582  }
1583  if( w == moveResizeGrabWindow())
1584  {
1585  x = this->x(); // translate from grab window to local coords
1586  y = this->y();
1587  }
1588  if( !waitingMotionEvent())
1589  handleMoveResize( x, y, x_root, y_root );
1590  return true;
1591  }
1592 
1593 void Client::focusInEvent( XFocusInEvent* e )
1594  {
1595  if( e->window != window())
1596  return; // only window gets focus
1597  if ( e->mode == NotifyUngrab )
1598  return; // we don't care
1599  if ( e->detail == NotifyPointer )
1600  return; // we don't care
1601  if( !isShown( false ) || !isOnCurrentDesktop()) // we unmapped it, but it got focus meanwhile ->
1602  return; // activateNextClient() already transferred focus elsewhere
1603  // check if this client is in should_get_focus list or if activation is allowed
1604  bool activate = workspace()->allowClientActivation( this, -1U, true );
1605  workspace()->gotFocusIn( this ); // remove from should_get_focus list
1606  if( activate )
1607  setActive( TRUE );
1608  else
1609  {
1610  workspace()->restoreFocus();
1611  demandAttention();
1612  }
1613  }
1614 
1615 // When a client loses focus, FocusOut events are usually immediatelly
1616 // followed by FocusIn events for another client that gains the focus
1617 // (unless the focus goes to another screen, or to the nofocus widget).
1618 // Without this check, the former focused client would have to be
1619 // deactivated, and after that, the new one would be activated, with
1620 // a short time when there would be no active client. This can cause
1621 // flicker sometimes, e.g. when a fullscreen is shown, and focus is transferred
1622 // from it to its transient, the fullscreen would be kept in the Active layer
1623 // at the beginning and at the end, but not in the middle, when the active
1624 // client would be temporarily none (see Client::belongToLayer() ).
1625 // Therefore, the events queue is checked, whether it contains the matching
1626 // FocusIn event, and if yes, deactivation of the previous client will
1627 // be skipped, as activation of the new one will automatically deactivate
1628 // previously active client.
1629 static bool follows_focusin = false;
1630 static bool follows_focusin_failed = false;
1631 static Bool predicate_follows_focusin( Display*, XEvent* e, XPointer arg )
1632  {
1633  if( follows_focusin || follows_focusin_failed )
1634  return False;
1635  Client* c = ( Client* ) arg;
1636  if( e->type == FocusIn && c->workspace()->findClient( WindowMatchPredicate( e->xfocus.window )))
1637  { // found FocusIn
1638  follows_focusin = true;
1639  return False;
1640  }
1641  // events that may be in the queue before the FocusIn event that's being
1642  // searched for
1643  if( e->type == FocusIn || e->type == FocusOut || e->type == KeymapNotify )
1644  return False;
1645  follows_focusin_failed = true; // a different event - stop search
1646  return False;
1647  }
1648 
1649 static bool check_follows_focusin( Client* c )
1650  {
1651  follows_focusin = follows_focusin_failed = false;
1652  XEvent dummy;
1653  // XCheckIfEvent() is used to make the search non-blocking, the predicate
1654  // always returns False, so nothing is removed from the events queue.
1655  // XPeekIfEvent() would block.
1656  XCheckIfEvent( tqt_xdisplay(), &dummy, predicate_follows_focusin, (XPointer)c );
1657  return follows_focusin;
1658  }
1659 
1660 
1661 void Client::focusOutEvent( XFocusOutEvent* e )
1662  {
1663  if( e->window != window())
1664  return; // only window gets focus
1665  if ( e->mode == NotifyGrab )
1666  return; // we don't care
1667  if ( isShade() )
1668  return; // here neither
1669  if ( e->detail != NotifyNonlinear
1670  && e->detail != NotifyNonlinearVirtual )
1671  // SELI check all this
1672  return; // hack for motif apps like netscape
1673  if ( TQApplication::activePopupWidget() )
1674  return;
1675  if( !check_follows_focusin( this ))
1676  setActive( FALSE );
1677  }
1678 
1679 // performs _NET_WM_MOVERESIZE
1680 void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction )
1681  {
1682  if( direction == NET::Move )
1683  performMouseCommand( Options::MouseMove, TQPoint( x_root, y_root ));
1684  else if( moveResizeMode && direction == NET::MoveResizeCancel )
1685  {
1686  finishMoveResize( true );
1687  buttonDown = FALSE;
1688  setCursor( mode );
1689  }
1690  else if( direction >= NET::TopLeft && direction <= NET::Left )
1691  {
1692  static const Position convert[] =
1693  {
1694  PositionTopLeft,
1695  PositionTop,
1696  PositionTopRight,
1697  PositionRight,
1698  PositionBottomRight,
1699  PositionBottom,
1700  PositionBottomLeft,
1701  PositionLeft
1702  };
1703  if(!isResizable() || isShade())
1704  return;
1705  if( moveResizeMode )
1706  finishMoveResize( false );
1707  buttonDown = TRUE;
1708  moveOffset = TQPoint( x_root - x(), y_root - y()); // map from global
1709  invertedMoveOffset = rect().bottomRight() - moveOffset;
1710  unrestrictedMoveResize = false;
1711  mode = convert[ direction ];
1712  setCursor( mode );
1713  if( !startMoveResize())
1714  {
1715  buttonDown = false;
1716  setCursor( mode );
1717  }
1718  }
1719  else if( direction == NET::KeyboardMove )
1720  { // ignore mouse coordinates given in the message, mouse position is used by the moving algorithm
1721  TQCursor::setPos( geometry().center() );
1722  performMouseCommand( Options::MouseUnrestrictedMove, geometry().center());
1723  }
1724  else if( direction == NET::KeyboardSize )
1725  { // ignore mouse coordinates given in the message, mouse position is used by the resizing algorithm
1726  TQCursor::setPos( geometry().bottomRight());
1727  performMouseCommand( Options::MouseUnrestrictedResize, geometry().bottomRight());
1728  }
1729  }
1730 
1731 void Client::keyPressEvent( uint key_code )
1732  {
1733  updateUserTime();
1734  if ( !isMove() && !isResize() )
1735  return;
1736  bool is_control = key_code & TQt::CTRL;
1737  bool is_alt = key_code & TQt::ALT;
1738  key_code = key_code & 0xffff;
1739  int delta = is_control?1:is_alt?32:8;
1740  TQPoint pos = TQCursor::pos();
1741  switch ( key_code )
1742  {
1743  case Key_Left:
1744  pos.rx() -= delta;
1745  break;
1746  case Key_Right:
1747  pos.rx() += delta;
1748  break;
1749  case Key_Up:
1750  pos.ry() -= delta;
1751  break;
1752  case Key_Down:
1753  pos.ry() += delta;
1754  break;
1755  case Key_Space:
1756  case Key_Return:
1757  case Key_Enter:
1758  finishMoveResize( false );
1759  buttonDown = FALSE;
1760  setCursor( mode );
1761  break;
1762  case Key_Escape:
1763  finishMoveResize( true );
1764  buttonDown = FALSE;
1765  setCursor( mode );
1766  break;
1767  default:
1768  return;
1769  }
1770  TQCursor::setPos( pos );
1771  }
1772 
1773 // ****************************************
1774 // Group
1775 // ****************************************
1776 
1777 bool Group::groupEvent( XEvent* e )
1778  {
1779  unsigned long dirty[ 2 ];
1780  leader_info->event( e, dirty, 2 ); // pass through the NET stuff
1781  if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
1782  getIcons();
1783  if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
1784  startupIdChanged();
1785  return false;
1786  }
1787 
1788 
1789 } // 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.9.1
This website is maintained by Timothy Pearson.