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>
31 #include "workspace.h"
36 #include "unmanaged.h"
41 #include <QApplication>
43 #include <kkeyserver.h>
45 #include <X11/extensions/shape.h>
46 #include <X11/Xatom.h>
50 #include <X11/extensions/Xrandr.h>
56 // ****************************************
58 // ****************************************
60 WinInfo::WinInfo( Client
* c
, Display
* display
, Window window
,
61 Window rwin
, const unsigned long pr
[], int pr_size
)
62 : NETWinInfo( 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::changeState( unsigned long state
, unsigned long mask
)
73 mask
&= ~NET::Sticky
; // KWin doesn't support large desktops, ignore
74 mask
&= ~NET::Hidden
; // clients are not allowed to change this directly
75 state
&= mask
; // for safety, clear all other bits
77 if(( mask
& NET::FullScreen
) != 0 && ( state
& NET::FullScreen
) == 0 )
78 m_client
->setFullScreen( false, false );
79 if ( (mask
& NET::Max
) == NET::Max
)
80 m_client
->setMaximize( state
& NET::MaxVert
, state
& NET::MaxHoriz
);
81 else if ( mask
& NET::MaxVert
)
82 m_client
->setMaximize( state
& NET::MaxVert
, m_client
->maximizeMode() & Client::MaximizeHorizontal
);
83 else if ( mask
& NET::MaxHoriz
)
84 m_client
->setMaximize( m_client
->maximizeMode() & Client::MaximizeVertical
, state
& NET::MaxHoriz
);
86 if ( mask
& NET::Shaded
)
87 m_client
->setShade( state
& NET::Shaded
? ShadeNormal
: ShadeNone
);
88 if ( mask
& NET::KeepAbove
)
89 m_client
->setKeepAbove( (state
& NET::KeepAbove
) != 0 );
90 if ( mask
& NET::KeepBelow
)
91 m_client
->setKeepBelow( (state
& NET::KeepBelow
) != 0 );
92 if( mask
& NET::SkipTaskbar
)
93 m_client
->setSkipTaskbar( ( state
& NET::SkipTaskbar
) != 0, true );
94 if( mask
& NET::SkipPager
)
95 m_client
->setSkipPager( ( state
& NET::SkipPager
) != 0 );
96 if( mask
& NET::DemandsAttention
)
97 m_client
->demandAttention(( state
& NET::DemandsAttention
) != 0 );
98 if( mask
& NET::Modal
)
99 m_client
->setModal( ( state
& NET::Modal
) != 0 );
100 // unsetting fullscreen first, setting it last (because e.g. maximize works only for !isFullScreen() )
101 if(( mask
& NET::FullScreen
) != 0 && ( state
& NET::FullScreen
) != 0 )
102 m_client
->setFullScreen( true, false );
105 void WinInfo::disable()
107 m_client
= NULL
; // only used when the object is passed to Deleted
110 // ****************************************
112 // ****************************************
114 RootInfo::RootInfo( Workspace
* ws
, Display
*dpy
, Window w
, const char *name
, unsigned long pr
[], int pr_num
, int scr
)
115 : NETRootInfo( dpy
, w
, name
, pr
, pr_num
, scr
)
120 void RootInfo::changeNumberOfDesktops(int n
)
122 workspace
->setNumberOfDesktops( n
);
125 void RootInfo::changeCurrentDesktop(int d
)
127 workspace
->setCurrentDesktop( d
);
130 void RootInfo::changeActiveWindow( Window w
, NET::RequestSource src
, Time timestamp
, Window active_window
)
132 if( Client
* c
= workspace
->findClient( WindowMatchPredicate( w
)))
134 if( timestamp
== CurrentTime
)
135 timestamp
= c
->userTime();
136 if( src
!= NET::FromApplication
&& src
!= FromTool
)
138 if( src
== NET::FromTool
)
139 workspace
->activateClient( c
, true ); // force
140 else // NET::FromApplication
143 if( workspace
->allowClientActivation( c
, timestamp
, false, true ))
144 workspace
->activateClient( c
);
145 // if activation of the requestor's window would be allowed, allow activation too
146 else if( active_window
!= None
147 && ( c2
= workspace
->findClient( WindowMatchPredicate( active_window
))) != NULL
148 && workspace
->allowClientActivation( c2
,
149 timestampCompare( timestamp
, c2
->userTime() > 0 ? timestamp
: c2
->userTime()), false, true ))
151 workspace
->activateClient( c
);
154 c
->demandAttention();
159 void RootInfo::restackWindow( Window w
, RequestSource src
, Window above
, int detail
, Time timestamp
)
161 if( Client
* c
= workspace
->findClient( WindowMatchPredicate( w
)))
163 if( timestamp
== CurrentTime
)
164 timestamp
= c
->userTime();
165 if( src
!= NET::FromApplication
&& src
!= FromTool
)
167 c
->restackWindow( above
, detail
, src
, timestamp
, true );
171 void RootInfo::gotTakeActivity( Window w
, Time timestamp
, long flags
)
173 if( Client
* c
= workspace
->findClient( WindowMatchPredicate( w
)))
174 workspace
->handleTakeActivity( c
, timestamp
, flags
);
177 void RootInfo::closeWindow(Window w
)
179 Client
* c
= workspace
->findClient( WindowMatchPredicate( w
));
184 void RootInfo::moveResize(Window w
, int x_root
, int y_root
, unsigned long direction
)
186 Client
* c
= workspace
->findClient( WindowMatchPredicate( w
));
189 updateXTime(); // otherwise grabbing may have old timestamp - this message should include timestamp
190 c
->NETMoveResize( x_root
, y_root
, (Direction
)direction
);
194 void RootInfo::moveResizeWindow(Window w
, int flags
, int x
, int y
, int width
, int height
)
196 Client
* c
= workspace
->findClient( WindowMatchPredicate( w
));
198 c
->NETMoveResizeWindow( flags
, x
, y
, width
, height
);
201 void RootInfo::gotPing( Window w
, Time timestamp
)
203 if( Client
* c
= workspace
->findClient( WindowMatchPredicate( w
)))
204 c
->gotPing( timestamp
);
207 void RootInfo::changeShowingDesktop( bool showing
)
209 workspace
->setShowingDesktop( showing
);
212 // ****************************************
214 // ****************************************
217 Handles workspace specific XEvents
219 bool Workspace::workspaceEvent( XEvent
* e
)
221 if ( mouse_emulation
&& (e
->type
== ButtonPress
|| e
->type
== ButtonRelease
) )
223 mouse_emulation
= false;
226 if( effects
&& static_cast< EffectsHandlerImpl
* >( effects
)->hasKeyboardGrab()
227 && ( e
->type
== KeyPress
|| e
->type
== KeyRelease
))
228 return false; // let Qt process it, it'll be intercepted again in eventFilter()
230 if( e
->type
== PropertyNotify
|| e
->type
== ClientMessage
)
232 unsigned long dirty
[ NETRootInfo::PROPERTIES_SIZE
];
233 rootInfo
->event( e
, dirty
, NETRootInfo::PROPERTIES_SIZE
);
234 if( dirty
[ NETRootInfo::PROTOCOLS
] & NET::DesktopNames
)
235 saveDesktopSettings();
236 if( dirty
[ NETRootInfo::PROTOCOLS2
] & NET::WM2DesktopLayout
)
237 updateDesktopLayout();
240 // events that should be handled before Clients can get them
245 was_user_interaction
= true;
248 if ( tab_grab
|| control_grab
)
250 tab_box
->handleMouseEvent( e
);
253 if( effects
&& static_cast<EffectsHandlerImpl
*>(effects
)->checkInputWindowEvent( e
))
258 was_user_interaction
= true;
260 KKeyServer::xEventToQt(e
, &keyQt
);
261 // kDebug(125) << "Workspace::keyPress( " << keyQt << " )";
264 movingClient
->keyPressEvent(keyQt
);
267 if( tab_grab
|| control_grab
)
269 tabBoxKeyPress( keyQt
);
275 was_user_interaction
= true;
276 if( tab_grab
|| control_grab
)
278 tabBoxKeyRelease( e
->xkey
);
284 if( Client
* c
= findClient( WindowMatchPredicate( e
->xany
.window
)))
286 if( c
->windowEvent( e
))
289 else if( Client
* c
= findClient( WrapperIdMatchPredicate( e
->xany
.window
)))
291 if( c
->windowEvent( e
))
294 else if( Client
* c
= findClient( FrameIdMatchPredicate( e
->xany
.window
)))
296 if( c
->windowEvent( e
))
299 else if( Unmanaged
* c
= findUnmanaged( WindowMatchPredicate( e
->xany
.window
)))
301 if( c
->windowEvent( e
))
306 Window special
= findSpecialEventWindow( e
);
307 if( special
!= None
)
308 if( Client
* c
= findClient( WindowMatchPredicate( special
)))
310 if( c
->windowEvent( e
))
314 if( movingClient
!= NULL
&& movingClient
->moveResizeGrabWindow() == e
->xany
.window
315 && ( e
->type
== MotionNotify
|| e
->type
== ButtonPress
|| e
->type
== ButtonRelease
))
317 if( movingClient
->windowEvent( e
))
324 if ( e
->xcreatewindow
.parent
== rootWindow() &&
325 !QWidget::find( e
->xcreatewindow
.window
) &&
326 !e
->xcreatewindow
.override_redirect
)
328 // see comments for allowClientActivation()
330 XChangeProperty(display(), e
->xcreatewindow
.window
,
331 atoms
->kde_net_wm_user_creation_time
, XA_CARDINAL
,
332 32, PropModeReplace
, (unsigned char *)&t
, 1);
338 return ( e
->xunmap
.event
!= e
->xunmap
.window
); // hide wm typical event from Qt
342 //do not confuse Qt with these events. After all, _we_ are the
343 //window manager who does the reparenting.
354 // e->xmaprequest.window is different from e->xany.window
355 // TODO this shouldn't be necessary now
356 Client
* c
= findClient( WindowMatchPredicate( e
->xmaprequest
.window
));
359 // don't check for the parent being the root window, this breaks when some app unmaps
360 // a window, changes something and immediately maps it back, without giving KWin
361 // a chance to reparent it back to root
362 // since KWin can get MapRequest only for root window children and
363 // children of WindowWrapper (=clients), the check is AFAIK useless anyway
364 // Note: Now the save-set support in Client::mapRequestEvent() actually requires that
365 // this code doesn't check the parent to be root.
366 // if ( e->xmaprequest.parent == root ) {
367 c
= createClient( e
->xmaprequest
.window
, false );
368 if( c
== NULL
) // refused to manage, simply map it (most probably override redirect)
369 XMapRaised( display(), e
->xmaprequest
.window
);
375 updateFocusChains( c
, FocusChainUpdate
);
382 if( e
->xmap
.override_redirect
)
384 Unmanaged
* c
= findUnmanaged( WindowMatchPredicate( e
->xmap
.window
));
386 c
= createUnmanaged( e
->xmap
.window
);
388 return c
->windowEvent( e
);
390 return ( e
->xmap
.event
!= e
->xmap
.window
); // hide wm typical event from Qt
395 if ( QWhatsThis::inWhatsThisMode() )
397 QWidget
* w
= QWidget::find( e
->xcrossing
.window
);
399 QWhatsThis::leaveWhatsThisMode();
401 if( electricBorderEvent(e
))
407 if ( !QWhatsThis::inWhatsThisMode() )
409 // TODO is this cliente ever found, given that client events are searched above?
410 Client
* c
= findClient( FrameIdMatchPredicate( e
->xcrossing
.window
));
411 if ( c
&& e
->xcrossing
.detail
!= NotifyInferior
)
412 QWhatsThis::leaveWhatsThisMode();
415 case ConfigureRequest
:
417 if ( e
->xconfigurerequest
.parent
== rootWindow())
420 wc
.border_width
= e
->xconfigurerequest
.border_width
;
421 wc
.x
= e
->xconfigurerequest
.x
;
422 wc
.y
= e
->xconfigurerequest
.y
;
423 wc
.width
= e
->xconfigurerequest
.width
;
424 wc
.height
= e
->xconfigurerequest
.height
;
426 wc
.stack_mode
= Above
;
427 unsigned int value_mask
= e
->xconfigurerequest
.value_mask
428 & ( CWX
| CWY
| CWWidth
| CWHeight
| CWBorderWidth
);
429 XConfigureWindow( display(), e
->xconfigurerequest
.window
, value_mask
, &wc
);
435 if ( mouse_emulation
)
436 return keyPressMouseEmulation( e
->xkey
);
439 if ( mouse_emulation
)
443 if( e
->xfocus
.window
== rootWindow()
444 && ( e
->xfocus
.detail
== NotifyDetailNone
|| e
->xfocus
.detail
== NotifyPointerRoot
))
446 updateXTime(); // focusToNull() uses xTime(), which is old now (FocusIn has no timestamp)
449 XGetInputFocus( display(), &focus
, &revert
);
450 if( focus
== None
|| focus
== PointerRoot
)
452 //kWarning( 1212 ) << "X focus set to None/PointerRoot, reseting focus" ;
453 Client
*c
= mostRecentlyActivatedClient();
455 requestFocus( c
, true );
456 else if( activateNextClient( NULL
))
464 return true; // always eat these, they would tell Qt that KWin is the active app
466 if( electricBorderEvent( e
))
471 && ( e
->xexpose
.window
== rootWindow() // root window needs repainting
472 || overlay
!= None
&& e
->xexpose
.window
== overlay
)) // overlay needs repainting
474 addRepaint( e
->xexpose
.x
, e
->xexpose
.y
, e
->xexpose
.width
, e
->xexpose
.height
);
477 case VisibilityNotify
:
478 if( compositing() && overlay
!= None
&& e
->xvisibility
.window
== overlay
)
480 overlay_visible
= ( e
->xvisibility
.state
!= VisibilityFullyObscured
);
485 if( e
->type
== Extensions::randrNotifyEvent() && Extensions::randrAvailable() )
488 XRRUpdateConfiguration( e
);
492 // desktopResized() should take care of when the size or
493 // shape of the desktop has changed, but we also want to
494 // catch refresh rate changes
496 QTimer::singleShot( 0, this, SLOT( setupCompositing() ) );
499 else if( e
->type
== Extensions::syncAlarmNotifyEvent() && Extensions::syncAvailable())
502 foreach( Client
* c
, clients
)
503 c
->syncEvent( reinterpret_cast< XSyncAlarmNotifyEvent
* >( e
));
504 foreach( Client
* c
, desktops
)
505 c
->syncEvent( reinterpret_cast< XSyncAlarmNotifyEvent
* >( e
));
513 // Used only to filter events that need to be processed by Qt first
514 // (e.g. keyboard input to be composed), otherwise events are
515 // handle by the XEvent filter above
516 bool Workspace::workspaceEvent( QEvent
* e
)
518 if(( e
->type() == QEvent::KeyPress
|| e
->type() == QEvent::KeyRelease
|| e
->type() == QEvent::ShortcutOverride
)
519 && effects
&& static_cast< EffectsHandlerImpl
* >( effects
)->hasKeyboardGrab())
521 static_cast< EffectsHandlerImpl
* >( effects
)->grabbedKeyboardEvent( static_cast< QKeyEvent
* >( e
));
527 // Some events don't have the actual window which caused the event
528 // as e->xany.window (e.g. ConfigureRequest), but as some other
529 // field in the XEvent structure.
530 Window
Workspace::findSpecialEventWindow( XEvent
* e
)
535 return e
->xcreatewindow
.window
;
537 return e
->xdestroywindow
.window
;
539 return e
->xunmap
.window
;
541 return e
->xmap
.window
;
543 return e
->xmaprequest
.window
;
545 return e
->xreparent
.window
;
546 case ConfigureNotify
:
547 return e
->xconfigure
.window
;
549 return e
->xgravity
.window
;
550 case ConfigureRequest
:
551 return e
->xconfigurerequest
.window
;
552 case CirculateNotify
:
553 return e
->xcirculate
.window
;
554 case CirculateRequest
:
555 return e
->xcirculaterequest
.window
;
561 // ****************************************
563 // ****************************************
566 General handler for XEvents concerning the client window
568 bool Client::windowEvent( XEvent
* e
)
570 if( e
->xany
.window
== window()) // avoid doing stuff on frame or wrapper
572 unsigned long dirty
[ 2 ];
573 double old_opacity
= opacity();
574 info
->event( e
, dirty
, 2 ); // pass through the NET stuff
576 if ( ( dirty
[ WinInfo::PROTOCOLS
] & NET::WMName
) != 0 )
578 if ( ( dirty
[ WinInfo::PROTOCOLS
] & NET::WMIconName
) != 0 )
580 if ( ( dirty
[ WinInfo::PROTOCOLS
] & NET::WMStrut
) != 0
581 || ( dirty
[ WinInfo::PROTOCOLS2
] & NET::WM2ExtendedStrut
) != 0 )
583 if( isTopMenu()) // the fallback mode of KMenuBar may alter the strut
584 checkWorkspacePosition(); // restore it
585 workspace()->updateClientArea();
587 if ( ( dirty
[ WinInfo::PROTOCOLS
] & NET::WMIcon
) != 0 )
589 // Note there's a difference between userTime() and info->userTime()
590 // info->userTime() is the value of the property, userTime() also includes
591 // updates of the time done by KWin (ButtonPress on windowrapper etc.).
592 if(( dirty
[ WinInfo::PROTOCOLS2
] & NET::WM2UserTime
) != 0 )
594 workspace()->setWasUserInteraction();
595 updateUserTime( info
->userTime());
597 if(( dirty
[ WinInfo::PROTOCOLS2
] & NET::WM2StartupId
) != 0 )
599 if( dirty
[ WinInfo::PROTOCOLS
] & NET::WMIconGeometry
)
601 if( demandAttentionKNotifyTimer
!= NULL
)
602 demandAttentionKNotify();
604 if( dirty
[ WinInfo::PROTOCOLS2
] & NET::WM2Opacity
)
609 scene
->windowOpacityChanged( this );
611 static_cast<EffectsHandlerImpl
*>(effects
)->windowOpacityChanged( effectWindow(), old_opacity
);
614 { // forward to the frame if there's possibly another compositing manager running
615 NETWinInfo
i( display(), frameId(), rootWindow(), 0 );
616 i
.setOpacity( info
->opacity());
624 unmapNotifyEvent( &e
->xunmap
);
627 destroyNotifyEvent( &e
->xdestroywindow
);
630 // this one may pass the event to workspace
631 return mapRequestEvent( &e
->xmaprequest
);
632 case ConfigureRequest
:
633 configureRequestEvent( &e
->xconfigurerequest
);
636 propertyNotifyEvent( &e
->xproperty
);
640 workspace()->setWasUserInteraction();
644 workspace()->setWasUserInteraction();
645 buttonPressEvent( e
->xbutton
.window
, e
->xbutton
.button
, e
->xbutton
.state
,
646 e
->xbutton
.x
, e
->xbutton
.y
, e
->xbutton
.x_root
, e
->xbutton
.y_root
);
649 // don't update user time on releases
650 // e.g. if the user presses Alt+F2, the Alt release
651 // would appear as user input to the currently active window
654 // don't update user time on releases
655 // e.g. if the user presses Alt+F2, the Alt release
656 // would appear as user input to the currently active window
657 buttonReleaseEvent( e
->xbutton
.window
, e
->xbutton
.button
, e
->xbutton
.state
,
658 e
->xbutton
.x
, e
->xbutton
.y
, e
->xbutton
.x_root
, e
->xbutton
.y_root
);
661 motionNotifyEvent( e
->xmotion
.window
, e
->xmotion
.state
,
662 e
->xmotion
.x
, e
->xmotion
.y
, e
->xmotion
.x_root
, e
->xmotion
.y_root
);
663 workspace()->updateFocusMousePosition( QPoint( e
->xmotion
.x_root
, e
->xmotion
.y_root
));
666 enterNotifyEvent( &e
->xcrossing
);
667 // MotionNotify is guaranteed to be generated only if the mouse
668 // move start and ends in the window; for cases when it only
669 // starts or only ends there, Enter/LeaveNotify are generated.
670 // Fake a MotionEvent in such cases to make handle of mouse
671 // events simpler (Qt does that too).
672 motionNotifyEvent( e
->xcrossing
.window
, e
->xcrossing
.state
,
673 e
->xcrossing
.x
, e
->xcrossing
.y
, e
->xcrossing
.x_root
, e
->xcrossing
.y_root
);
674 workspace()->updateFocusMousePosition( QPoint( e
->xcrossing
.x_root
, e
->xcrossing
.y_root
));
677 motionNotifyEvent( e
->xcrossing
.window
, e
->xcrossing
.state
,
678 e
->xcrossing
.x
, e
->xcrossing
.y
, e
->xcrossing
.x_root
, e
->xcrossing
.y_root
);
679 leaveNotifyEvent( &e
->xcrossing
);
680 // not here, it'd break following enter notify handling
681 // workspace()->updateFocusMousePosition( QPoint( e->xcrossing.x_root, e->xcrossing.y_root ));
684 focusInEvent( &e
->xfocus
);
687 focusOutEvent( &e
->xfocus
);
692 clientMessageEvent( &e
->xclient
);
694 case ColormapChangeMask
:
695 if( e
->xany
.window
== window())
697 cmap
= e
->xcolormap
.colormap
;
699 workspace()->updateColormap();
703 if( e
->xany
.window
== window())
705 if( e
->type
== Extensions::shapeNotifyEvent() )
707 detectShape( window()); // workaround for #19644
711 if( e
->xany
.window
== frameId())
714 if( e
->type
== Extensions::damageNotifyEvent())
715 damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent
* >( e
));
720 return true; // eat all events
724 Handles map requests of the client window
726 bool Client::mapRequestEvent( XMapRequestEvent
* e
)
728 if( e
->window
!= window())
730 // Special support for the save-set feature, which is a bit broken.
731 // If there's a window from one client embedded in another one,
732 // e.g. using XEMBED, and the embedder suddenly looses its X connection,
733 // save-set will reparent the embedded window to its closest ancestor
734 // that will remains. Unfortunately, with reparenting window managers,
735 // this is not the root window, but the frame (or in KWin's case,
736 // it's the wrapper for the client window). In this case,
737 // the wrapper will get ReparentNotify for a window it won't know,
738 // which will be ignored, and then it gets MapRequest, as save-set
739 // always maps. Returning true here means that Workspace::workspaceEvent()
740 // will handle this MapRequest and manage this window (i.e. act as if
741 // it was reparented to root window).
742 if( e
->parent
== wrapperId())
744 return true; // no messing with frame etc.
746 if( isTopMenu() && workspace()->managingTopMenus())
747 return true; // kwin controls these
748 switch ( mappingState() )
751 assert( false ); // WMs are not supposed to manage clients in Withdrawn state,
752 // manage(); // after initial mapping manage() is called from createClient()
755 // also copied in clientMessage()
759 setShade( ShadeNone
);
760 if( !isOnCurrentDesktop())
762 if( workspace()->allowClientActivation( this ))
763 workspace()->activateClient( this );
769 // TODO fake MapNotify?
776 Handles unmap notify events of the client window
778 void Client::unmapNotifyEvent( XUnmapEvent
* e
)
780 if( e
->window
!= window())
782 if( e
->event
!= wrapperId())
783 { // most probably event from root window when initially reparenting
785 if( e
->event
== rootWindow() && e
->send_event
)
786 ignore
= false; // XWithdrawWindow()
790 switch( mappingState())
796 // maybe we will be destroyed soon. Check this first.
798 if( XCheckTypedWindowEvent (display(), window(),
799 DestroyNotify
, &ev
) ) // TODO I don't like this much
801 destroyClient(); // deletes this
811 void Client::destroyNotifyEvent( XDestroyWindowEvent
* e
)
813 if( e
->window
!= window())
820 Handles client messages for the client window
822 void Client::clientMessageEvent( XClientMessageEvent
* e
)
824 if( e
->window
!= window())
825 return; // ignore frame/wrapper
827 if ( e
->message_type
== atoms
->kde_wm_change_state
)
829 if( isTopMenu() && workspace()->managingTopMenus())
830 return; // kwin controls these
831 bool avoid_animation
= ( e
->data
.l
[ 1 ] );
832 if( e
->data
.l
[ 0 ] == IconicState
)
834 else if( e
->data
.l
[ 0 ] == NormalState
)
835 { // copied from mapRequest()
837 unminimize( avoid_animation
);
839 setShade( ShadeNone
);
840 if( !isOnCurrentDesktop())
842 if( workspace()->allowClientActivation( this ))
843 workspace()->activateClient( this );
849 else if ( e
->message_type
== atoms
->wm_change_state
)
851 if( isTopMenu() && workspace()->managingTopMenus())
852 return; // kwin controls these
853 if ( e
->data
.l
[0] == IconicState
)
861 Handles configure requests of the client window
863 void Client::configureRequestEvent( XConfigureRequestEvent
* e
)
865 if( e
->window
!= window())
866 return; // ignore frame/wrapper
867 if ( isResize() || isMove())
868 return; // we have better things to do right now
870 if( fullscreen_mode
== FullScreenNormal
) // refuse resizing of fullscreen windows
871 { // but allow resizing fullscreen hacks in order to let them cancel fullscreen mode
872 sendSyntheticConfigureNotify();
875 if( isSplash() // no manipulations with splashscreens either
876 || isTopMenu()) // topmenus neither
878 sendSyntheticConfigureNotify();
882 if ( e
->value_mask
& CWBorderWidth
)
884 // first, get rid of a window border
886 unsigned int value_mask
= 0;
889 value_mask
= CWBorderWidth
;
890 XConfigureWindow( display(), window(), value_mask
, & wc
);
893 if( e
->value_mask
& ( CWX
| CWY
| CWHeight
| CWWidth
))
894 configureRequest( e
->value_mask
, e
->x
, e
->y
, e
->width
, e
->height
, 0, false );
896 if ( e
->value_mask
& CWStackMode
)
897 restackWindow( e
->above
, e
->detail
, NET::FromApplication
, userTime(), false );
899 // Sending a synthetic configure notify always is fine, even in cases where
900 // the ICCCM doesn't require this - it can be though of as 'the WM decided to move
901 // the window later'. The client should not cause that many configure request,
902 // so this should not have any significant impact. With user moving/resizing
903 // the it should be optimized though (see also Client::setGeometry()/plainResize()/move()).
904 sendSyntheticConfigureNotify();
906 // SELI TODO accept configure requests for isDesktop windows (because kdesktop
907 // may get XRANDR resize event before kwin), but check it's still at the bottom?
912 Handles property changes of the client window
914 void Client::propertyNotifyEvent( XPropertyEvent
* e
)
916 Toplevel::propertyNotifyEvent( e
);
917 if( e
->window
!= window())
918 return; // ignore frame/wrapper
921 case XA_WM_NORMAL_HINTS
:
927 case XA_WM_ICON_NAME
:
930 case XA_WM_TRANSIENT_FOR
:
935 getIcons(); // because KWin::icon() uses WMHints as fallback
938 if ( e
->atom
== atoms
->wm_protocols
)
939 getWindowProtocols();
940 else if( e
->atom
== atoms
->motif_wm_hints
)
942 else if( e
->atom
== atoms
->net_wm_sync_request_counter
)
949 void Client::enterNotifyEvent( XCrossingEvent
* e
)
951 if( e
->window
!= frameId())
952 return; // care only about entering the whole frame
953 if( e
->mode
== NotifyNormal
||
954 ( !options
->focusPolicyIsReasonable() &&
955 e
->mode
== NotifyUngrab
) )
958 if (options
->shadeHover
&& isShade())
960 delete shadeHoverTimer
;
961 shadeHoverTimer
= new QTimer( this );
962 connect( shadeHoverTimer
, SIGNAL( timeout() ), this, SLOT( shadeHover() ));
963 shadeHoverTimer
->setSingleShot( true );
964 shadeHoverTimer
->start( options
->shadeHoverInterval
);
967 if ( options
->focusPolicy
== Options::ClickToFocus
)
970 if ( options
->autoRaise
&& !isDesktop() &&
971 !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() &&
972 workspace()->topClientOnDesktop( workspace()->currentDesktop()) != this )
974 delete autoRaiseTimer
;
975 autoRaiseTimer
= new QTimer( this );
976 connect( autoRaiseTimer
, SIGNAL( timeout() ), this, SLOT( autoRaise() ) );
977 autoRaiseTimer
->setSingleShot( true );
978 autoRaiseTimer
->start( options
->autoRaiseInterval
);
981 QPoint
currentPos( e
->x_root
, e
->y_root
);
982 if ( options
->focusPolicy
!= Options::FocusStrictlyUnderMouse
&& ( isDesktop() || isDock() || isTopMenu() ) )
984 // for FocusFollowsMouse, change focus only if the mouse has actually been moved, not if the focus
985 // change came because of window changes (e.g. closing a window) - #92290
986 if( options
->focusPolicy
!= Options::FocusFollowsMouse
987 || currentPos
!= workspace()->focusMousePosition())
989 if ( options
->delayFocus
)
990 workspace()->requestDelayFocus( this );
992 workspace()->requestFocus( this );
998 void Client::leaveNotifyEvent( XCrossingEvent
* e
)
1000 if( e
->window
!= frameId())
1001 return; // care only about leaving the whole frame
1002 if ( e
->mode
== NotifyNormal
)
1006 mode
= PositionCenter
;
1009 bool lostMouse
= !rect().contains( QPoint( e
->x
, e
->y
) );
1010 // 'lostMouse' wouldn't work with e.g. B2 or Keramik, which have non-rectangular decorations
1011 // (i.e. the LeaveNotify event comes before leaving the rect and no LeaveNotify event
1012 // comes after leaving the rect) - so lets check if the pointer is really outside the window
1014 // TODO this still sucks if a window appears above this one - it should lose the mouse
1015 // if this window is another client, but not if it's a popup ... maybe after KDE3.1 :(
1016 // (repeat after me 'AARGHL!')
1017 if ( !lostMouse
&& e
->detail
!= NotifyInferior
)
1022 if( XQueryPointer( display(), frameId(), &w
, &child
, &d1
, &d2
, &d3
, &d4
, &d5
) == False
1024 lostMouse
= true; // really lost the mouse
1029 workspace()->cancelDelayFocus();
1031 if ( shade_mode
== ShadeHover
&& !moveResizeMode
&& !buttonDown
)
1032 setShade( ShadeNormal
);
1034 if ( options
->focusPolicy
== Options::FocusStrictlyUnderMouse
)
1035 if ( isActive() && lostMouse
)
1036 workspace()->requestFocus( 0 ) ;
1041 #define XCapL KKeyServer::modXLock()
1042 #define XNumL KKeyServer::modXNumLock()
1043 #define XScrL KKeyServer::modXScrollLock()
1044 void Client::grabButton( int modifier
)
1046 unsigned int mods
[ 8 ] =
1048 0, XCapL
, XNumL
, XNumL
| XCapL
,
1049 XScrL
, XScrL
| XCapL
,
1050 XScrL
| XNumL
, XScrL
| XNumL
| XCapL
1055 XGrabButton( display(), AnyButton
,
1056 modifier
| mods
[ i
],
1057 wrapperId(), false, ButtonPressMask
,
1058 GrabModeSync
, GrabModeAsync
, None
, None
);
1061 void Client::ungrabButton( int modifier
)
1063 unsigned int mods
[ 8 ] =
1065 0, XCapL
, XNumL
, XNumL
| XCapL
,
1066 XScrL
, XScrL
| XCapL
,
1067 XScrL
| XNumL
, XScrL
| XNumL
| XCapL
1072 XUngrabButton( display(), AnyButton
,
1073 modifier
| mods
[ i
], wrapperId());
1080 Releases the passive grab for some modifier combinations when a
1081 window becomes active. This helps broken X programs that
1082 missinterpret LeaveNotify events in grab mode to work properly
1083 (Motif, AWT, Tk, ...)
1085 void Client::updateMouseGrab()
1087 if( workspace()->globalShortcutsDisabled())
1089 XUngrabButton( display(), AnyButton
, AnyModifier
, wrapperId());
1090 // keep grab for the simple click without modifiers if needed (see below)
1091 bool not_obscured
= workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
1092 if( !( !options
->clickRaise
|| not_obscured
))
1096 if( isActive() && !workspace()->forcedGlobalMouseGrab()) // see Workspace::establishTabBoxGrab()
1098 // first grab all modifier combinations
1099 XGrabButton( display(), AnyButton
, AnyModifier
, wrapperId(), false,
1101 GrabModeSync
, GrabModeAsync
,
1103 // remove the grab for no modifiers only if the window
1104 // is unobscured or if the user doesn't want click raise
1105 // (it is unobscured if it the topmost in the unconstrained stacking order, i.e. it is
1106 // the most recently raised window)
1107 bool not_obscured
= workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
1108 if( !options
->clickRaise
|| not_obscured
)
1109 ungrabButton( None
);
1112 ungrabButton( ShiftMask
);
1113 ungrabButton( ControlMask
);
1114 ungrabButton( ControlMask
| ShiftMask
);
1118 XUngrabButton( display(), AnyButton
, AnyModifier
, wrapperId());
1119 // simply grab all modifier combinations
1120 XGrabButton(display(), AnyButton
, AnyModifier
, wrapperId(), false,
1122 GrabModeSync
, GrabModeAsync
,
1127 // Qt propagates mouse events up the widget hierachy, which means events
1128 // for the decoration window cannot be (easily) intercepted as X11 events
1129 bool Client::eventFilter( QObject
* o
, QEvent
* e
)
1131 if( decoration
== NULL
1132 || o
!= decoration
->widget())
1134 if( e
->type() == QEvent::MouseButtonPress
)
1136 QMouseEvent
* ev
= static_cast< QMouseEvent
* >( e
);
1137 return buttonPressEvent( decorationId(), qtToX11Button( ev
->button()), qtToX11State( ev
->buttons(), ev
->modifiers() ),
1138 ev
->x(), ev
->y(), ev
->globalX(), ev
->globalY() );
1140 if( e
->type() == QEvent::MouseButtonRelease
)
1142 QMouseEvent
* ev
= static_cast< QMouseEvent
* >( e
);
1143 return buttonReleaseEvent( decorationId(), qtToX11Button( ev
->button()), qtToX11State( ev
->buttons(), ev
->modifiers() ),
1144 ev
->x(), ev
->y(), ev
->globalX(), ev
->globalY() );
1146 if( e
->type() == QEvent::MouseMove
) // FRAME i fake z enter/leave?
1148 QMouseEvent
* ev
= static_cast< QMouseEvent
* >( e
);
1149 return motionNotifyEvent( decorationId(), qtToX11State( ev
->buttons(), ev
->modifiers() ),
1150 ev
->x(), ev
->y(), ev
->globalX(), ev
->globalY() );
1152 if( e
->type() == QEvent::Wheel
)
1154 QWheelEvent
* ev
= static_cast< QWheelEvent
* >( e
);
1155 bool r
= buttonPressEvent( decorationId(), ev
->delta() > 0 ? Button4
: Button5
, qtToX11State( ev
->buttons(), ev
->modifiers() ),
1156 ev
->x(), ev
->y(), ev
->globalX(), ev
->globalY() );
1157 r
= r
|| buttonReleaseEvent( decorationId(), ev
->delta() > 0 ? Button4
: Button5
, qtToX11State( ev
->buttons(), ev
->modifiers() ),
1158 ev
->x(), ev
->y(), ev
->globalX(), ev
->globalY() );
1161 if( e
->type() == QEvent::Resize
)
1163 QResizeEvent
* ev
= static_cast< QResizeEvent
* >( e
);
1164 // Filter out resize events that inform about size different than frame size.
1165 // This will ensure that decoration->width() etc. and decoration->widget()->width() will be in sync.
1166 // These events only seem to be delayed events from initial resizing before show() was called
1167 // on the decoration widget.
1168 if( ev
->size() != size())
1170 // HACK: Avoid decoration redraw delays. On resize Qt sets WA_WStateConfigPending
1171 // which delays all painting until a matching ConfigureNotify event comes.
1172 // But this process itself is the window manager, so it's not needed
1173 // to wait for that event, the geometry is known.
1174 // Note that if Qt in the future changes how this flag is handled and what it
1175 // triggers then this may potentionally break things. See mainly QETWidget::translateConfigEvent().
1176 decoration
->widget()->setAttribute( Qt::WA_WState_ConfigPending
, false );
1177 decoration
->widget()->update();
1183 // return value matters only when filtering events before decoration gets them
1184 bool Client::buttonPressEvent( Window w
, int button
, int state
, int x
, int y
, int x_root
, int y_root
)
1188 if( w
== wrapperId())
1189 XAllowEvents(display(), SyncPointer
, CurrentTime
); //xTime());
1193 if( w
== wrapperId() || w
== frameId() || w
== decorationId())
1194 { // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace
1196 workspace()->setWasUserInteraction();
1197 uint keyModX
= (options
->keyCmdAllModKey() == Qt::Key_Meta
) ?
1198 KKeyServer::modXMeta() :
1199 KKeyServer::modXAlt();
1200 bool bModKeyHeld
= keyModX
!= 0 && ( state
& KKeyServer::accelModMaskX()) == keyModX
;
1203 && button
== Button1
&& !bModKeyHeld
)
1204 { // hide splashwindow if the user clicks on it
1206 if( w
== wrapperId())
1207 XAllowEvents(display(), SyncPointer
, CurrentTime
); //xTime());
1211 Options::MouseCommand com
= Options::MouseNothing
;
1212 bool was_action
= false;
1213 bool perform_handled
= false;
1220 com
= options
->commandAll1();
1223 com
= options
->commandAll2();
1226 com
= options
->commandAll3();
1230 com
= options
->operationWindowMouseWheel( button
== Button4
? 120 : -120 );
1235 { // inactive inner window
1236 if( !isActive() && w
== wrapperId())
1239 perform_handled
= true;
1243 com
= options
->commandWindow1();
1246 com
= options
->commandWindow2();
1249 com
= options
->commandWindow3();
1252 com
= Options::MouseActivateAndPassClick
;
1255 // active inner window
1256 if( isActive() && w
== wrapperId()
1257 && options
->clickRaise
&& button
< 4 ) // exclude wheel
1259 com
= Options::MouseActivateRaiseAndPassClick
;
1261 perform_handled
= true;
1266 bool replay
= performMouseCommand( com
, QPoint( x_root
, y_root
), perform_handled
);
1268 if ( isSpecialWindow())
1271 if( w
== wrapperId()) // these can come only from a grab
1272 XAllowEvents(display(), replay
? ReplayPointer
: SyncPointer
, CurrentTime
); //xTime());
1277 if( w
== wrapperId()) // these can come only from a grab
1279 XAllowEvents(display(), ReplayPointer
, CurrentTime
); //xTime());
1282 if( w
== decorationId())
1283 return false; // don't eat decoration events
1285 processDecorationButtonPress( button
, state
, x
, y
, x_root
, y_root
);
1290 // this function processes button press events only after decoration decides not to handle them,
1291 // unlike buttonPressEvent(), which (when the window is decoration) filters events before decoration gets them
1292 void Client::processDecorationButtonPress( int button
, int /*state*/, int x
, int y
, int x_root
, int y_root
)
1294 Options::MouseCommand com
= Options::MouseNothing
;
1295 bool active
= isActive();
1296 if ( !wantsInput() ) // we cannot be active, use it anyway
1299 if ( button
== Button1
)
1300 com
= active
? options
->commandActiveTitlebar1() : options
->commandInactiveTitlebar1();
1301 else if ( button
== Button2
)
1302 com
= active
? options
->commandActiveTitlebar2() : options
->commandInactiveTitlebar2();
1303 else if ( button
== Button3
)
1304 com
= active
? options
->commandActiveTitlebar3() : options
->commandInactiveTitlebar3();
1305 if( button
== Button1
1306 && com
!= Options::MouseOperationsMenu
// actions where it's not possible to get the matching
1307 && com
!= Options::MouseMinimize
) // mouse release event
1309 mode
= mousePosition( QPoint( x
, y
));
1311 moveOffset
= QPoint( x
, y
);
1312 invertedMoveOffset
= rect().bottomRight() - moveOffset
;
1313 unrestrictedMoveResize
= false;
1314 startDelayedMoveResize();
1317 performMouseCommand( com
, QPoint( x_root
, y_root
));
1320 // called from decoration
1321 void Client::processMousePressEvent( QMouseEvent
* e
)
1323 if( e
->type() != QEvent::MouseButtonPress
)
1325 kWarning() << "processMousePressEvent()" ;
1329 switch( e
->button())
1331 case Qt::LeftButton
:
1337 case Qt::RightButton
:
1343 processDecorationButtonPress( button
, e
->buttons(), e
->x(), e
->y(), e
->globalX(), e
->globalY());
1346 // return value matters only when filtering events before decoration gets them
1347 bool Client::buttonReleaseEvent( Window w
, int /*button*/, int state
, int x
, int y
, int x_root
, int y_root
)
1349 if( w
== decorationId() && !buttonDown
)
1351 if( w
== wrapperId())
1353 XAllowEvents(display(), SyncPointer
, CurrentTime
); //xTime());
1356 if( w
!= frameId() && w
!= decorationId() && w
!= moveResizeGrabWindow())
1358 x
= this->x(); // translate from grab window to local coords
1360 if ( (state
& ( Button1Mask
& Button2Mask
& Button3Mask
)) == 0 )
1363 stopDelayedMoveResize();
1364 if ( moveResizeMode
)
1366 finishMoveResize( false );
1367 // mouse position is still relative to old Client position, adjust it
1368 QPoint
mousepos( x_root
- x
, y_root
- y
);
1369 mode
= mousePosition( mousepos
);
1376 static bool was_motion
= false;
1377 static Time next_motion_time
= CurrentTime
;
1378 // Check whole incoming X queue for MotionNotify events
1379 // checking whole queue is done by always returning False in the predicate.
1380 // If there are more MotionNotify events in the queue, all until the last
1381 // one may be safely discarded (if a ButtonRelease event comes, a MotionNotify
1382 // will be faked from it, so there's no need to check other events).
1383 // This helps avoiding being overloaded by being flooded from many events
1384 // from the XServer.
1385 static Bool
motion_predicate( Display
*, XEvent
* ev
, XPointer
)
1387 if( ev
->type
== MotionNotify
)
1390 next_motion_time
= ev
->xmotion
.time
; // for setting time
1395 static bool waitingMotionEvent()
1397 // The queue doesn't need to be checked until the X timestamp
1398 // of processes events reaches the timestamp of the last suitable
1399 // MotionNotify event in the queue.
1400 if( next_motion_time
!= CurrentTime
1401 && timestampCompare( xTime(), next_motion_time
) < 0 )
1404 XSync( display(), False
); // this helps to discard more MotionNotify events
1406 XCheckIfEvent( display(), &dummy
, motion_predicate
, NULL
);
1410 // return value matters only when filtering events before decoration gets them
1411 bool Client::motionNotifyEvent( Window w
, int /*state*/, int x
, int y
, int x_root
, int y_root
)
1413 if( w
!= frameId() && w
!= decorationId() && w
!= moveResizeGrabWindow())
1414 return true; // care only about the whole frame
1417 Position newmode
= mousePosition( QPoint( x
, y
));
1418 if( newmode
!= mode
)
1423 // reset the timestamp for the optimization, otherwise with long passivity
1424 // the option in waitingMotionEvent() may be always true
1425 next_motion_time
= CurrentTime
;
1428 if( w
== moveResizeGrabWindow())
1430 x
= this->x(); // translate from grab window to local coords
1433 if( !waitingMotionEvent())
1434 handleMoveResize( x
, y
, x_root
, y_root
);
1438 void Client::focusInEvent( XFocusInEvent
* e
)
1440 if( e
->window
!= window())
1441 return; // only window gets focus
1442 if ( e
->mode
== NotifyUngrab
)
1443 return; // we don't care
1444 if ( e
->detail
== NotifyPointer
)
1445 return; // we don't care
1446 if( !isShown( false ) || !isOnCurrentDesktop()) // we unmapped it, but it got focus meanwhile ->
1447 return; // activateNextClient() already transferred focus elsewhere
1448 // check if this client is in should_get_focus list or if activation is allowed
1449 bool activate
= workspace()->allowClientActivation( this, -1U, true );
1450 workspace()->gotFocusIn( this ); // remove from should_get_focus list
1455 workspace()->restoreFocus();
1460 // When a client loses focus, FocusOut events are usually immediatelly
1461 // followed by FocusIn events for another client that gains the focus
1462 // (unless the focus goes to another screen, or to the nofocus widget).
1463 // Without this check, the former focused client would have to be
1464 // deactivated, and after that, the new one would be activated, with
1465 // a short time when there would be no active client. This can cause
1466 // flicker sometimes, e.g. when a fullscreen is shown, and focus is transferred
1467 // from it to its transient, the fullscreen would be kept in the Active layer
1468 // at the beginning and at the end, but not in the middle, when the active
1469 // client would be temporarily none (see Client::belongToLayer() ).
1470 // Therefore, the events queue is checked, whether it contains the matching
1471 // FocusIn event, and if yes, deactivation of the previous client will
1472 // be skipped, as activation of the new one will automatically deactivate
1473 // previously active client.
1474 static bool follows_focusin
= false;
1475 static bool follows_focusin_failed
= false;
1476 static Bool
predicate_follows_focusin( Display
*, XEvent
* e
, XPointer arg
)
1478 if( follows_focusin
|| follows_focusin_failed
)
1480 Client
* c
= ( Client
* ) arg
;
1481 if( e
->type
== FocusIn
&& c
->workspace()->findClient( WindowMatchPredicate( e
->xfocus
.window
)))
1483 follows_focusin
= true;
1486 // events that may be in the queue before the FocusIn event that's being
1488 if( e
->type
== FocusIn
|| e
->type
== FocusOut
|| e
->type
== KeymapNotify
)
1490 follows_focusin_failed
= true; // a different event - stop search
1494 static bool check_follows_focusin( Client
* c
)
1496 follows_focusin
= follows_focusin_failed
= false;
1498 // XCheckIfEvent() is used to make the search non-blocking, the predicate
1499 // always returns False, so nothing is removed from the events queue.
1500 // XPeekIfEvent() would block.
1501 XCheckIfEvent( display(), &dummy
, predicate_follows_focusin
, (XPointer
)c
);
1502 return follows_focusin
;
1506 void Client::focusOutEvent( XFocusOutEvent
* e
)
1508 if( e
->window
!= window())
1509 return; // only window gets focus
1510 if ( e
->mode
== NotifyGrab
)
1511 return; // we don't care
1513 return; // here neither
1514 if ( e
->detail
!= NotifyNonlinear
1515 && e
->detail
!= NotifyNonlinearVirtual
)
1516 // SELI check all this
1517 return; // hack for motif apps like netscape
1518 if ( QApplication::activePopupWidget() )
1520 if( !check_follows_focusin( this ))
1524 // performs _NET_WM_MOVERESIZE
1525 void Client::NETMoveResize( int x_root
, int y_root
, NET::Direction direction
)
1527 if( direction
== NET::Move
)
1528 performMouseCommand( Options::MouseMove
, QPoint( x_root
, y_root
));
1529 else if( moveResizeMode
&& direction
== NET::MoveResizeCancel
)
1531 finishMoveResize( true );
1535 else if( direction
>= NET::TopLeft
&& direction
<= NET::Left
)
1537 static const Position convert
[] =
1543 PositionBottomRight
,
1548 if(!isResizable() || isShade())
1550 if( moveResizeMode
)
1551 finishMoveResize( false );
1553 moveOffset
= QPoint( x_root
- x(), y_root
- y()); // map from global
1554 invertedMoveOffset
= rect().bottomRight() - moveOffset
;
1555 unrestrictedMoveResize
= false;
1556 mode
= convert
[ direction
];
1557 if( !startMoveResize())
1561 else if( direction
== NET::KeyboardMove
)
1562 { // ignore mouse coordinates given in the message, mouse position is used by the moving algorithm
1563 QCursor::setPos( geometry().center() );
1564 performMouseCommand( Options::MouseUnrestrictedMove
, geometry().center());
1566 else if( direction
== NET::KeyboardSize
)
1567 { // ignore mouse coordinates given in the message, mouse position is used by the resizing algorithm
1568 QCursor::setPos( geometry().bottomRight());
1569 performMouseCommand( Options::MouseUnrestrictedResize
, geometry().bottomRight());
1573 void Client::keyPressEvent( uint key_code
)
1576 if ( !isMove() && !isResize() )
1578 bool is_control
= key_code
& Qt::CTRL
;
1579 bool is_alt
= key_code
& Qt::ALT
;
1580 key_code
= key_code
& ~Qt::KeyboardModifierMask
;
1581 int delta
= is_control
?1:is_alt
?32:8;
1582 QPoint pos
= cursorPos();
1598 case Qt::Key_Return
:
1600 finishMoveResize( false );
1604 case Qt::Key_Escape
:
1605 finishMoveResize( true );
1612 QCursor::setPos( pos
);
1616 void Client::syncEvent( XSyncAlarmNotifyEvent
* e
)
1618 if( e
->alarm
== sync_alarm
&& XSyncValueEqual( e
->counter_value
, sync_counter_value
))
1620 ready_for_painting
= true;
1623 delete sync_timeout
;
1624 sync_timeout
= NULL
;
1625 if( sync_resize_pending
)
1626 performMoveResize();
1632 // ****************************************
1634 // ****************************************
1636 bool Unmanaged::windowEvent( XEvent
* e
)
1638 double old_opacity
= opacity();
1639 unsigned long dirty
[ 2 ];
1640 info
->event( e
, dirty
, 2 ); // pass through the NET stuff
1641 if( dirty
[ NETWinInfo::PROTOCOLS2
] & NET::WM2Opacity
)
1646 scene
->windowOpacityChanged( this );
1648 static_cast<EffectsHandlerImpl
*>(effects
)->windowOpacityChanged( effectWindow(), old_opacity
);
1654 unmapNotifyEvent( &e
->xunmap
);
1657 mapNotifyEvent( &e
->xmap
);
1659 case ConfigureNotify
:
1660 configureNotifyEvent( &e
->xconfigure
);
1662 case PropertyNotify
:
1663 propertyNotifyEvent( &e
->xproperty
);
1667 if( e
->type
== Extensions::shapeNotifyEvent() )
1669 detectShape( window());
1672 scene
->windowGeometryShapeChanged( this );
1673 if( effects
!= NULL
)
1674 static_cast<EffectsHandlerImpl
*>(effects
)->windowGeometryShapeChanged( effectWindow(), geometry());
1677 if( e
->type
== Extensions::damageNotifyEvent())
1678 damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent
* >( e
));
1683 return false; // don't eat events, even our own unmanaged widgets are tracked
1686 void Unmanaged::mapNotifyEvent( XMapEvent
* )
1690 void Unmanaged::unmapNotifyEvent( XUnmapEvent
* )
1695 void Unmanaged::configureNotifyEvent( XConfigureEvent
* e
)
1698 static_cast<EffectsHandlerImpl
*>(effects
)->checkInputWindowStacking(); // keep them on top
1699 QRect
newgeom( e
->x
, e
->y
, e
->width
, e
->height
);
1700 if( newgeom
!= geom
)
1702 addWorkspaceRepaint( geometry()); // damage old area
1705 discardWindowPixmap();
1707 scene
->windowGeometryShapeChanged( this );
1708 if( effects
!= NULL
)
1709 static_cast<EffectsHandlerImpl
*>(effects
)->windowGeometryShapeChanged( effectWindow(), old
);
1711 workspace()->restackUnmanaged( this, e
->above
);
1714 // ****************************************
1716 // ****************************************
1718 void Toplevel::propertyNotifyEvent( XPropertyEvent
* e
)
1720 if( e
->window
!= window())
1721 return; // ignore frame/wrapper
1725 if (e
->atom
== atoms
->wm_client_leader
)
1726 getWmClientLeader();
1727 else if( e
->atom
== atoms
->wm_window_role
)
1732 static_cast< EffectsHandlerImpl
* >( effects
)->propertyNotify( effectWindow(), e
->atom
);
1735 // ****************************************
1737 // ****************************************
1739 bool Group::groupEvent( XEvent
* e
)
1741 unsigned long dirty
[ 2 ];
1742 leader_info
->event( e
, dirty
, 2 ); // pass through the NET stuff
1743 if ( ( dirty
[ WinInfo::PROTOCOLS
] & NET::WMIcon
) != 0 )
1745 if(( dirty
[ WinInfo::PROTOCOLS2
] & NET::WM2StartupId
) != 0 )