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 : 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 // ****************************************
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
)
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
)
143 if( src
== NET::FromTool
)
144 workspace
->activateClient( c
, true ); // force
145 else // NET::FromApplication
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
);
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
)
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
));
189 void RootInfo::moveResize(Window w
, int x_root
, int y_root
, unsigned long direction
)
191 Client
* c
= workspace
->findClient( WindowMatchPredicate( w
));
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
));
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 // ****************************************
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;
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
250 was_user_interaction
= true;
253 if ( tab_grab
|| control_grab
)
255 tab_box
->handleMouseEvent( e
);
258 if( effects
&& static_cast<EffectsHandlerImpl
*>(effects
)->checkInputWindowEvent( e
))
263 was_user_interaction
= true;
265 KKeyServer::xEventToQt(e
, &keyQt
);
266 // kDebug(125) << "Workspace::keyPress( " << keyQt << " )";
269 movingClient
->keyPressEvent(keyQt
);
272 if( tab_grab
|| control_grab
)
274 tabBoxKeyPress( keyQt
);
280 was_user_interaction
= true;
281 if( tab_grab
|| control_grab
)
283 tabBoxKeyRelease( e
->xkey
);
287 case ConfigureNotify
:
288 if( e
->xconfigure
.event
== rootWindow())
289 x_stacking_dirty
= true;
293 if( Client
* c
= findClient( WindowMatchPredicate( e
->xany
.window
)))
295 if( c
->windowEvent( e
))
298 else if( Client
* c
= findClient( WrapperIdMatchPredicate( e
->xany
.window
)))
300 if( c
->windowEvent( e
))
303 else if( Client
* c
= findClient( FrameIdMatchPredicate( e
->xany
.window
)))
305 if( c
->windowEvent( e
))
308 else if( Unmanaged
* c
= findUnmanaged( WindowMatchPredicate( e
->xany
.window
)))
310 if( c
->windowEvent( e
))
315 Window special
= findSpecialEventWindow( e
);
316 if( special
!= None
)
317 if( Client
* c
= findClient( WindowMatchPredicate( special
)))
319 if( c
->windowEvent( e
))
323 if( movingClient
!= NULL
&& movingClient
->moveResizeGrabWindow() == e
->xany
.window
324 && ( e
->type
== MotionNotify
|| e
->type
== ButtonPress
|| e
->type
== ButtonRelease
))
326 if( movingClient
->windowEvent( e
))
333 if ( e
->xcreatewindow
.parent
== rootWindow() &&
334 !QWidget::find( e
->xcreatewindow
.window
) &&
335 !e
->xcreatewindow
.override_redirect
)
337 // see comments for allowClientActivation()
339 XChangeProperty(display(), e
->xcreatewindow
.window
,
340 atoms
->kde_net_wm_user_creation_time
, XA_CARDINAL
,
341 32, PropModeReplace
, (unsigned char *)&t
, 1);
347 return ( e
->xunmap
.event
!= e
->xunmap
.window
); // hide wm typical event from Qt
351 //do not confuse Qt with these events. After all, _we_ are the
352 //window manager who does the reparenting.
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
));
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
);
384 updateFocusChains( c
, FocusChainUpdate
);
391 if( e
->xmap
.override_redirect
)
393 Unmanaged
* c
= findUnmanaged( WindowMatchPredicate( e
->xmap
.window
));
395 c
= createUnmanaged( e
->xmap
.window
);
397 return c
->windowEvent( e
);
399 return ( e
->xmap
.event
!= e
->xmap
.window
); // hide wm typical event from Qt
404 if ( QWhatsThis::inWhatsThisMode() )
406 QWidget
* w
= QWidget::find( e
->xcrossing
.window
);
408 QWhatsThis::leaveWhatsThisMode();
410 if( electricBorderEvent(e
))
416 if ( !QWhatsThis::inWhatsThisMode() )
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();
424 case ConfigureRequest
:
426 if ( e
->xconfigurerequest
.parent
== rootWindow())
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
;
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
);
444 if ( mouse_emulation
)
445 return keyPressMouseEmulation( e
->xkey
);
448 if ( mouse_emulation
)
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)
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();
464 requestFocus( c
, true );
465 else if( activateNextClient( NULL
))
473 return true; // always eat these, they would tell Qt that KWin is the active app
475 if( electricBorderEvent( e
))
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
);
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
494 QTimer::singleShot( 2000, this, SLOT( addRepaintFull()));
496 checkCompositeTimer();
500 if( e
->type
== Extensions::randrNotifyEvent() && Extensions::randrAvailable() )
503 XRRUpdateConfiguration( e
);
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
511 QTimer::singleShot( 0, this, SLOT( setupCompositing() ) );
514 else if( e
->type
== Extensions::syncAlarmNotifyEvent() && Extensions::syncAvailable())
517 foreach( Client
* c
, clients
)
518 c
->syncEvent( reinterpret_cast< XSyncAlarmNotifyEvent
* >( e
));
519 foreach( Client
* c
, desktops
)
520 c
->syncEvent( reinterpret_cast< XSyncAlarmNotifyEvent
* >( e
));
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
));
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
)
550 return e
->xcreatewindow
.window
;
552 return e
->xdestroywindow
.window
;
554 return e
->xunmap
.window
;
556 return e
->xmap
.window
;
558 return e
->xmaprequest
.window
;
560 return e
->xreparent
.window
;
561 case ConfigureNotify
:
562 return e
->xconfigure
.window
;
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
;
576 // ****************************************
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 )
593 if ( ( dirty
[ WinInfo::PROTOCOLS
] & NET::WMIconName
) != 0 )
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 )
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 )
614 if( dirty
[ WinInfo::PROTOCOLS
] & NET::WMIconGeometry
)
616 if( demandAttentionKNotifyTimer
!= NULL
)
617 demandAttentionKNotify();
619 if( dirty
[ WinInfo::PROTOCOLS2
] & NET::WM2Opacity
)
624 scene
->windowOpacityChanged( this );
626 static_cast<EffectsHandlerImpl
*>(effects
)->windowOpacityChanged( effectWindow(), old_opacity
);
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());
639 unmapNotifyEvent( &e
->xunmap
);
642 destroyNotifyEvent( &e
->xdestroywindow
);
645 // this one may pass the event to workspace
646 return mapRequestEvent( &e
->xmaprequest
);
647 case ConfigureRequest
:
648 configureRequestEvent( &e
->xconfigurerequest
);
651 propertyNotifyEvent( &e
->xproperty
);
655 workspace()->setWasUserInteraction();
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
);
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
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
);
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
));
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
));
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 ));
699 focusInEvent( &e
->xfocus
);
702 focusOutEvent( &e
->xfocus
);
707 clientMessageEvent( &e
->xclient
);
709 case ColormapChangeMask
:
710 if( e
->xany
.window
== window())
712 cmap
= e
->xcolormap
.colormap
;
714 workspace()->updateColormap();
718 if( e
->xany
.window
== window())
720 if( e
->type
== Extensions::shapeNotifyEvent() )
722 detectShape( window()); // workaround for #19644
726 if( e
->xany
.window
== frameId())
729 if( e
->type
== Extensions::damageNotifyEvent())
730 damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent
* >( e
));
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())
759 return true; // no messing with frame etc.
761 if( isTopMenu() && workspace()->managingTopMenus())
762 return true; // kwin controls these
763 // also copied in clientMessage()
767 setShade( ShadeNone
);
768 if( !isOnCurrentDesktop())
770 if( workspace()->allowClientActivation( this ))
771 workspace()->activateClient( this );
779 Handles unmap notify events of the client window
781 void Client::unmapNotifyEvent( XUnmapEvent
* e
)
783 if( e
->window
!= window())
785 if( e
->event
!= wrapperId())
786 { // most probably event from root window when initially reparenting
788 if( e
->event
== rootWindow() && e
->send_event
)
789 ignore
= false; // XWithdrawWindow()
796 void Client::destroyNotifyEvent( XDestroyWindowEvent
* e
)
798 if( e
->window
!= window())
805 Handles client messages for the client window
807 void Client::clientMessageEvent( XClientMessageEvent
* e
)
809 if( e
->window
!= window())
810 return; // ignore frame/wrapper
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
)
819 else if( e
->data
.l
[ 0 ] == NormalState
)
820 { // copied from mapRequest()
822 unminimize( avoid_animation
);
824 setShade( ShadeNone
);
825 if( !isOnCurrentDesktop())
827 if( workspace()->allowClientActivation( this ))
828 workspace()->activateClient( this );
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
)
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();
860 if( isSplash() // no manipulations with splashscreens either
861 || isTopMenu()) // topmenus neither
863 sendSyntheticConfigureNotify();
867 if ( e
->value_mask
& CWBorderWidth
)
869 // first, get rid of a window border
871 unsigned int value_mask
= 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
906 case XA_WM_NORMAL_HINTS
:
912 case XA_WM_ICON_NAME
:
915 case XA_WM_TRANSIENT_FOR
:
920 getIcons(); // because KWin::icon() uses WMHints as fallback
923 if ( e
->atom
== atoms
->wm_protocols
)
924 getWindowProtocols();
925 else if( e
->atom
== atoms
->motif_wm_hints
)
927 else if( e
->atom
== atoms
->net_wm_sync_request_counter
)
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();
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
)
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() ) )
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 );
981 workspace()->requestFocus( this );
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
)
995 mode
= PositionCenter
;
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
)
1011 if( XQueryPointer( display(), frameId(), &w
, &child
, &d1
, &d2
, &d3
, &d4
, &d5
) == False
1013 lostMouse
= true; // really lost the mouse
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 ) ;
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
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
1066 XUngrabButton( display(), AnyButton
,
1067 modifier
| mods
[ i
], wrapperId());
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
))
1090 if( isActive() && !workspace()->forcedGlobalMouseGrab()) // see Workspace::establishTabBoxGrab()
1092 // first grab all modifier combinations
1093 XGrabButton( display(), AnyButton
, AnyModifier
, wrapperId(), false,
1095 GrabModeSync
, GrabModeAsync
,
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
);
1106 ungrabButton( ShiftMask
);
1107 ungrabButton( ControlMask
);
1108 ungrabButton( ControlMask
| ShiftMask
);
1112 XUngrabButton( display(), AnyButton
, AnyModifier
, wrapperId());
1113 // simply grab all modifier combinations
1114 XGrabButton(display(), AnyButton
, AnyModifier
, wrapperId(), false,
1116 GrabModeSync
, GrabModeAsync
,
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())
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() );
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())
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();
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
)
1182 if( w
== wrapperId())
1183 XAllowEvents(display(), SyncPointer
, CurrentTime
); //xTime());
1187 if( w
== wrapperId() || w
== frameId() || w
== decorationId())
1188 { // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace
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
;
1197 && button
== Button1
&& !bModKeyHeld
)
1198 { // hide splashwindow if the user clicks on it
1200 if( w
== wrapperId())
1201 XAllowEvents(display(), SyncPointer
, CurrentTime
); //xTime());
1205 Options::MouseCommand com
= Options::MouseNothing
;
1206 bool was_action
= false;
1207 bool perform_handled
= false;
1214 com
= options
->commandAll1();
1217 com
= options
->commandAll2();
1220 com
= options
->commandAll3();
1224 com
= options
->operationWindowMouseWheel( button
== Button4
? 120 : -120 );
1229 { // inactive inner window
1230 if( !isActive() && w
== wrapperId() && button
< 4 )
1233 perform_handled
= true;
1237 com
= options
->commandWindow1();
1240 com
= options
->commandWindow2();
1243 com
= options
->commandWindow3();
1247 // active inner window
1248 if( isActive() && w
== wrapperId()
1249 && options
->clickRaise
&& button
< 4 ) // exclude wheel
1251 com
= Options::MouseActivateRaiseAndPassClick
;
1253 perform_handled
= true;
1258 bool replay
= performMouseCommand( com
, QPoint( x_root
, y_root
), perform_handled
);
1260 if ( isSpecialWindow())
1263 if( w
== wrapperId()) // these can come only from a grab
1264 XAllowEvents(display(), replay
? ReplayPointer
: SyncPointer
, CurrentTime
); //xTime());
1269 if( w
== wrapperId()) // these can come only from a grab
1271 XAllowEvents(display(), ReplayPointer
, CurrentTime
); //xTime());
1274 if( w
== decorationId())
1275 return false; // don't eat decoration events
1277 processDecorationButtonPress( button
, state
, x
, y
, x_root
, y_root
);
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
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
));
1303 moveOffset
= QPoint( x
, y
);
1304 invertedMoveOffset
= rect().bottomRight() - moveOffset
;
1305 unrestrictedMoveResize
= false;
1306 startDelayedMoveResize();
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()" ;
1321 switch( e
->button())
1323 case Qt::LeftButton
:
1329 case Qt::RightButton
:
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
)
1343 if( w
== wrapperId())
1345 XAllowEvents(display(), SyncPointer
, CurrentTime
); //xTime());
1348 if( w
!= frameId() && w
!= decorationId() && w
!= moveResizeGrabWindow())
1350 x
= this->x(); // translate from grab window to local coords
1352 if ( (state
& ( Button1Mask
& Button2Mask
& Button3Mask
)) == 0 )
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
);
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
)
1382 next_motion_time
= ev
->xmotion
.time
; // for setting time
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 )
1396 XSync( display(), False
); // this helps to discard more MotionNotify events
1398 XCheckIfEvent( display(), &dummy
, motion_predicate
, NULL
);
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
1409 Position newmode
= mousePosition( QPoint( x
, y
));
1410 if( newmode
!= mode
)
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
;
1420 if( w
== moveResizeGrabWindow())
1422 x
= this->x(); // translate from grab window to local coords
1425 if( !waitingMotionEvent())
1426 handleMoveResize( x
, y
, x_root
, y_root
);
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
1447 workspace()->restoreFocus();
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
)
1472 Client
* c
= ( Client
* ) arg
;
1473 if( e
->type
== FocusIn
&& c
->workspace()->findClient( WindowMatchPredicate( e
->xfocus
.window
)))
1475 follows_focusin
= true;
1478 // events that may be in the queue before the FocusIn event that's being
1480 if( e
->type
== FocusIn
|| e
->type
== FocusOut
|| e
->type
== KeymapNotify
)
1482 follows_focusin_failed
= true; // a different event - stop search
1486 static bool check_follows_focusin( Client
* c
)
1488 follows_focusin
= follows_focusin_failed
= false;
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
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() )
1512 if( !check_follows_focusin( this ))
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 );
1527 else if( direction
>= NET::TopLeft
&& direction
<= NET::Left
)
1529 static const Position convert
[] =
1535 PositionBottomRight
,
1540 if(!isResizable() || isShade())
1542 if( moveResizeMode
)
1543 finishMoveResize( false );
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())
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
)
1568 if ( !isMove() && !isResize() )
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();
1590 case Qt::Key_Return
:
1592 finishMoveResize( false );
1596 case Qt::Key_Escape
:
1597 finishMoveResize( true );
1604 QCursor::setPos( pos
);
1608 void Client::syncEvent( XSyncAlarmNotifyEvent
* e
)
1610 if( e
->alarm
== sync_alarm
&& XSyncValueEqual( e
->counter_value
, sync_counter_value
))
1612 ready_for_painting
= true;
1615 delete sync_timeout
;
1616 sync_timeout
= NULL
;
1617 if( sync_resize_pending
)
1618 performMoveResize();
1624 // ****************************************
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
)
1638 scene
->windowOpacityChanged( this );
1640 static_cast<EffectsHandlerImpl
*>(effects
)->windowOpacityChanged( effectWindow(), old_opacity
);
1646 unmapNotifyEvent( &e
->xunmap
);
1649 mapNotifyEvent( &e
->xmap
);
1651 case ConfigureNotify
:
1652 configureNotifyEvent( &e
->xconfigure
);
1654 case PropertyNotify
:
1655 propertyNotifyEvent( &e
->xproperty
);
1659 if( e
->type
== Extensions::shapeNotifyEvent() )
1661 detectShape( window());
1663 addWorkspaceRepaint( geometry()); // in case shape change removes part of this window
1665 scene
->windowGeometryShapeChanged( this );
1666 if( effects
!= NULL
)
1667 static_cast<EffectsHandlerImpl
*>(effects
)->windowGeometryShapeChanged( effectWindow(), geometry());
1670 if( e
->type
== Extensions::damageNotifyEvent())
1671 damageNotifyEvent( reinterpret_cast< XDamageNotifyEvent
* >( e
));
1676 return false; // don't eat events, even our own unmanaged widgets are tracked
1679 void Unmanaged::mapNotifyEvent( XMapEvent
* )
1683 void Unmanaged::unmapNotifyEvent( XUnmapEvent
* )
1688 void Unmanaged::configureNotifyEvent( XConfigureEvent
* e
)
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
1699 if( old
.size() != geom
.size())
1700 discardWindowPixmap();
1702 scene
->windowGeometryShapeChanged( this );
1703 if( effects
!= NULL
)
1704 static_cast<EffectsHandlerImpl
*>(effects
)->windowGeometryShapeChanged( effectWindow(), old
);
1708 // ****************************************
1710 // ****************************************
1712 void Toplevel::propertyNotifyEvent( XPropertyEvent
* e
)
1714 if( e
->window
!= window())
1715 return; // ignore frame/wrapper
1719 if (e
->atom
== atoms
->wm_client_leader
)
1720 getWmClientLeader();
1721 else if( e
->atom
== atoms
->wm_window_role
)
1726 static_cast< EffectsHandlerImpl
* >( effects
)->propertyNotify( effectWindow(), e
->atom
);
1729 // ****************************************
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 )
1739 if(( dirty
[ WinInfo::PROTOCOLS2
] & NET::WM2StartupId
) != 0 )