add more spacing
[personal-kdebase.git] / workspace / kwin / events.cpp
bloba6cc98fac3a996592a030bfcfd01e71b38a39f5e
1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *********************************************************************/
24 This file contains things relevant to handling incoming events.
28 #include <config-X11.h>
30 #include "client.h"
31 #include "workspace.h"
32 #include "atoms.h"
33 #include "tabbox.h"
34 #include "group.h"
35 #include "rules.h"
36 #include "unmanaged.h"
37 #include "scene.h"
38 #include "effects.h"
40 #include <QWhatsThis>
41 #include <QApplication>
43 #include <kkeyserver.h>
45 #include <X11/extensions/shape.h>
46 #include <X11/Xatom.h>
47 #include <QX11Info>
49 #ifdef HAVE_XRANDR
50 #include <X11/extensions/Xrandr.h>
51 #endif
53 namespace KWin
56 // ****************************************
57 // WinInfo
58 // ****************************************
60 WinInfo::WinInfo( Client * c, Display * display, Window window,
61 Window rwin, const unsigned long pr[], int pr_size )
62 : NETWinInfo2( display, window, rwin, pr, pr_size, NET::WindowManager ), m_client( c )
66 void WinInfo::changeDesktop(int desktop)
68 m_client->workspace()->sendClientToDesktop( m_client, desktop, true );
71 void WinInfo::changeFullscreenMonitors( NETFullscreenMonitors topology )
73 m_client->updateFullscreenMonitors( topology );
76 void WinInfo::changeState( unsigned long state, unsigned long mask )
78 mask &= ~NET::Sticky; // KWin doesn't support large desktops, ignore
79 mask &= ~NET::Hidden; // clients are not allowed to change this directly
80 state &= mask; // for safety, clear all other bits
82 if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) == 0 )
83 m_client->setFullScreen( false, false );
84 if ( (mask & NET::Max) == NET::Max )
85 m_client->setMaximize( state & NET::MaxVert, state & NET::MaxHoriz );
86 else if ( mask & NET::MaxVert )
87 m_client->setMaximize( state & NET::MaxVert, m_client->maximizeMode() & Client::MaximizeHorizontal );
88 else if ( mask & NET::MaxHoriz )
89 m_client->setMaximize( m_client->maximizeMode() & Client::MaximizeVertical, state & NET::MaxHoriz );
91 if ( mask & NET::Shaded )
92 m_client->setShade( state & NET::Shaded ? ShadeNormal : ShadeNone );
93 if ( mask & NET::KeepAbove)
94 m_client->setKeepAbove( (state & NET::KeepAbove) != 0 );
95 if ( mask & NET::KeepBelow)
96 m_client->setKeepBelow( (state & NET::KeepBelow) != 0 );
97 if( mask & NET::SkipTaskbar )
98 m_client->setSkipTaskbar( ( state & NET::SkipTaskbar ) != 0, true );
99 if( mask & NET::SkipPager )
100 m_client->setSkipPager( ( state & NET::SkipPager ) != 0 );
101 if( mask & NET::DemandsAttention )
102 m_client->demandAttention(( state & NET::DemandsAttention ) != 0 );
103 if( mask & NET::Modal )
104 m_client->setModal( ( state & NET::Modal ) != 0 );
105 // unsetting fullscreen first, setting it last (because e.g. maximize works only for !isFullScreen() )
106 if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) != 0 )
107 m_client->setFullScreen( true, false );
110 void WinInfo::disable()
112 m_client = NULL; // only used when the object is passed to Deleted
115 // ****************************************
116 // RootInfo
117 // ****************************************
119 RootInfo::RootInfo( Workspace* ws, Display *dpy, Window w, const char *name, unsigned long pr[], int pr_num, int scr )
120 : NETRootInfo( dpy, w, name, pr, pr_num, scr )
122 workspace = ws;
125 void RootInfo::changeNumberOfDesktops(int n)
127 workspace->setNumberOfDesktops( n );
130 void RootInfo::changeCurrentDesktop(int d)
132 workspace->setCurrentDesktop( d );
135 void RootInfo::changeActiveWindow( Window w, NET::RequestSource src, Time timestamp, Window active_window )
137 if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
139 if( timestamp == CurrentTime )
140 timestamp = c->userTime();
141 if( src != NET::FromApplication && src != FromTool )
142 src = NET::FromTool;
143 if( src == NET::FromTool )
144 workspace->activateClient( c, true ); // force
145 else // NET::FromApplication
147 Client* c2;
148 if( workspace->allowClientActivation( c, timestamp, false, true ))
149 workspace->activateClient( c );
150 // if activation of the requestor's window would be allowed, allow activation too
151 else if( active_window != None
152 && ( c2 = workspace->findClient( WindowMatchPredicate( active_window ))) != NULL
153 && workspace->allowClientActivation( c2,
154 timestampCompare( timestamp, c2->userTime() > 0 ? timestamp : c2->userTime()), false, true ))
156 workspace->activateClient( c );
158 else
159 c->demandAttention();
164 void RootInfo::restackWindow( Window w, RequestSource src, Window above, int detail, Time timestamp )
166 if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
168 if( timestamp == CurrentTime )
169 timestamp = c->userTime();
170 if( src != NET::FromApplication && src != FromTool )
171 src = NET::FromTool;
172 c->restackWindow( above, detail, src, timestamp, true );
176 void RootInfo::gotTakeActivity( Window w, Time timestamp, long flags )
178 if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
179 workspace->handleTakeActivity( c, timestamp, flags );
182 void RootInfo::closeWindow(Window w)
184 Client* c = workspace->findClient( WindowMatchPredicate( w ));
185 if ( c )
186 c->closeWindow();
189 void RootInfo::moveResize(Window w, int x_root, int y_root, unsigned long direction)
191 Client* c = workspace->findClient( WindowMatchPredicate( w ));
192 if ( c )
194 updateXTime(); // otherwise grabbing may have old timestamp - this message should include timestamp
195 c->NETMoveResize( x_root, y_root, (Direction)direction);
199 void RootInfo::moveResizeWindow(Window w, int flags, int x, int y, int width, int height )
201 Client* c = workspace->findClient( WindowMatchPredicate( w ));
202 if ( c )
203 c->NETMoveResizeWindow( flags, x, y, width, height );
206 void RootInfo::gotPing( Window w, Time timestamp )
208 if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
209 c->gotPing( timestamp );
212 void RootInfo::changeShowingDesktop( bool showing )
214 workspace->setShowingDesktop( showing );
217 // ****************************************
218 // Workspace
219 // ****************************************
222 Handles workspace specific XEvents
224 bool Workspace::workspaceEvent( XEvent * e )
226 if ( mouse_emulation && (e->type == ButtonPress || e->type == ButtonRelease ) )
228 mouse_emulation = false;
229 ungrabXKeyboard();
231 if( effects && static_cast< EffectsHandlerImpl* >( effects )->hasKeyboardGrab()
232 && ( e->type == KeyPress || e->type == KeyRelease ))
233 return false; // let Qt process it, it'll be intercepted again in eventFilter()
235 if( e->type == PropertyNotify || e->type == ClientMessage )
237 unsigned long dirty[ NETRootInfo::PROPERTIES_SIZE ];
238 rootInfo->event( e, dirty, NETRootInfo::PROPERTIES_SIZE );
239 if( dirty[ NETRootInfo::PROTOCOLS ] & NET::DesktopNames )
240 saveDesktopSettings();
241 if( dirty[ NETRootInfo::PROTOCOLS2 ] & NET::WM2DesktopLayout )
242 updateDesktopLayout();
245 // events that should be handled before Clients can get them
246 switch (e->type)
248 case ButtonPress:
249 case ButtonRelease:
250 was_user_interaction = true;
251 // fallthrough
252 case MotionNotify:
253 if ( tab_grab || control_grab )
255 tab_box->handleMouseEvent( e );
256 return true;
258 if( effects && static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowEvent( e ))
259 return true;
260 break;
261 case KeyPress:
263 was_user_interaction = true;
264 int keyQt;
265 KKeyServer::xEventToQt(e, &keyQt);
266 // kDebug(125) << "Workspace::keyPress( " << keyQt << " )";
267 if (movingClient)
269 movingClient->keyPressEvent(keyQt);
270 return true;
272 if( tab_grab || control_grab )
274 tabBoxKeyPress( keyQt );
275 return true;
277 break;
279 case KeyRelease:
280 was_user_interaction = true;
281 if( tab_grab || control_grab )
283 tabBoxKeyRelease( e->xkey );
284 return true;
286 break;
287 case ConfigureNotify:
288 if( e->xconfigure.event == rootWindow())
289 x_stacking_dirty = true;
290 break;
293 if( Client* c = findClient( WindowMatchPredicate( e->xany.window )))
295 if( c->windowEvent( e ))
296 return true;
298 else if( Client* c = findClient( WrapperIdMatchPredicate( e->xany.window )))
300 if( c->windowEvent( e ))
301 return true;
303 else if( Client* c = findClient( FrameIdMatchPredicate( e->xany.window )))
305 if( c->windowEvent( e ))
306 return true;
308 else if( Unmanaged* c = findUnmanaged( WindowMatchPredicate( e->xany.window )))
310 if( c->windowEvent( e ))
311 return true;
313 else
315 Window special = findSpecialEventWindow( e );
316 if( special != None )
317 if( Client* c = findClient( WindowMatchPredicate( special )))
319 if( c->windowEvent( e ))
320 return true;
323 if( movingClient != NULL && movingClient->moveResizeGrabWindow() == e->xany.window
324 && ( e->type == MotionNotify || e->type == ButtonPress || e->type == ButtonRelease ))
326 if( movingClient->windowEvent( e ))
327 return true;
330 switch (e->type)
332 case CreateNotify:
333 if ( e->xcreatewindow.parent == rootWindow() &&
334 !QWidget::find( e->xcreatewindow.window) &&
335 !e->xcreatewindow.override_redirect )
337 // see comments for allowClientActivation()
338 Time t = xTime();
339 XChangeProperty(display(), e->xcreatewindow.window,
340 atoms->kde_net_wm_user_creation_time, XA_CARDINAL,
341 32, PropModeReplace, (unsigned char *)&t, 1);
343 break;
345 case UnmapNotify:
347 return ( e->xunmap.event != e->xunmap.window ); // hide wm typical event from Qt
349 case ReparentNotify:
351 //do not confuse Qt with these events. After all, _we_ are the
352 //window manager who does the reparenting.
353 return true;
355 case DestroyNotify:
357 return false;
359 case MapRequest:
361 updateXTime();
363 // e->xmaprequest.window is different from e->xany.window
364 // TODO this shouldn't be necessary now
365 Client* c = findClient( WindowMatchPredicate( e->xmaprequest.window ));
366 if ( !c )
368 // don't check for the parent being the root window, this breaks when some app unmaps
369 // a window, changes something and immediately maps it back, without giving KWin
370 // a chance to reparent it back to root
371 // since KWin can get MapRequest only for root window children and
372 // children of WindowWrapper (=clients), the check is AFAIK useless anyway
373 // Note: Now the save-set support in Client::mapRequestEvent() actually requires that
374 // this code doesn't check the parent to be root.
375 // if ( e->xmaprequest.parent == root ) {
376 c = createClient( e->xmaprequest.window, false );
377 if( c == NULL ) // refused to manage, simply map it (most probably override redirect)
378 XMapRaised( display(), e->xmaprequest.window );
379 return true;
381 if( c )
383 c->windowEvent( e );
384 updateFocusChains( c, FocusChainUpdate );
385 return true;
387 break;
389 case MapNotify:
391 if( e->xmap.override_redirect )
393 Unmanaged* c = findUnmanaged( WindowMatchPredicate( e->xmap.window ));
394 if( c == NULL )
395 c = createUnmanaged( e->xmap.window );
396 if( c )
397 return c->windowEvent( e );
399 return ( e->xmap.event != e->xmap.window ); // hide wm typical event from Qt
402 case EnterNotify:
404 if ( QWhatsThis::inWhatsThisMode() )
406 QWidget* w = QWidget::find( e->xcrossing.window );
407 if ( w )
408 QWhatsThis::leaveWhatsThisMode();
410 if( electricBorderEvent(e))
411 return true;
412 break;
414 case LeaveNotify:
416 if ( !QWhatsThis::inWhatsThisMode() )
417 break;
418 // TODO is this cliente ever found, given that client events are searched above?
419 Client* c = findClient( FrameIdMatchPredicate( e->xcrossing.window ));
420 if ( c && e->xcrossing.detail != NotifyInferior )
421 QWhatsThis::leaveWhatsThisMode();
422 break;
424 case ConfigureRequest:
426 if ( e->xconfigurerequest.parent == rootWindow())
428 XWindowChanges wc;
429 wc.border_width = e->xconfigurerequest.border_width;
430 wc.x = e->xconfigurerequest.x;
431 wc.y = e->xconfigurerequest.y;
432 wc.width = e->xconfigurerequest.width;
433 wc.height = e->xconfigurerequest.height;
434 wc.sibling = None;
435 wc.stack_mode = Above;
436 unsigned int value_mask = e->xconfigurerequest.value_mask
437 & ( CWX | CWY | CWWidth | CWHeight | CWBorderWidth );
438 XConfigureWindow( display(), e->xconfigurerequest.window, value_mask, &wc );
439 return true;
441 break;
443 case KeyPress:
444 if ( mouse_emulation )
445 return keyPressMouseEmulation( e->xkey );
446 break;
447 case KeyRelease:
448 if ( mouse_emulation )
449 return false;
450 break;
451 case FocusIn:
452 if( e->xfocus.window == rootWindow()
453 && ( e->xfocus.detail == NotifyDetailNone || e->xfocus.detail == NotifyPointerRoot ))
455 updateXTime(); // focusToNull() uses xTime(), which is old now (FocusIn has no timestamp)
456 Window focus;
457 int revert;
458 XGetInputFocus( display(), &focus, &revert );
459 if( focus == None || focus == PointerRoot )
461 //kWarning( 1212 ) << "X focus set to None/PointerRoot, reseting focus" ;
462 Client *c = mostRecentlyActivatedClient();
463 if( c != NULL )
464 requestFocus( c, true );
465 else if( activateNextClient( NULL ))
466 ; // ok, activated
467 else
468 focusToNull();
471 // fall through
472 case FocusOut:
473 return true; // always eat these, they would tell Qt that KWin is the active app
474 case ClientMessage:
475 if( electricBorderEvent( e ))
476 return true;
477 break;
478 case Expose:
479 if( compositing()
480 && ( e->xexpose.window == rootWindow() // root window needs repainting
481 || overlay != None && e->xexpose.window == overlay )) // overlay needs repainting
483 addRepaint( e->xexpose.x, e->xexpose.y, e->xexpose.width, e->xexpose.height );
485 break;
486 case VisibilityNotify:
487 if( compositing() && overlay != None && e->xvisibility.window == overlay )
489 bool was_visible = overlay_visible;
490 overlay_visible = ( e->xvisibility.state != VisibilityFullyObscured );
491 if( !was_visible && overlay_visible )
492 { // hack for #154825
493 addRepaintFull();
494 QTimer::singleShot( 2000, this, SLOT( addRepaintFull()));
496 checkCompositeTimer();
498 break;
499 default:
500 if( e->type == Extensions::randrNotifyEvent() && Extensions::randrAvailable() )
502 #ifdef HAVE_XRANDR
503 XRRUpdateConfiguration( e );
504 #endif
505 if( compositing() )
507 // desktopResized() should take care of when the size or
508 // shape of the desktop has changed, but we also want to
509 // catch refresh rate changes
510 finishCompositing();
511 QTimer::singleShot( 0, this, SLOT( setupCompositing() ) );
514 else if( e->type == Extensions::syncAlarmNotifyEvent() && Extensions::syncAvailable())
516 #ifdef HAVE_XSYNC
517 foreach( Client* c, clients )
518 c->syncEvent( reinterpret_cast< XSyncAlarmNotifyEvent* >( e ));
519 foreach( Client* c, desktops )
520 c->syncEvent( reinterpret_cast< XSyncAlarmNotifyEvent* >( e ));
521 #endif
523 break;
525 return false;
528 // Used only to filter events that need to be processed by Qt first
529 // (e.g. keyboard input to be composed), otherwise events are
530 // handle by the XEvent filter above
531 bool Workspace::workspaceEvent( QEvent* e )
533 if(( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease || e->type() == QEvent::ShortcutOverride )
534 && effects && static_cast< EffectsHandlerImpl* >( effects )->hasKeyboardGrab())
536 static_cast< EffectsHandlerImpl* >( effects )->grabbedKeyboardEvent( static_cast< QKeyEvent* >( e ));
537 return true;
539 return false;
542 // Some events don't have the actual window which caused the event
543 // as e->xany.window (e.g. ConfigureRequest), but as some other
544 // field in the XEvent structure.
545 Window Workspace::findSpecialEventWindow( XEvent* e )
547 switch( e->type )
549 case CreateNotify:
550 return e->xcreatewindow.window;
551 case DestroyNotify:
552 return e->xdestroywindow.window;
553 case UnmapNotify:
554 return e->xunmap.window;
555 case MapNotify:
556 return e->xmap.window;
557 case MapRequest:
558 return e->xmaprequest.window;
559 case ReparentNotify:
560 return e->xreparent.window;
561 case ConfigureNotify:
562 return e->xconfigure.window;
563 case GravityNotify:
564 return e->xgravity.window;
565 case ConfigureRequest:
566 return e->xconfigurerequest.window;
567 case CirculateNotify:
568 return e->xcirculate.window;
569 case CirculateRequest:
570 return e->xcirculaterequest.window;
571 default:
572 return None;
576 // ****************************************
577 // Client
578 // ****************************************
581 General handler for XEvents concerning the client window
583 bool Client::windowEvent( XEvent* e )
585 if( e->xany.window == window()) // avoid doing stuff on frame or wrapper
587 unsigned long dirty[ 2 ];
588 double old_opacity = opacity();
589 info->event( e, dirty, 2 ); // pass through the NET stuff
591 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMName ) != 0 )
592 fetchName();
593 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconName ) != 0 )
594 fetchIconicName();
595 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMStrut ) != 0
596 || ( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2ExtendedStrut ) != 0 )
598 if( isTopMenu()) // the fallback mode of KMenuBar may alter the strut
599 checkWorkspacePosition(); // restore it
600 workspace()->updateClientArea();
602 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
603 getIcons();
604 // Note there's a difference between userTime() and info->userTime()
605 // info->userTime() is the value of the property, userTime() also includes
606 // updates of the time done by KWin (ButtonPress on windowrapper etc.).
607 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2UserTime ) != 0 )
609 workspace()->setWasUserInteraction();
610 updateUserTime( info->userTime());
612 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
613 startupIdChanged();
614 if( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconGeometry )
616 if( demandAttentionKNotifyTimer != NULL )
617 demandAttentionKNotify();
619 if( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2Opacity )
621 if( compositing())
623 addRepaintFull();
624 scene->windowOpacityChanged( this );
625 if( effects )
626 static_cast<EffectsHandlerImpl*>(effects)->windowOpacityChanged( effectWindow(), old_opacity );
628 else
629 { // forward to the frame if there's possibly another compositing manager running
630 NETWinInfo2 i( display(), frameId(), rootWindow(), 0 );
631 i.setOpacity( info->opacity());
636 switch (e->type)
638 case UnmapNotify:
639 unmapNotifyEvent( &e->xunmap );
640 break;
641 case DestroyNotify:
642 destroyNotifyEvent( &e->xdestroywindow );
643 break;
644 case MapRequest:
645 // this one may pass the event to workspace
646 return mapRequestEvent( &e->xmaprequest );
647 case ConfigureRequest:
648 configureRequestEvent( &e->xconfigurerequest );
649 break;
650 case PropertyNotify:
651 propertyNotifyEvent( &e->xproperty );
652 break;
653 case KeyPress:
654 updateUserTime();
655 workspace()->setWasUserInteraction();
656 break;
657 case ButtonPress:
658 updateUserTime();
659 workspace()->setWasUserInteraction();
660 buttonPressEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
661 e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
662 break;
663 case KeyRelease:
664 // don't update user time on releases
665 // e.g. if the user presses Alt+F2, the Alt release
666 // would appear as user input to the currently active window
667 break;
668 case ButtonRelease:
669 // don't update user time on releases
670 // e.g. if the user presses Alt+F2, the Alt release
671 // would appear as user input to the currently active window
672 buttonReleaseEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
673 e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
674 break;
675 case MotionNotify:
676 motionNotifyEvent( e->xmotion.window, e->xmotion.state,
677 e->xmotion.x, e->xmotion.y, e->xmotion.x_root, e->xmotion.y_root );
678 workspace()->updateFocusMousePosition( QPoint( e->xmotion.x_root, e->xmotion.y_root ));
679 break;
680 case EnterNotify:
681 enterNotifyEvent( &e->xcrossing );
682 // MotionNotify is guaranteed to be generated only if the mouse
683 // move start and ends in the window; for cases when it only
684 // starts or only ends there, Enter/LeaveNotify are generated.
685 // Fake a MotionEvent in such cases to make handle of mouse
686 // events simpler (Qt does that too).
687 motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
688 e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
689 workspace()->updateFocusMousePosition( QPoint( e->xcrossing.x_root, e->xcrossing.y_root ));
690 break;
691 case LeaveNotify:
692 motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
693 e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
694 leaveNotifyEvent( &e->xcrossing );
695 // not here, it'd break following enter notify handling
696 // workspace()->updateFocusMousePosition( QPoint( e->xcrossing.x_root, e->xcrossing.y_root ));
697 break;
698 case FocusIn:
699 focusInEvent( &e->xfocus );
700 break;
701 case FocusOut:
702 focusOutEvent( &e->xfocus );
703 break;
704 case ReparentNotify:
705 break;
706 case ClientMessage:
707 clientMessageEvent( &e->xclient );
708 break;
709 case ColormapChangeMask:
710 if( e->xany.window == window())
712 cmap = e->xcolormap.colormap;
713 if ( isActive() )
714 workspace()->updateColormap();
716 break;
717 default:
718 if( e->xany.window == window())
720 if( e->type == Extensions::shapeNotifyEvent() )
722 detectShape( window()); // workaround for #19644
723 updateShape();
726 if( e->xany.window == frameId())
728 #ifdef HAVE_XDAMAGE
729 if( e->type == Extensions::damageNotifyEvent())
730 damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent* >( e ));
731 #endif
733 break;
735 return true; // eat all events
739 Handles map requests of the client window
741 bool Client::mapRequestEvent( XMapRequestEvent* e )
743 if( e->window != window())
745 // Special support for the save-set feature, which is a bit broken.
746 // If there's a window from one client embedded in another one,
747 // e.g. using XEMBED, and the embedder suddenly looses its X connection,
748 // save-set will reparent the embedded window to its closest ancestor
749 // that will remains. Unfortunately, with reparenting window managers,
750 // this is not the root window, but the frame (or in KWin's case,
751 // it's the wrapper for the client window). In this case,
752 // the wrapper will get ReparentNotify for a window it won't know,
753 // which will be ignored, and then it gets MapRequest, as save-set
754 // always maps. Returning true here means that Workspace::workspaceEvent()
755 // will handle this MapRequest and manage this window (i.e. act as if
756 // it was reparented to root window).
757 if( e->parent == wrapperId())
758 return false;
759 return true; // no messing with frame etc.
761 if( isTopMenu() && workspace()->managingTopMenus())
762 return true; // kwin controls these
763 // also copied in clientMessage()
764 if( isMinimized())
765 unminimize();
766 if( isShade())
767 setShade( ShadeNone );
768 if( !isOnCurrentDesktop())
770 if( workspace()->allowClientActivation( this ))
771 workspace()->activateClient( this );
772 else
773 demandAttention();
775 return true;
779 Handles unmap notify events of the client window
781 void Client::unmapNotifyEvent( XUnmapEvent* e )
783 if( e->window != window())
784 return;
785 if( e->event != wrapperId())
786 { // most probably event from root window when initially reparenting
787 bool ignore = true;
788 if( e->event == rootWindow() && e->send_event )
789 ignore = false; // XWithdrawWindow()
790 if( ignore )
791 return;
793 releaseWindow();
796 void Client::destroyNotifyEvent( XDestroyWindowEvent* e )
798 if( e->window != window())
799 return;
800 destroyClient();
805 Handles client messages for the client window
807 void Client::clientMessageEvent( XClientMessageEvent* e )
809 if( e->window != window())
810 return; // ignore frame/wrapper
811 // WM_STATE
812 if ( e->message_type == atoms->kde_wm_change_state )
814 if( isTopMenu() && workspace()->managingTopMenus())
815 return; // kwin controls these
816 bool avoid_animation = ( e->data.l[ 1 ] );
817 if( e->data.l[ 0 ] == IconicState )
818 minimize();
819 else if( e->data.l[ 0 ] == NormalState )
820 { // copied from mapRequest()
821 if( isMinimized())
822 unminimize( avoid_animation );
823 if( isShade())
824 setShade( ShadeNone );
825 if( !isOnCurrentDesktop())
827 if( workspace()->allowClientActivation( this ))
828 workspace()->activateClient( this );
829 else
830 demandAttention();
834 else if ( e->message_type == atoms->wm_change_state)
836 if( isTopMenu() && workspace()->managingTopMenus())
837 return; // kwin controls these
838 if ( e->data.l[0] == IconicState )
839 minimize();
840 return;
846 Handles configure requests of the client window
848 void Client::configureRequestEvent( XConfigureRequestEvent* e )
850 if( e->window != window())
851 return; // ignore frame/wrapper
852 if ( isResize() || isMove())
853 return; // we have better things to do right now
855 if( fullscreen_mode == FullScreenNormal ) // refuse resizing of fullscreen windows
856 { // but allow resizing fullscreen hacks in order to let them cancel fullscreen mode
857 sendSyntheticConfigureNotify();
858 return;
860 if( isSplash() // no manipulations with splashscreens either
861 || isTopMenu()) // topmenus neither
863 sendSyntheticConfigureNotify();
864 return;
867 if ( e->value_mask & CWBorderWidth )
869 // first, get rid of a window border
870 XWindowChanges wc;
871 unsigned int value_mask = 0;
873 wc.border_width = 0;
874 value_mask = CWBorderWidth;
875 XConfigureWindow( display(), window(), value_mask, & wc );
878 if( e->value_mask & ( CWX | CWY | CWHeight | CWWidth ))
879 configureRequest( e->value_mask, e->x, e->y, e->width, e->height, 0, false );
881 if ( e->value_mask & CWStackMode )
882 restackWindow( e->above, e->detail, NET::FromApplication, userTime(), false );
884 // Sending a synthetic configure notify always is fine, even in cases where
885 // the ICCCM doesn't require this - it can be though of as 'the WM decided to move
886 // the window later'. The client should not cause that many configure request,
887 // so this should not have any significant impact. With user moving/resizing
888 // the it should be optimized though (see also Client::setGeometry()/plainResize()/move()).
889 sendSyntheticConfigureNotify();
891 // SELI TODO accept configure requests for isDesktop windows (because kdesktop
892 // may get XRANDR resize event before kwin), but check it's still at the bottom?
897 Handles property changes of the client window
899 void Client::propertyNotifyEvent( XPropertyEvent* e )
901 Toplevel::propertyNotifyEvent( e );
902 if( e->window != window())
903 return; // ignore frame/wrapper
904 switch ( e->atom )
906 case XA_WM_NORMAL_HINTS:
907 getWmNormalHints();
908 break;
909 case XA_WM_NAME:
910 fetchName();
911 break;
912 case XA_WM_ICON_NAME:
913 fetchIconicName();
914 break;
915 case XA_WM_TRANSIENT_FOR:
916 readTransient();
917 break;
918 case XA_WM_HINTS:
919 getWMHints();
920 getIcons(); // because KWin::icon() uses WMHints as fallback
921 break;
922 default:
923 if ( e->atom == atoms->wm_protocols )
924 getWindowProtocols();
925 else if( e->atom == atoms->motif_wm_hints )
926 getMotifHints();
927 else if( e->atom == atoms->net_wm_sync_request_counter )
928 getSyncCounter();
929 break;
934 void Client::enterNotifyEvent( XCrossingEvent* e )
936 if( e->window != frameId())
937 return; // care only about entering the whole frame
938 if( e->mode == NotifyNormal ||
939 ( !options->focusPolicyIsReasonable() &&
940 e->mode == NotifyUngrab ) )
943 if ( options->shadeHover )
945 cancelShadeHoverTimer();
946 if (isShade())
948 shadeHoverTimer = new QTimer( this );
949 connect( shadeHoverTimer, SIGNAL( timeout() ), this, SLOT( shadeHover() ));
950 shadeHoverTimer->setSingleShot( true );
951 shadeHoverTimer->start( options->shadeHoverInterval );
955 if ( options->focusPolicy == Options::ClickToFocus )
956 return;
958 if ( options->autoRaise && !isDesktop() &&
959 !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() &&
960 workspace()->topClientOnDesktop( workspace()->currentDesktop(),
961 options->separateScreenFocus ? screen() : -1 ) != this )
963 delete autoRaiseTimer;
964 autoRaiseTimer = new QTimer( this );
965 connect( autoRaiseTimer, SIGNAL( timeout() ), this, SLOT( autoRaise() ) );
966 autoRaiseTimer->setSingleShot( true );
967 autoRaiseTimer->start( options->autoRaiseInterval );
970 QPoint currentPos( e->x_root, e->y_root );
971 if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isTopMenu() ) )
972 return;
973 // for FocusFollowsMouse, change focus only if the mouse has actually been moved, not if the focus
974 // change came because of window changes (e.g. closing a window) - #92290
975 if( options->focusPolicy != Options::FocusFollowsMouse
976 || currentPos != workspace()->focusMousePosition())
978 if ( options->delayFocus )
979 workspace()->requestDelayFocus( this );
980 else
981 workspace()->requestFocus( this );
983 return;
987 void Client::leaveNotifyEvent( XCrossingEvent* e )
989 if( e->window != frameId())
990 return; // care only about leaving the whole frame
991 if ( e->mode == NotifyNormal )
993 if ( !buttonDown )
995 mode = PositionCenter;
996 updateCursor();
998 bool lostMouse = !rect().contains( QPoint( e->x, e->y ) );
999 // 'lostMouse' wouldn't work with e.g. B2 or Keramik, which have non-rectangular decorations
1000 // (i.e. the LeaveNotify event comes before leaving the rect and no LeaveNotify event
1001 // comes after leaving the rect) - so lets check if the pointer is really outside the window
1003 // TODO this still sucks if a window appears above this one - it should lose the mouse
1004 // if this window is another client, but not if it's a popup ... maybe after KDE3.1 :(
1005 // (repeat after me 'AARGHL!')
1006 if ( !lostMouse && e->detail != NotifyInferior )
1008 int d1, d2, d3, d4;
1009 unsigned int d5;
1010 Window w, child;
1011 if( XQueryPointer( display(), frameId(), &w, &child, &d1, &d2, &d3, &d4, &d5 ) == False
1012 || child == None )
1013 lostMouse = true; // really lost the mouse
1015 if ( lostMouse )
1017 cancelAutoRaise();
1018 workspace()->cancelDelayFocus();
1019 cancelShadeHoverTimer();
1020 if ( shade_mode == ShadeHover && !moveResizeMode && !buttonDown )
1022 shadeHoverTimer = new QTimer( this );
1023 connect( shadeHoverTimer, SIGNAL( timeout() ), this, SLOT( shadeUnhover() ));
1024 shadeHoverTimer->setSingleShot( true );
1025 shadeHoverTimer->start( options->shadeHoverInterval );
1028 if ( options->focusPolicy == Options::FocusStrictlyUnderMouse )
1029 if ( isActive() && lostMouse )
1030 workspace()->requestFocus( 0 ) ;
1031 return;
1035 #define XCapL KKeyServer::modXLock()
1036 #define XNumL KKeyServer::modXNumLock()
1037 #define XScrL KKeyServer::modXScrollLock()
1038 void Client::grabButton( int modifier )
1040 unsigned int mods[ 8 ] =
1042 0, XCapL, XNumL, XNumL | XCapL,
1043 XScrL, XScrL | XCapL,
1044 XScrL | XNumL, XScrL | XNumL | XCapL
1046 for( int i = 0;
1047 i < 8;
1048 ++i )
1049 XGrabButton( display(), AnyButton,
1050 modifier | mods[ i ],
1051 wrapperId(), false, ButtonPressMask,
1052 GrabModeSync, GrabModeAsync, None, None );
1055 void Client::ungrabButton( int modifier )
1057 unsigned int mods[ 8 ] =
1059 0, XCapL, XNumL, XNumL | XCapL,
1060 XScrL, XScrL | XCapL,
1061 XScrL | XNumL, XScrL | XNumL | XCapL
1063 for( int i = 0;
1064 i < 8;
1065 ++i )
1066 XUngrabButton( display(), AnyButton,
1067 modifier | mods[ i ], wrapperId());
1069 #undef XCapL
1070 #undef XNumL
1071 #undef XScrL
1074 Releases the passive grab for some modifier combinations when a
1075 window becomes active. This helps broken X programs that
1076 missinterpret LeaveNotify events in grab mode to work properly
1077 (Motif, AWT, Tk, ...)
1079 void Client::updateMouseGrab()
1081 if( workspace()->globalShortcutsDisabled())
1083 XUngrabButton( display(), AnyButton, AnyModifier, wrapperId());
1084 // keep grab for the simple click without modifiers if needed (see below)
1085 bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), -1, true, false ) == this;
1086 if( !( !options->clickRaise || not_obscured ))
1087 grabButton( None );
1088 return;
1090 if( isActive() && !workspace()->forcedGlobalMouseGrab()) // see Workspace::establishTabBoxGrab()
1092 // first grab all modifier combinations
1093 XGrabButton( display(), AnyButton, AnyModifier, wrapperId(), false,
1094 ButtonPressMask,
1095 GrabModeSync, GrabModeAsync,
1096 None, None );
1097 // remove the grab for no modifiers only if the window
1098 // is unobscured or if the user doesn't want click raise
1099 // (it is unobscured if it the topmost in the unconstrained stacking order, i.e. it is
1100 // the most recently raised window)
1101 bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), -1, true, false ) == this;
1102 if( !options->clickRaise || not_obscured )
1103 ungrabButton( None );
1104 else
1105 grabButton( None );
1106 ungrabButton( ShiftMask );
1107 ungrabButton( ControlMask );
1108 ungrabButton( ControlMask | ShiftMask );
1110 else
1112 XUngrabButton( display(), AnyButton, AnyModifier, wrapperId());
1113 // simply grab all modifier combinations
1114 XGrabButton(display(), AnyButton, AnyModifier, wrapperId(), false,
1115 ButtonPressMask,
1116 GrabModeSync, GrabModeAsync,
1117 None, None );
1121 // Qt propagates mouse events up the widget hierachy, which means events
1122 // for the decoration window cannot be (easily) intercepted as X11 events
1123 bool Client::eventFilter( QObject* o, QEvent* e )
1125 if( decoration == NULL
1126 || o != decoration->widget())
1127 return false;
1128 if( e->type() == QEvent::MouseButtonPress )
1130 QMouseEvent* ev = static_cast< QMouseEvent* >( e );
1131 return buttonPressEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->buttons(), ev->modifiers() ),
1132 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1134 if( e->type() == QEvent::MouseButtonRelease )
1136 QMouseEvent* ev = static_cast< QMouseEvent* >( e );
1137 return buttonReleaseEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->buttons(), ev->modifiers() ),
1138 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1140 if( e->type() == QEvent::MouseMove ) // FRAME i fake z enter/leave?
1142 QMouseEvent* ev = static_cast< QMouseEvent* >( e );
1143 return motionNotifyEvent( decorationId(), qtToX11State( ev->buttons(), ev->modifiers() ),
1144 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1146 if( e->type() == QEvent::Wheel )
1148 QWheelEvent* ev = static_cast< QWheelEvent* >( e );
1149 bool r = buttonPressEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->buttons(), ev->modifiers() ),
1150 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1151 r = r || buttonReleaseEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->buttons(), ev->modifiers() ),
1152 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1153 return r;
1155 if( e->type() == QEvent::Resize )
1157 QResizeEvent* ev = static_cast< QResizeEvent* >( e );
1158 // Filter out resize events that inform about size different than frame size.
1159 // This will ensure that decoration->width() etc. and decoration->widget()->width() will be in sync.
1160 // These events only seem to be delayed events from initial resizing before show() was called
1161 // on the decoration widget.
1162 if( ev->size() != size())
1163 return true;
1164 // HACK: Avoid decoration redraw delays. On resize Qt sets WA_WStateConfigPending
1165 // which delays all painting until a matching ConfigureNotify event comes.
1166 // But this process itself is the window manager, so it's not needed
1167 // to wait for that event, the geometry is known.
1168 // Note that if Qt in the future changes how this flag is handled and what it
1169 // triggers then this may potentionally break things. See mainly QETWidget::translateConfigEvent().
1170 decoration->widget()->setAttribute( Qt::WA_WState_ConfigPending, false );
1171 decoration->widget()->update();
1172 return false;
1174 return false;
1177 // return value matters only when filtering events before decoration gets them
1178 bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root )
1180 if (buttonDown)
1182 if( w == wrapperId())
1183 XAllowEvents(display(), SyncPointer, CurrentTime ); //xTime());
1184 return true;
1187 if( w == wrapperId() || w == frameId() || w == decorationId())
1188 { // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace
1189 updateUserTime();
1190 workspace()->setWasUserInteraction();
1191 uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ?
1192 KKeyServer::modXMeta() :
1193 KKeyServer::modXAlt();
1194 bool bModKeyHeld = keyModX != 0 && ( state & KKeyServer::accelModMaskX()) == keyModX;
1196 if( isSplash()
1197 && button == Button1 && !bModKeyHeld )
1198 { // hide splashwindow if the user clicks on it
1199 hideClient( true );
1200 if( w == wrapperId())
1201 XAllowEvents(display(), SyncPointer, CurrentTime ); //xTime());
1202 return true;
1205 Options::MouseCommand com = Options::MouseNothing;
1206 bool was_action = false;
1207 bool perform_handled = false;
1208 if ( bModKeyHeld )
1210 was_action = true;
1211 switch (button)
1213 case Button1:
1214 com = options->commandAll1();
1215 break;
1216 case Button2:
1217 com = options->commandAll2();
1218 break;
1219 case Button3:
1220 com = options->commandAll3();
1221 break;
1222 case Button4:
1223 case Button5:
1224 com = options->operationWindowMouseWheel( button == Button4 ? 120 : -120 );
1225 break;
1228 else
1229 { // inactive inner window
1230 if( !isActive() && w == wrapperId() && button < 4 )
1232 was_action = true;
1233 perform_handled = true;
1234 switch (button)
1236 case Button1:
1237 com = options->commandWindow1();
1238 break;
1239 case Button2:
1240 com = options->commandWindow2();
1241 break;
1242 case Button3:
1243 com = options->commandWindow3();
1244 break;
1247 // active inner window
1248 if( isActive() && w == wrapperId()
1249 && options->clickRaise && button < 4 ) // exclude wheel
1251 com = Options::MouseActivateRaiseAndPassClick;
1252 was_action = true;
1253 perform_handled = true;
1256 if( was_action )
1258 bool replay = performMouseCommand( com, QPoint( x_root, y_root), perform_handled );
1260 if ( isSpecialWindow())
1261 replay = true;
1263 if( w == wrapperId()) // these can come only from a grab
1264 XAllowEvents(display(), replay? ReplayPointer : SyncPointer, CurrentTime ); //xTime());
1265 return true;
1269 if( w == wrapperId()) // these can come only from a grab
1271 XAllowEvents(display(), ReplayPointer, CurrentTime ); //xTime());
1272 return true;
1274 if( w == decorationId())
1275 return false; // don't eat decoration events
1276 if( w == frameId())
1277 processDecorationButtonPress( button, state, x, y, x_root, y_root );
1278 return true;
1282 // this function processes button press events only after decoration decides not to handle them,
1283 // unlike buttonPressEvent(), which (when the window is decoration) filters events before decoration gets them
1284 void Client::processDecorationButtonPress( int button, int /*state*/, int x, int y, int x_root, int y_root )
1286 Options::MouseCommand com = Options::MouseNothing;
1287 bool active = isActive();
1288 if ( !wantsInput() ) // we cannot be active, use it anyway
1289 active = true;
1291 if ( button == Button1 )
1292 com = active ? options->commandActiveTitlebar1() : options->commandInactiveTitlebar1();
1293 else if ( button == Button2 )
1294 com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2();
1295 else if ( button == Button3 )
1296 com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3();
1297 if( button == Button1
1298 && com != Options::MouseOperationsMenu // actions where it's not possible to get the matching
1299 && com != Options::MouseMinimize ) // mouse release event
1301 mode = mousePosition( QPoint( x, y ));
1302 buttonDown = true;
1303 moveOffset = QPoint( x, y );
1304 invertedMoveOffset = rect().bottomRight() - moveOffset;
1305 unrestrictedMoveResize = false;
1306 startDelayedMoveResize();
1307 updateCursor();
1309 performMouseCommand( com, QPoint( x_root, y_root ));
1312 // called from decoration
1313 void Client::processMousePressEvent( QMouseEvent* e )
1315 if( e->type() != QEvent::MouseButtonPress )
1317 kWarning(1212) << "processMousePressEvent()" ;
1318 return;
1320 int button;
1321 switch( e->button())
1323 case Qt::LeftButton:
1324 button = Button1;
1325 break;
1326 case Qt::MidButton:
1327 button = Button2;
1328 break;
1329 case Qt::RightButton:
1330 button = Button3;
1331 break;
1332 default:
1333 return;
1335 processDecorationButtonPress( button, e->buttons(), e->x(), e->y(), e->globalX(), e->globalY());
1338 // return value matters only when filtering events before decoration gets them
1339 bool Client::buttonReleaseEvent( Window w, int /*button*/, int state, int x, int y, int x_root, int y_root )
1341 if( w == decorationId() && !buttonDown)
1342 return false;
1343 if( w == wrapperId())
1345 XAllowEvents(display(), SyncPointer, CurrentTime ); //xTime());
1346 return true;
1348 if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
1349 return true;
1350 x = this->x(); // translate from grab window to local coords
1351 y = this->y();
1352 if ( (state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 )
1354 buttonDown = false;
1355 stopDelayedMoveResize();
1356 if ( moveResizeMode )
1358 finishMoveResize( false );
1359 // mouse position is still relative to old Client position, adjust it
1360 QPoint mousepos( x_root - x, y_root - y );
1361 mode = mousePosition( mousepos );
1363 updateCursor();
1365 return true;
1368 static bool was_motion = false;
1369 static Time next_motion_time = CurrentTime;
1370 // Check whole incoming X queue for MotionNotify events
1371 // checking whole queue is done by always returning False in the predicate.
1372 // If there are more MotionNotify events in the queue, all until the last
1373 // one may be safely discarded (if a ButtonRelease event comes, a MotionNotify
1374 // will be faked from it, so there's no need to check other events).
1375 // This helps avoiding being overloaded by being flooded from many events
1376 // from the XServer.
1377 static Bool motion_predicate( Display*, XEvent* ev, XPointer )
1379 if( ev->type == MotionNotify )
1381 was_motion = true;
1382 next_motion_time = ev->xmotion.time; // for setting time
1384 return False;
1387 static bool waitingMotionEvent()
1389 // The queue doesn't need to be checked until the X timestamp
1390 // of processes events reaches the timestamp of the last suitable
1391 // MotionNotify event in the queue.
1392 if( next_motion_time != CurrentTime
1393 && timestampCompare( xTime(), next_motion_time ) < 0 )
1394 return true;
1395 was_motion = false;
1396 XSync( display(), False ); // this helps to discard more MotionNotify events
1397 XEvent dummy;
1398 XCheckIfEvent( display(), &dummy, motion_predicate, NULL );
1399 return was_motion;
1402 // return value matters only when filtering events before decoration gets them
1403 bool Client::motionNotifyEvent( Window w, int /*state*/, int x, int y, int x_root, int y_root )
1405 if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
1406 return true; // care only about the whole frame
1407 if ( !buttonDown )
1409 Position newmode = mousePosition( QPoint( x, y ));
1410 if( newmode != mode )
1412 mode = newmode;
1413 updateCursor();
1415 // reset the timestamp for the optimization, otherwise with long passivity
1416 // the option in waitingMotionEvent() may be always true
1417 next_motion_time = CurrentTime;
1418 return false;
1420 if( w == moveResizeGrabWindow())
1422 x = this->x(); // translate from grab window to local coords
1423 y = this->y();
1425 if( !waitingMotionEvent())
1426 handleMoveResize( x, y, x_root, y_root );
1427 return true;
1430 void Client::focusInEvent( XFocusInEvent* e )
1432 if( e->window != window())
1433 return; // only window gets focus
1434 if ( e->mode == NotifyUngrab )
1435 return; // we don't care
1436 if ( e->detail == NotifyPointer )
1437 return; // we don't care
1438 if( !isShown( false ) || !isOnCurrentDesktop()) // we unmapped it, but it got focus meanwhile ->
1439 return; // activateNextClient() already transferred focus elsewhere
1440 // check if this client is in should_get_focus list or if activation is allowed
1441 bool activate = workspace()->allowClientActivation( this, -1U, true );
1442 workspace()->gotFocusIn( this ); // remove from should_get_focus list
1443 if( activate )
1444 setActive( true );
1445 else
1447 workspace()->restoreFocus();
1448 demandAttention();
1452 // When a client loses focus, FocusOut events are usually immediatelly
1453 // followed by FocusIn events for another client that gains the focus
1454 // (unless the focus goes to another screen, or to the nofocus widget).
1455 // Without this check, the former focused client would have to be
1456 // deactivated, and after that, the new one would be activated, with
1457 // a short time when there would be no active client. This can cause
1458 // flicker sometimes, e.g. when a fullscreen is shown, and focus is transferred
1459 // from it to its transient, the fullscreen would be kept in the Active layer
1460 // at the beginning and at the end, but not in the middle, when the active
1461 // client would be temporarily none (see Client::belongToLayer() ).
1462 // Therefore, the events queue is checked, whether it contains the matching
1463 // FocusIn event, and if yes, deactivation of the previous client will
1464 // be skipped, as activation of the new one will automatically deactivate
1465 // previously active client.
1466 static bool follows_focusin = false;
1467 static bool follows_focusin_failed = false;
1468 static Bool predicate_follows_focusin( Display*, XEvent* e, XPointer arg )
1470 if( follows_focusin || follows_focusin_failed )
1471 return False;
1472 Client* c = ( Client* ) arg;
1473 if( e->type == FocusIn && c->workspace()->findClient( WindowMatchPredicate( e->xfocus.window )))
1474 { // found FocusIn
1475 follows_focusin = true;
1476 return False;
1478 // events that may be in the queue before the FocusIn event that's being
1479 // searched for
1480 if( e->type == FocusIn || e->type == FocusOut || e->type == KeymapNotify )
1481 return False;
1482 follows_focusin_failed = true; // a different event - stop search
1483 return False;
1486 static bool check_follows_focusin( Client* c )
1488 follows_focusin = follows_focusin_failed = false;
1489 XEvent dummy;
1490 // XCheckIfEvent() is used to make the search non-blocking, the predicate
1491 // always returns False, so nothing is removed from the events queue.
1492 // XPeekIfEvent() would block.
1493 XCheckIfEvent( display(), &dummy, predicate_follows_focusin, (XPointer)c );
1494 return follows_focusin;
1498 void Client::focusOutEvent( XFocusOutEvent* e )
1500 if( e->window != window())
1501 return; // only window gets focus
1502 if ( e->mode == NotifyGrab )
1503 return; // we don't care
1504 if ( isShade() )
1505 return; // here neither
1506 if ( e->detail != NotifyNonlinear
1507 && e->detail != NotifyNonlinearVirtual )
1508 // SELI check all this
1509 return; // hack for motif apps like netscape
1510 if ( QApplication::activePopupWidget() )
1511 return;
1512 if( !check_follows_focusin( this ))
1513 setActive( false );
1516 // performs _NET_WM_MOVERESIZE
1517 void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction )
1519 if( direction == NET::Move )
1520 performMouseCommand( Options::MouseMove, QPoint( x_root, y_root ));
1521 else if( moveResizeMode && direction == NET::MoveResizeCancel)
1523 finishMoveResize( true );
1524 buttonDown = false;
1525 updateCursor();
1527 else if( direction >= NET::TopLeft && direction <= NET::Left )
1529 static const Position convert[] =
1531 PositionTopLeft,
1532 PositionTop,
1533 PositionTopRight,
1534 PositionRight,
1535 PositionBottomRight,
1536 PositionBottom,
1537 PositionBottomLeft,
1538 PositionLeft
1540 if(!isResizable() || isShade())
1541 return;
1542 if( moveResizeMode )
1543 finishMoveResize( false );
1544 buttonDown = true;
1545 moveOffset = QPoint( x_root - x(), y_root - y()); // map from global
1546 invertedMoveOffset = rect().bottomRight() - moveOffset;
1547 unrestrictedMoveResize = false;
1548 mode = convert[ direction ];
1549 if( !startMoveResize())
1550 buttonDown = false;
1551 updateCursor();
1553 else if( direction == NET::KeyboardMove )
1554 { // ignore mouse coordinates given in the message, mouse position is used by the moving algorithm
1555 QCursor::setPos( geometry().center() );
1556 performMouseCommand( Options::MouseUnrestrictedMove, geometry().center());
1558 else if( direction == NET::KeyboardSize )
1559 { // ignore mouse coordinates given in the message, mouse position is used by the resizing algorithm
1560 QCursor::setPos( geometry().bottomRight());
1561 performMouseCommand( Options::MouseUnrestrictedResize, geometry().bottomRight());
1565 void Client::keyPressEvent( uint key_code )
1567 updateUserTime();
1568 if ( !isMove() && !isResize() )
1569 return;
1570 bool is_control = key_code & Qt::CTRL;
1571 bool is_alt = key_code & Qt::ALT;
1572 key_code = key_code & ~Qt::KeyboardModifierMask;
1573 int delta = is_control?1:is_alt?32:8;
1574 QPoint pos = cursorPos();
1575 switch ( key_code )
1577 case Qt::Key_Left:
1578 pos.rx() -= delta;
1579 break;
1580 case Qt::Key_Right:
1581 pos.rx() += delta;
1582 break;
1583 case Qt::Key_Up:
1584 pos.ry() -= delta;
1585 break;
1586 case Qt::Key_Down:
1587 pos.ry() += delta;
1588 break;
1589 case Qt::Key_Space:
1590 case Qt::Key_Return:
1591 case Qt::Key_Enter:
1592 finishMoveResize( false );
1593 buttonDown = false;
1594 updateCursor();
1595 break;
1596 case Qt::Key_Escape:
1597 finishMoveResize( true );
1598 buttonDown = false;
1599 updateCursor();
1600 break;
1601 default:
1602 return;
1604 QCursor::setPos( pos );
1607 #ifdef HAVE_XSYNC
1608 void Client::syncEvent( XSyncAlarmNotifyEvent* e )
1610 if( e->alarm == sync_alarm && XSyncValueEqual( e->counter_value, sync_counter_value ))
1612 ready_for_painting = true;
1613 if( isResize())
1615 delete sync_timeout;
1616 sync_timeout = NULL;
1617 if( sync_resize_pending )
1618 performMoveResize();
1622 #endif
1624 // ****************************************
1625 // Unmanaged
1626 // ****************************************
1628 bool Unmanaged::windowEvent( XEvent* e )
1630 double old_opacity = opacity();
1631 unsigned long dirty[ 2 ];
1632 info->event( e, dirty, 2 ); // pass through the NET stuff
1633 if( dirty[ NETWinInfo::PROTOCOLS2 ] & NET::WM2Opacity )
1635 if( compositing())
1637 addRepaintFull();
1638 scene->windowOpacityChanged( this );
1639 if( effects )
1640 static_cast<EffectsHandlerImpl*>(effects)->windowOpacityChanged( effectWindow(), old_opacity );
1643 switch (e->type)
1645 case UnmapNotify:
1646 unmapNotifyEvent( &e->xunmap );
1647 break;
1648 case MapNotify:
1649 mapNotifyEvent( &e->xmap );
1650 break;
1651 case ConfigureNotify:
1652 configureNotifyEvent( &e->xconfigure );
1653 break;
1654 case PropertyNotify:
1655 propertyNotifyEvent( &e->xproperty );
1656 break;
1657 default:
1659 if( e->type == Extensions::shapeNotifyEvent() )
1661 detectShape( window());
1662 addRepaintFull();
1663 addWorkspaceRepaint( geometry()); // in case shape change removes part of this window
1664 if( scene != NULL )
1665 scene->windowGeometryShapeChanged( this );
1666 if( effects != NULL )
1667 static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), geometry());
1669 #ifdef HAVE_XDAMAGE
1670 if( e->type == Extensions::damageNotifyEvent())
1671 damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent* >( e ));
1672 #endif
1673 break;
1676 return false; // don't eat events, even our own unmanaged widgets are tracked
1679 void Unmanaged::mapNotifyEvent( XMapEvent* )
1683 void Unmanaged::unmapNotifyEvent( XUnmapEvent* )
1685 release();
1688 void Unmanaged::configureNotifyEvent( XConfigureEvent* e )
1690 if( effects )
1691 static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowStacking(); // keep them on top
1692 QRect newgeom( e->x, e->y, e->width, e->height );
1693 if( newgeom != geom )
1695 addWorkspaceRepaint( geometry()); // damage old area
1696 QRect old = geom;
1697 geom = newgeom;
1698 addRepaintFull();
1699 if( old.size() != geom.size())
1700 discardWindowPixmap();
1701 if( scene != NULL )
1702 scene->windowGeometryShapeChanged( this );
1703 if( effects != NULL )
1704 static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), old );
1708 // ****************************************
1709 // Toplevel
1710 // ****************************************
1712 void Toplevel::propertyNotifyEvent( XPropertyEvent* e )
1714 if( e->window != window())
1715 return; // ignore frame/wrapper
1716 switch ( e->atom )
1718 default:
1719 if (e->atom == atoms->wm_client_leader )
1720 getWmClientLeader();
1721 else if( e->atom == atoms->wm_window_role )
1722 getWindowRole();
1723 break;
1725 if( effects )
1726 static_cast< EffectsHandlerImpl* >( effects )->propertyNotify( effectWindow(), e->atom );
1729 // ****************************************
1730 // Group
1731 // ****************************************
1733 bool Group::groupEvent( XEvent* e )
1735 unsigned long dirty[ 2 ];
1736 leader_info->event( e, dirty, 2 ); // pass through the NET stuff
1737 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
1738 getIcons();
1739 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
1740 startupIdChanged();
1741 return false;
1745 } // namespace