diff options
Diffstat (limited to 'kwin/events.cpp')
-rw-r--r-- | kwin/events.cpp | 1784 |
1 files changed, 0 insertions, 1784 deletions
diff --git a/kwin/events.cpp b/kwin/events.cpp deleted file mode 100644 index 45f4f6e35..000000000 --- a/kwin/events.cpp +++ /dev/null @@ -1,1784 +0,0 @@ -/***************************************************************** - KWin - the KDE window manager - This file is part of the KDE project. - -Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org> -Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> - -You can Freely distribute this program under the GNU General Public -License. See the file "COPYING" for the exact licensing terms. -******************************************************************/ - -/* - - This file contains things relevant to handling incoming events. - -*/ - -#include "client.h" -#include "workspace.h" -#include "atoms.h" -#include "tabbox.h" -#include "group.h" -#include "rules.h" - -#include <tqwhatsthis.h> -#include <kkeynative.h> -#include <tqapplication.h> - -#include <X11/extensions/shape.h> -#include <X11/Xatom.h> -#include <stdlib.h> - -extern Atom qt_window_role; - -namespace KWinInternal -{ - -// **************************************** -// WinInfo -// **************************************** - -WinInfo::WinInfo( Client * c, Display * display, Window window, - Window rwin, const unsigned long pr[], int pr_size ) - : NETWinInfo( display, window, rwin, pr, pr_size, NET::WindowManager ), m_client( c ) - { - } - -void WinInfo::changeDesktop(int desktop) - { - m_client->workspace()->sendClientToDesktop( m_client, desktop, true ); - } - -void WinInfo::changeState( unsigned long state, unsigned long mask ) - { - mask &= ~NET::Sticky; // KWin doesn't support large desktops, ignore - mask &= ~NET::Hidden; // clients are not allowed to change this directly - state &= mask; // for safety, clear all other bits - - if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) == 0 ) - m_client->setFullScreen( false, false ); - if ( (mask & NET::Max) == NET::Max ) - m_client->setMaximize( state & NET::MaxVert, state & NET::MaxHoriz ); - else if ( mask & NET::MaxVert ) - m_client->setMaximize( state & NET::MaxVert, m_client->maximizeMode() & Client::MaximizeHorizontal ); - else if ( mask & NET::MaxHoriz ) - m_client->setMaximize( m_client->maximizeMode() & Client::MaximizeVertical, state & NET::MaxHoriz ); - - if ( mask & NET::Shaded ) - m_client->setShade( state & NET::Shaded ? ShadeNormal : ShadeNone ); - if ( mask & NET::KeepAbove) - m_client->setKeepAbove( (state & NET::KeepAbove) != 0 ); - if ( mask & NET::KeepBelow) - m_client->setKeepBelow( (state & NET::KeepBelow) != 0 ); - if( mask & NET::SkipTaskbar ) - m_client->setSkipTaskbar( ( state & NET::SkipTaskbar ) != 0, true ); - if( mask & NET::SkipPager ) - m_client->setSkipPager( ( state & NET::SkipPager ) != 0 ); - if( mask & NET::DemandsAttention ) - m_client->demandAttention(( state & NET::DemandsAttention ) != 0 ); - if( mask & NET::Modal ) - m_client->setModal( ( state & NET::Modal ) != 0 ); - // unsetting fullscreen first, setting it last (because e.g. maximize works only for !isFullScreen() ) - if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) != 0 ) - m_client->setFullScreen( true, false ); - } - - -// **************************************** -// RootInfo -// **************************************** - -RootInfo::RootInfo( Workspace* ws, Display *dpy, Window w, const char *name, unsigned long pr[], int pr_num, int scr ) - : NETRootInfo4( dpy, w, name, pr, pr_num, scr ) - { - workspace = ws; - } - -void RootInfo::changeNumberOfDesktops(int n) - { - workspace->setNumberOfDesktops( n ); - } - -void RootInfo::changeCurrentDesktop(int d) - { - workspace->setCurrentDesktop( d ); - } - -void RootInfo::changeActiveWindow( Window w, NET::RequestSource src, Time timestamp, Window active_window ) - { - if( Client* c = workspace->findClient( WindowMatchPredicate( w ))) - { - if( timestamp == CurrentTime ) - timestamp = c->userTime(); - if( src != NET::FromApplication && src != FromTool ) - src = NET::FromTool; - if( src == NET::FromTool ) - workspace->activateClient( c, true ); // force - else // NET::FromApplication - { - Client* c2; - if( workspace->allowClientActivation( c, timestamp )) - workspace->activateClient( c ); - // if activation of the requestor's window would be allowed, allow activation too - else if( active_window != None - && ( c2 = workspace->findClient( WindowMatchPredicate( active_window ))) != NULL - && workspace->allowClientActivation( c2, - timestampCompare( timestamp, c2->userTime() > 0 ? timestamp : c2->userTime()))) - workspace->activateClient( c ); - else - c->demandAttention(); - } - } - } - -void RootInfo::restackWindow( Window w, RequestSource src, Window above, int detail, Time timestamp ) - { - if( Client* c = workspace->findClient( WindowMatchPredicate( w ))) - { - if( timestamp == CurrentTime ) - timestamp = c->userTime(); - if( src != NET::FromApplication && src != FromTool ) - src = NET::FromTool; - c->restackWindow( above, detail, src, timestamp, true ); - } - } - -void RootInfo::gotTakeActivity( Window w, Time timestamp, long flags ) - { - if( Client* c = workspace->findClient( WindowMatchPredicate( w ))) - workspace->handleTakeActivity( c, timestamp, flags ); - } - -void RootInfo::closeWindow(Window w) - { - Client* c = workspace->findClient( WindowMatchPredicate( w )); - if ( c ) - c->closeWindow(); - } - -void RootInfo::moveResize(Window w, int x_root, int y_root, unsigned long direction) - { - Client* c = workspace->findClient( WindowMatchPredicate( w )); - if ( c ) - { - updateXTime(); // otherwise grabbing may have old timestamp - this message should include timestamp - c->NETMoveResize( x_root, y_root, (Direction)direction); - } - } - -void RootInfo::moveResizeWindow(Window w, int flags, int x, int y, int width, int height ) - { - Client* c = workspace->findClient( WindowMatchPredicate( w )); - if ( c ) - c->NETMoveResizeWindow( flags, x, y, width, height ); - } - -void RootInfo::gotPing( Window w, Time timestamp ) - { - if( Client* c = workspace->findClient( WindowMatchPredicate( w ))) - c->gotPing( timestamp ); - } - -void RootInfo::changeShowingDesktop( bool showing ) - { - workspace->setShowingDesktop( showing ); - } - -// **************************************** -// Workspace -// **************************************** - -/*! - Handles workspace specific XEvents - */ -bool Workspace::workspaceEvent( XEvent * e ) - { - if ( mouse_emulation && (e->type == ButtonPress || e->type == ButtonRelease ) ) - { - mouse_emulation = FALSE; - XUngrabKeyboard( qt_xdisplay(), GET_QT_X_TIME() ); - } - - if( e->type == PropertyNotify || e->type == ClientMessage ) - { - unsigned long dirty[ NETRootInfo::PROPERTIES_SIZE ]; - rootInfo->event( e, dirty, NETRootInfo::PROPERTIES_SIZE ); - if( dirty[ NETRootInfo::PROTOCOLS ] & NET::DesktopNames ) - saveDesktopSettings(); - if( dirty[ NETRootInfo::PROTOCOLS2 ] & NET::WM2DesktopLayout ) - updateDesktopLayout(); - } - - // events that should be handled before Clients can get them - switch (e->type) - { - case ButtonPress: - case ButtonRelease: - was_user_interaction = true; - // fallthrough - case MotionNotify: - if ( tab_grab || control_grab ) - { - tab_box->handleMouseEvent( e ); - return TRUE; - } - break; - case KeyPress: - { - was_user_interaction = true; - KKeyNative keyX( (XEvent*)e ); - uint keyQt = keyX.keyCodeQt(); - kdDebug(125) << "Workspace::keyPress( " << keyX.key().toString() << " )" << endl; - if (movingClient) - { - movingClient->keyPressEvent(keyQt); - return true; - } - if( tab_grab || control_grab ) - { - tabBoxKeyPress( keyX ); - return true; - } - break; - } - case KeyRelease: - was_user_interaction = true; - if( tab_grab || control_grab ) - { - tabBoxKeyRelease( e->xkey ); - return true; - } - break; - }; - - if( Client* c = findClient( WindowMatchPredicate( e->xany.window ))) - { - if( c->windowEvent( e )) - return true; - } - else if( Client* c = findClient( WrapperIdMatchPredicate( e->xany.window ))) - { - if( c->windowEvent( e )) - return true; - } - else if( Client* c = findClient( FrameIdMatchPredicate( e->xany.window ))) - { - if( c->windowEvent( e )) - return true; - } - else - { - Window special = findSpecialEventWindow( e ); - if( special != None ) - if( Client* c = findClient( WindowMatchPredicate( special ))) - { - if( c->windowEvent( e )) - return true; - } - } - if( movingClient != NULL && movingClient->moveResizeGrabWindow() == e->xany.window - && ( e->type == MotionNotify || e->type == ButtonPress || e->type == ButtonRelease )) - { - if( movingClient->windowEvent( e )) - return true; - } - - switch (e->type) - { - case CreateNotify: - if ( e->xcreatewindow.parent == root && - !TQWidget::find( e->xcreatewindow.window) && - !e->xcreatewindow.override_redirect ) - { - // see comments for allowClientActivation() - Time my_qtx_time = GET_QT_X_TIME(); - XChangeProperty(qt_xdisplay(), e->xcreatewindow.window, - atoms->kde_net_wm_user_creation_time, XA_CARDINAL, - 32, PropModeReplace, (unsigned char *)&my_qtx_time, 1); - SET_QT_X_TIME(my_qtx_time); - } - break; - - case UnmapNotify: - { - // check for system tray windows - if ( removeSystemTrayWin( e->xunmap.window, true ) ) - { - // If the system tray gets destroyed, the system tray - // icons automatically get unmapped, reparented and mapped - // again to the closest non-client ancestor due to - // QXEmbed's SaveSet feature. Unfortunatly with kicker - // this closest ancestor is not the root window, but our - // decoration, so we reparent explicitely back to the root - // window. - XEvent ev; - WId w = e->xunmap.window; - if ( XCheckTypedWindowEvent (qt_xdisplay(), w, - ReparentNotify, &ev) ) - { - if ( ev.xreparent.parent != root ) - { - XReparentWindow( qt_xdisplay(), w, root, 0, 0 ); - addSystemTrayWin( w ); - } - } - return TRUE; - } - - return ( e->xunmap.event != e->xunmap.window ); // hide wm typical event from Qt - } - case MapNotify: - - return ( e->xmap.event != e->xmap.window ); // hide wm typical event from Qt - - case ReparentNotify: - { - //do not confuse Qt with these events. After all, _we_ are the - //window manager who does the reparenting. - return TRUE; - } - case DestroyNotify: - { - if ( removeSystemTrayWin( e->xdestroywindow.window, false ) ) - return TRUE; - return false; - } - case MapRequest: - { - updateXTime(); - - // e->xmaprequest.window is different from e->xany.window - // TODO this shouldn't be necessary now - Client* c = findClient( WindowMatchPredicate( e->xmaprequest.window )); - if ( !c ) - { -// don't check for the parent being the root window, this breaks when some app unmaps -// a window, changes something and immediately maps it back, without giving KWin -// a chance to reparent it back to root -// since KWin can get MapRequest only for root window children and -// children of WindowWrapper (=clients), the check is AFAIK useless anyway -// Note: Now the save-set support in Client::mapRequestEvent() actually requires that -// this code doesn't check the parent to be root. -// if ( e->xmaprequest.parent == root ) { //###TODO store previously destroyed client ids - if ( addSystemTrayWin( e->xmaprequest.window ) ) - return TRUE; - c = createClient( e->xmaprequest.window, false ); - if ( c != NULL && root != qt_xrootwin() ) - { // TODO what is this? - // TODO may use TQWidget::create - XReparentWindow( qt_xdisplay(), c->frameId(), root, 0, 0 ); - } - if( c == NULL ) // refused to manage, simply map it (most probably override redirect) - XMapRaised( qt_xdisplay(), e->xmaprequest.window ); - return true; - } - if( c ) - { - c->windowEvent( e ); - updateFocusChains( c, FocusChainUpdate ); - return true; - } - break; - } - case EnterNotify: - { - if ( TQWhatsThis::inWhatsThisMode() ) - { - TQWidget* w = TQWidget::find( e->xcrossing.window ); - if ( w ) - TQWhatsThis::leaveWhatsThisMode(); - } - if( electricBorder(e)) - return true; - break; - } - case LeaveNotify: - { - if ( !TQWhatsThis::inWhatsThisMode() ) - break; - // TODO is this cliente ever found, given that client events are searched above? - Client* c = findClient( FrameIdMatchPredicate( e->xcrossing.window )); - if ( c && e->xcrossing.detail != NotifyInferior ) - TQWhatsThis::leaveWhatsThisMode(); - break; - } - case ConfigureRequest: - { - if ( e->xconfigurerequest.parent == root ) - { - XWindowChanges wc; - wc.border_width = e->xconfigurerequest.border_width; - wc.x = e->xconfigurerequest.x; - wc.y = e->xconfigurerequest.y; - wc.width = e->xconfigurerequest.width; - wc.height = e->xconfigurerequest.height; - wc.sibling = None; - wc.stack_mode = Above; - unsigned int value_mask = e->xconfigurerequest.value_mask - & ( CWX | CWY | CWWidth | CWHeight | CWBorderWidth ); - XConfigureWindow( qt_xdisplay(), e->xconfigurerequest.window, value_mask, &wc ); - return true; - } - break; - } - case KeyPress: - if ( mouse_emulation ) - return keyPressMouseEmulation( e->xkey ); - break; - case KeyRelease: - if ( mouse_emulation ) - return FALSE; - break; - case FocusIn: - if( e->xfocus.window == rootWin() && TQCString( getenv("KDE_MULTIHEAD")).lower() != "true" - && ( e->xfocus.detail == NotifyDetailNone || e->xfocus.detail == NotifyPointerRoot )) - { - updateXTime(); // focusToNull() uses qt_x_time, which is old now (FocusIn has no timestamp) - Window focus; - int revert; - XGetInputFocus( qt_xdisplay(), &focus, &revert ); - if( focus == None || focus == PointerRoot ) - { - //kdWarning( 1212 ) << "X focus set to None/PointerRoot, reseting focus" << endl; - Client *c = mostRecentlyActivatedClient(); - if( c != NULL ) - requestFocus( c, true ); - else if( activateNextClient( NULL )) - ; // ok, activated - else - focusToNull(); - } - } - // fall through - case FocusOut: - return true; // always eat these, they would tell Qt that KWin is the active app - case ClientMessage: - if( electricBorder( e )) - return true; - break; - default: - break; - } - return FALSE; - } - -// Some events don't have the actual window which caused the event -// as e->xany.window (e.g. ConfigureRequest), but as some other -// field in the XEvent structure. -Window Workspace::findSpecialEventWindow( XEvent* e ) - { - switch( e->type ) - { - case CreateNotify: - return e->xcreatewindow.window; - case DestroyNotify: - return e->xdestroywindow.window; - case UnmapNotify: - return e->xunmap.window; - case MapNotify: - return e->xmap.window; - case MapRequest: - return e->xmaprequest.window; - case ReparentNotify: - return e->xreparent.window; - case ConfigureNotify: - return e->xconfigure.window; - case GravityNotify: - return e->xgravity.window; - case ConfigureRequest: - return e->xconfigurerequest.window; - case CirculateNotify: - return e->xcirculate.window; - case CirculateRequest: - return e->xcirculaterequest.window; - default: - return None; - }; - } - -// **************************************** -// Client -// **************************************** - -/*! - General handler for XEvents concerning the client window - */ -bool Client::windowEvent( XEvent* e ) - { - if( e->xany.window == window()) // avoid doing stuff on frame or wrapper - { - unsigned long dirty[ 2 ]; - info->event( e, dirty, 2 ); // pass through the NET stuff - - if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMName ) != 0 ) - fetchName(); - if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconName ) != 0 ) - fetchIconicName(); - if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMStrut ) != 0 - || ( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2ExtendedStrut ) != 0 ) - { - if( isTopMenu()) // the fallback mode of KMenuBar may alter the strut - checkWorkspacePosition(); // restore it - workspace()->updateClientArea(); - } - if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 ) - getIcons(); - // Note there's a difference between userTime() and info->userTime() - // info->userTime() is the value of the property, userTime() also includes - // updates of the time done by KWin (ButtonPress on windowrapper etc.). - if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2UserTime ) != 0 ) - { - workspace()->setWasUserInteraction(); - updateUserTime( info->userTime()); - } - if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 ) - startupIdChanged(); - if( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconGeometry ) - { - if( demandAttentionKNotifyTimer != NULL ) - demandAttentionKNotify(); - } - } - -// TODO move all focus handling stuff to separate file? - switch (e->type) - { - case UnmapNotify: - unmapNotifyEvent( &e->xunmap ); - break; - case DestroyNotify: - destroyNotifyEvent( &e->xdestroywindow ); - break; - case MapRequest: - // this one may pass the event to workspace - return mapRequestEvent( &e->xmaprequest ); - case ConfigureRequest: - configureRequestEvent( &e->xconfigurerequest ); - break; - case PropertyNotify: - propertyNotifyEvent( &e->xproperty ); - break; - case KeyPress: - updateUserTime(); - workspace()->setWasUserInteraction(); - break; - case ButtonPress: - updateUserTime(); - workspace()->setWasUserInteraction(); - buttonPressEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state, - e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root ); - break; - case KeyRelease: - // don't update user time on releases - // e.g. if the user presses Alt+F2, the Alt release - // would appear as user input to the currently active window - break; - case ButtonRelease: - // don't update user time on releases - // e.g. if the user presses Alt+F2, the Alt release - // would appear as user input to the currently active window - buttonReleaseEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state, - e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root ); - break; - case MotionNotify: - motionNotifyEvent( e->xmotion.window, e->xmotion.state, - e->xmotion.x, e->xmotion.y, e->xmotion.x_root, e->xmotion.y_root ); - workspace()->updateFocusMousePosition( TQPoint( e->xmotion.x_root, e->xmotion.y_root )); - break; - case EnterNotify: - enterNotifyEvent( &e->xcrossing ); - // MotionNotify is guaranteed to be generated only if the mouse - // move start and ends in the window; for cases when it only - // starts or only ends there, Enter/LeaveNotify are generated. - // Fake a MotionEvent in such cases to make handle of mouse - // events simpler (Qt does that too). - motionNotifyEvent( e->xcrossing.window, e->xcrossing.state, - e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root ); - workspace()->updateFocusMousePosition( TQPoint( e->xcrossing.x_root, e->xcrossing.y_root )); - break; - case LeaveNotify: - motionNotifyEvent( e->xcrossing.window, e->xcrossing.state, - e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root ); - leaveNotifyEvent( &e->xcrossing ); - // not here, it'd break following enter notify handling - // workspace()->updateFocusMousePosition( TQPoint( e->xcrossing.x_root, e->xcrossing.y_root )); - break; - case FocusIn: - focusInEvent( &e->xfocus ); - break; - case FocusOut: - focusOutEvent( &e->xfocus ); - break; - case ReparentNotify: - break; - case ClientMessage: - clientMessageEvent( &e->xclient ); - break; - case ColormapChangeMask: - if( e->xany.window == window()) - { - cmap = e->xcolormap.colormap; - if ( isActive() ) - workspace()->updateColormap(); - } - break; - default: - if( e->xany.window == window()) - { - if( e->type == Shape::tqshapeEvent() ) - { - is_tqshape = Shape::hasShape( window()); // workaround for #19644 - updateShape(); - } - } - break; - } - return true; // eat all events - } - -/*! - Handles map requests of the client window - */ -bool Client::mapRequestEvent( XMapRequestEvent* e ) - { - if( e->window != window()) - { - // Special support for the save-set feature, which is a bit broken. - // If there's a window from one client embedded in another one, - // e.g. using XEMBED, and the embedder suddenly looses its X connection, - // save-set will reparent the embedded window to its closest ancestor - // that will remains. Unfortunately, with reparenting window managers, - // this is not the root window, but the frame (or in KWin's case, - // it's the wrapper for the client window). In this case, - // the wrapper will get ReparentNotify for a window it won't know, - // which will be ignored, and then it gets MapRequest, as save-set - // always maps. Returning true here means that Workspace::workspaceEvent() - // will handle this MapRequest and manage this window (i.e. act as if - // it was reparented to root window). - if( e->parent == wrapperId()) - return false; - return true; // no messing with frame etc. - } - if( isTopMenu() && workspace()->managingTopMenus()) - return true; // twin controls these - switch ( mappingState() ) - { - case WithdrawnState: - assert( false ); // WMs are not supposed to manage clients in Withdrawn state, -// manage(); // after initial mapping manage() is called from createClient() - break; - case IconicState: - // also copied in clientMessage() - if( isMinimized()) - unminimize(); - if( isShade()) - setShade( ShadeNone ); - if( !isOnCurrentDesktop()) - { - if( workspace()->allowClientActivation( this )) - workspace()->activateClient( this ); - else - demandAttention(); - } - break; - case NormalState: - // TODO fake MapNotify? - break; - } - return true; - } - -/*! - Handles unmap notify events of the client window - */ -void Client::unmapNotifyEvent( XUnmapEvent* e ) - { - if( e->window != window()) - return; - if( e->event != wrapperId()) - { // most probably event from root window when initially reparenting - bool ignore = true; - if( e->event == workspace()->rootWin() && e->send_event ) - ignore = false; // XWithdrawWindow() - if( ignore ) - return; - } - switch( mappingState()) - { - case IconicState: - releaseWindow(); - return; - case NormalState: - // maybe we will be destroyed soon. Check this first. - XEvent ev; - if( XCheckTypedWindowEvent (qt_xdisplay(), window(), - DestroyNotify, &ev) ) // TODO I don't like this much - { - destroyClient(); // deletes this - return; - } - releaseWindow(); - break; - default: - assert( false ); - } - } - -void Client::destroyNotifyEvent( XDestroyWindowEvent* e ) - { - if( e->window != window()) - return; - destroyClient(); - } - - -bool blockAnimation = FALSE; - -/*! - Handles client messages for the client window -*/ -void Client::clientMessageEvent( XClientMessageEvent* e ) - { - if( e->window != window()) - return; // ignore frame/wrapper - // WM_STATE - if ( e->message_type == atoms->kde_wm_change_state ) - { - if( isTopMenu() && workspace()->managingTopMenus()) - return; // twin controls these - if( e->data.l[ 1 ] ) - blockAnimation = true; - if( e->data.l[ 0 ] == IconicState ) - minimize(); - else if( e->data.l[ 0 ] == NormalState ) - { // copied from mapRequest() - if( isMinimized()) - unminimize(); - if( isShade()) - setShade( ShadeNone ); - if( !isOnCurrentDesktop()) - { - if( workspace()->allowClientActivation( this )) - workspace()->activateClient( this ); - else - demandAttention(); - } - } - blockAnimation = false; - } - else if ( e->message_type == atoms->wm_change_state) - { - if( isTopMenu() && workspace()->managingTopMenus()) - return; // twin controls these - if ( e->data.l[0] == IconicState ) - minimize(); - return; - } - } - - -/*! - Handles configure requests of the client window - */ -void Client::configureRequestEvent( XConfigureRequestEvent* e ) - { - if( e->window != window()) - return; // ignore frame/wrapper - if ( isResize() || isMove()) - return; // we have better things to do right now - - if( fullscreen_mode == FullScreenNormal ) // refuse resizing of fullscreen windows - { // but allow resizing fullscreen hacks in order to let them cancel fullscreen mode - sendSyntheticConfigureNotify(); - return; - } - if( isSplash() // no manipulations with splashscreens either - || isTopMenu()) // topmenus neither - { - sendSyntheticConfigureNotify(); - return; - } - - if ( e->value_mask & CWBorderWidth ) - { - // first, get rid of a window border - XWindowChanges wc; - unsigned int value_mask = 0; - - wc.border_width = 0; - value_mask = CWBorderWidth; - XConfigureWindow( qt_xdisplay(), window(), value_mask, & wc ); - } - - if( e->value_mask & ( CWX | CWY | CWHeight | CWWidth )) - configureRequest( e->value_mask, e->x, e->y, e->width, e->height, 0, false ); - - if ( e->value_mask & CWStackMode ) - restackWindow( e->above, e->detail, NET::FromApplication, userTime(), false ); - - // TODO sending a synthetic configure notify always is fine, even in cases where - // the ICCCM doesn't require this - it can be though of as 'the WM decided to move - // the window later'. The client should not cause that many configure request, - // so this should not have any significant impact. With user moving/resizing - // the it should be optimized though (see also Client::setGeometry()/plainResize()/move()). - sendSyntheticConfigureNotify(); - - // SELI TODO accept configure requests for isDesktop windows (because kdesktop - // may get XRANDR resize event before twin), but check it's still at the bottom? - } - - -/*! - Handles property changes of the client window - */ -void Client::propertyNotifyEvent( XPropertyEvent* e ) - { - if( e->window != window()) - return; // ignore frame/wrapper - switch ( e->atom ) - { - case XA_WM_NORMAL_HINTS: - getWmNormalHints(); - break; - case XA_WM_NAME: - fetchName(); - break; - case XA_WM_ICON_NAME: - fetchIconicName(); - break; - case XA_WM_TRANSIENT_FOR: - readTransient(); - break; - case XA_WM_HINTS: - getWMHints(); - getIcons(); // because KWin::icon() uses WMHints as fallback - break; - default: - if ( e->atom == atoms->wm_protocols ) - getWindowProtocols(); - else if (e->atom == atoms->wm_client_leader ) - getWmClientLeader(); - else if( e->atom == qt_window_role ) - window_role = staticWindowRole( window()); - else if( e->atom == atoms->motif_wm_hints ) - getMotifHints(); - break; - } - } - - -void Client::enterNotifyEvent( XCrossingEvent* e ) - { - if( e->window != frameId()) - return; // care only about entering the whole frame - if( e->mode == NotifyNormal || - ( !options->focusPolicyIsReasonable() && - e->mode == NotifyUngrab ) ) - { - - if (options->shadeHover && isShade()) - { - delete shadeHoverTimer; - shadeHoverTimer = new TQTimer( this ); - connect( shadeHoverTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( shadeHover() )); - shadeHoverTimer->start( options->shadeHoverInterval, TRUE ); - } - - if ( options->focusPolicy == Options::ClickToFocus ) - return; - - if ( options->autoRaise && !isDesktop() && - !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() && - workspace()->topClientOnDesktop( workspace()->currentDesktop()) != this ) - { - delete autoRaiseTimer; - autoRaiseTimer = new TQTimer( this ); - connect( autoRaiseTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( autoRaise() ) ); - autoRaiseTimer->start( options->autoRaiseInterval, TRUE ); - } - - TQPoint currentPos( e->x_root, e->y_root ); - if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isTopMenu() ) ) - return; - // for FocusFollowsMouse, change focus only if the mouse has actually been moved, not if the focus - // change came because of window changes (e.g. closing a window) - #92290 - if( options->focusPolicy != Options::FocusFollowsMouse - || currentPos != workspace()->focusMousePosition()) - { - if ( options->delayFocus ) - workspace()->requestDelayFocus( this ); - else - workspace()->requestFocus( this ); - } - return; - } - } - -void Client::leaveNotifyEvent( XCrossingEvent* e ) - { - if( e->window != frameId()) - return; // care only about leaving the whole frame - if ( e->mode == NotifyNormal ) - { - if ( !buttonDown ) - { - mode = PositionCenter; - setCursor( tqarrowCursor ); - } - bool lostMouse = !rect().contains( TQPoint( e->x, e->y ) ); - // 'lostMouse' wouldn't work with e.g. B2 or Keramik, which have non-rectangular decorations - // (i.e. the LeaveNotify event comes before leaving the rect and no LeaveNotify event - // comes after leaving the rect) - so lets check if the pointer is really outside the window - - // TODO this still sucks if a window appears above this one - it should lose the mouse - // if this window is another client, but not if it's a popup ... maybe after KDE3.1 :( - // (repeat after me 'AARGHL!') - if ( !lostMouse && e->detail != NotifyInferior ) - { - int d1, d2, d3, d4; - unsigned int d5; - Window w, child; - if( XQueryPointer( qt_xdisplay(), frameId(), &w, &child, &d1, &d2, &d3, &d4, &d5 ) == False - || child == None ) - lostMouse = true; // really lost the mouse - } - if ( lostMouse ) - { - cancelAutoRaise(); - workspace()->cancelDelayFocus(); - cancelShadeHover(); - if ( shade_mode == ShadeHover && !moveResizeMode && !buttonDown ) - setShade( ShadeNormal ); - } - if ( options->focusPolicy == Options::FocusStrictlyUnderMouse ) - if ( isActive() && lostMouse ) - workspace()->requestFocus( 0 ) ; - return; - } - } - -#define XCapL KKeyNative::modXLock() -#define XNumL KKeyNative::modXNumLock() -#define XScrL KKeyNative::modXScrollLock() -void Client::grabButton( int modifier ) - { - unsigned int mods[ 8 ] = - { - 0, XCapL, XNumL, XNumL | XCapL, - XScrL, XScrL | XCapL, - XScrL | XNumL, XScrL | XNumL | XCapL - }; - for( int i = 0; - i < 8; - ++i ) - XGrabButton( qt_xdisplay(), AnyButton, - modifier | mods[ i ], - wrapperId(), FALSE, ButtonPressMask, - GrabModeSync, GrabModeAsync, None, None ); - } - -void Client::ungrabButton( int modifier ) - { - unsigned int mods[ 8 ] = - { - 0, XCapL, XNumL, XNumL | XCapL, - XScrL, XScrL | XCapL, - XScrL | XNumL, XScrL | XNumL | XCapL - }; - for( int i = 0; - i < 8; - ++i ) - XUngrabButton( qt_xdisplay(), AnyButton, - modifier | mods[ i ], wrapperId()); - } -#undef XCapL -#undef XNumL -#undef XScrL - -/* - Releases the passive grab for some modifier combinations when a - window becomes active. This helps broken X programs that - missinterpret LeaveNotify events in grab mode to work properly - (Motif, AWT, Tk, ...) - */ -void Client::updateMouseGrab() - { - if( workspace()->globalShortcutsDisabled()) - { - XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, wrapperId()); - // keep grab for the simple click without modifiers if needed (see below) - bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this; - if( !( !options->clickRaise || not_obscured )) - grabButton( None ); - return; - } - if( isActive() && !workspace()->forcedGlobalMouseGrab()) // see Workspace::establishTabBoxGrab() - { - // first grab all modifier combinations - XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE, - ButtonPressMask, - GrabModeSync, GrabModeAsync, - None, None ); - // remove the grab for no modifiers only if the window - // is unobscured or if the user doesn't want click raise - // (it is unobscured if it the topmost in the unconstrained stacking order, i.e. it is - // the most recently raised window) - bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this; - if( !options->clickRaise || not_obscured ) - ungrabButton( None ); - else - grabButton( None ); - ungrabButton( ShiftMask ); - ungrabButton( ControlMask ); - ungrabButton( ControlMask | ShiftMask ); - } - else - { - XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, wrapperId()); - // simply grab all modifier combinations - XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE, - ButtonPressMask, - GrabModeSync, GrabModeAsync, - None, None ); - } - } - -int qtToX11Button( TQt::ButtonState button ) - { - if( button == Qt::LeftButton ) - return Button1; - else if( button == Qt::MidButton ) - return Button2; - else if( button == Qt::RightButton ) - return Button3; - return AnyButton; - } - -int qtToX11State( TQt::ButtonState state ) - { - int ret = 0; - if( state & Qt::LeftButton ) - ret |= Button1Mask; - if( state & Qt::MidButton ) - ret |= Button2Mask; - if( state & Qt::RightButton ) - ret |= Button3Mask; - if( state & TQt::ShiftButton ) - ret |= ShiftMask; - if( state & TQt::ControlButton ) - ret |= ControlMask; - if( state & TQt::AltButton ) - ret |= KKeyNative::modX(KKey::ALT); - if( state & TQt::MetaButton ) - ret |= KKeyNative::modX(KKey::WIN); - return ret; - } - -// Qt propagates mouse events up the widget hierachy, which means events -// for the decoration window cannot be (easily) intercepted as X11 events -bool Client::eventFilter( TQObject* o, TQEvent* e ) - { - if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(shadowWidget)) - { - if (e->type() == TQEvent::MouseButtonRelease) - { - int buttonMask, buttonPressed, x, y, x_root, y_root; - unsigned int mask; - TQMouseEvent *qe = (TQMouseEvent *)e; - Window inner_window, parent_window, pointer_window, root_window; - XButtonEvent xe; - - removeShadow(); - switch (qe->button()) - { - case Qt::MidButton: - buttonMask = Button2Mask; - buttonPressed = Button2; - break; - case Qt::RightButton: - buttonMask = Button3Mask; - buttonPressed = Button3; - break; - default: - buttonMask = Button1Mask; - buttonPressed = Button1; - break; - } - - // find the window under the cursor that should receive the - // simulated events - root_window = qt_xrootwin(); - XQueryPointer(qt_xdisplay(), root_window, &root_window, - &pointer_window, &x_root, &y_root, &x, &y, &mask); - - if (pointer_window != None) - { - // Save the child window immediately under the window - // decoration, if any. This is so that we can send an event to - // the immediate descendant of a window's window decoration, - // which causes KWin to refocus windows properly - parent_window = pointer_window; - XQueryPointer(qt_xdisplay(), parent_window, &root_window, - &pointer_window, &x_root, &y_root, &x, &y, &mask); - inner_window = pointer_window; - - while (pointer_window != None) - { - // Recursively query for the child window under the pointer, - // using the returned child window as the parent window for - // the subsequent query. When no child window is left, we've - // found the child that will receive the simulated event - parent_window = pointer_window; - XQueryPointer(qt_xdisplay(), parent_window, &root_window, - &pointer_window, &x_root, &y_root, &x, &y, &mask); - } - pointer_window = parent_window; - } - else - inner_window = None; - - // simulate a mouse button press - xe.type = ButtonPress; - xe.display = qt_xdisplay(); - xe.root = qt_xrootwin(); - xe.subwindow = None; - xe.time = CurrentTime; - xe.x = x; - xe.y = y; - xe.x_root = x_root; - xe.y_root = y_root; - xe.state = 0; - xe.button = buttonPressed; - xe.same_screen = True; - if (inner_window != None && inner_window != pointer_window) - { - xe.window = inner_window; - XSendEvent(qt_xdisplay(), inner_window, True, ButtonPressMask, - (XEvent *)&xe); - } - xe.window = pointer_window; - XSendEvent(qt_xdisplay(), pointer_window, True, ButtonPressMask, - (XEvent *)&xe); - - // simulate a mouse button release - xe.type = ButtonRelease; - xe.display = qt_xdisplay(); - xe.root = qt_xrootwin(); - xe.subwindow = None; - xe.time = CurrentTime; - xe.x = x; - xe.y = y; - xe.x_root = x_root; - xe.y_root = y_root; - xe.state = buttonMask; - xe.button = buttonPressed; - xe.same_screen = True; - if (inner_window != None && inner_window != pointer_window) - { - xe.window = inner_window; - XSendEvent(qt_xdisplay(), inner_window, True, ButtonReleaseMask, - (XEvent *)&xe); - } - xe.window = pointer_window; - XSendEvent(qt_xdisplay(), pointer_window, True, ButtonReleaseMask, - (XEvent *)&xe); - - drawDelayedShadow(); - - return true; - } - else if (e->type() == TQEvent::Wheel) - { - int x, y, x_root, y_root; - unsigned int buttonMask, buttonPressed, mask; - TQWheelEvent *wheelEvent = (TQWheelEvent *)e; - Window inner_window, parent_window, pointer_window, - root_window; - XButtonEvent xe; - - removeShadow(); - - // state and button parameters passed to XSendEvent depend on the - // direction in which the mouse wheel was rolled - buttonMask = wheelEvent->delta() > 0 ? Button4Mask : Button5Mask; - buttonPressed = wheelEvent->delta() > 0 ? Button4 : Button5; - - // find the window under the cursor that should receive the - // simulated events - root_window = qt_xrootwin(); - XQueryPointer(qt_xdisplay(), root_window, &root_window, - &pointer_window, &x_root, &y_root, &x, &y, &mask); - - if (pointer_window != None) - { - // Save the child window immediately under the window - // decoration, if any. This is so that we can send an event to - // the immediate descendant of a window's window decoration, - // which causes KWin to refocus windows properly - parent_window = pointer_window; - XQueryPointer(qt_xdisplay(), parent_window, &root_window, - &pointer_window, &x_root, &y_root, &x, &y, &mask); - inner_window = pointer_window; - - while (pointer_window != None) - { - // Recursively query for the child window under the pointer, - // using the returned child window as the parent window for - // the subsequent query. When no child window is left, we've - // found the child that will receive the simulated event - parent_window = pointer_window; - XQueryPointer(qt_xdisplay(), parent_window, &root_window, - &pointer_window, &x_root, &y_root, &x, &y, &mask); - } - pointer_window = parent_window; - } - else - inner_window = None; - - // simulate a mouse button press - xe.type = ButtonPress; - xe.display = qt_xdisplay(); - xe.root = qt_xrootwin(); - xe.subwindow = None; - xe.time = CurrentTime; - xe.x = x; - xe.y = y; - xe.x_root = x_root; - xe.y_root = y_root; - xe.state = 0; - xe.same_screen = True; - if (inner_window != None && inner_window != pointer_window) - { - xe.button = buttonPressed; - xe.window = inner_window; - XSendEvent(qt_xdisplay(), inner_window, True, ButtonPressMask, - (XEvent *)&xe); - } - xe.button = buttonPressed; - xe.window = pointer_window; - XSendEvent(qt_xdisplay(), pointer_window, True, ButtonPressMask, - (XEvent *)&xe); - - // simulate a mouse button release - xe.type = ButtonRelease; - xe.display = qt_xdisplay(); - xe.root = qt_xrootwin(); - xe.subwindow = None; - xe.time = CurrentTime; - xe.x = x; - xe.y = y; - xe.x_root = x_root; - xe.y_root = y_root; - xe.same_screen = True; - if (inner_window != None && inner_window != pointer_window) - { - xe.window = inner_window; - xe.state = buttonMask; - xe.button = buttonPressed; - XSendEvent(qt_xdisplay(), inner_window, True, ButtonReleaseMask, - (XEvent *)&xe); - } - xe.state = buttonMask; - xe.button = buttonPressed; - xe.window = pointer_window; - XSendEvent(qt_xdisplay(), pointer_window, True, ButtonReleaseMask, - (XEvent *)&xe); - - drawDelayedShadow(); - - return true; - } - } - if( decoration == NULL - || TQT_BASE_OBJECT(o) != TQT_BASE_OBJECT(decoration->widget())) - return false; - if( e->type() == TQEvent::MouseButtonPress ) - { - TQMouseEvent* ev = TQT_TQMOUSEEVENT( e ); - return buttonPressEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()), - ev->x(), ev->y(), ev->globalX(), ev->globalY() ); - } - if( e->type() == TQEvent::MouseButtonRelease ) - { - TQMouseEvent* ev = TQT_TQMOUSEEVENT( e ); - return buttonReleaseEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()), - ev->x(), ev->y(), ev->globalX(), ev->globalY() ); - } - if( e->type() == TQEvent::MouseMove ) // FRAME i fake z enter/leave? - { - TQMouseEvent* ev = TQT_TQMOUSEEVENT( e ); - return motionNotifyEvent( decorationId(), qtToX11State( ev->state()), - ev->x(), ev->y(), ev->globalX(), ev->globalY() ); - } - if( e->type() == TQEvent::Wheel ) - { - TQWheelEvent* ev = TQT_TQWHEELEVENT( e ); - bool r = buttonPressEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->state()), - ev->x(), ev->y(), ev->globalX(), ev->globalY() ); - r = r || buttonReleaseEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->state()), - ev->x(), ev->y(), ev->globalX(), ev->globalY() ); - return r; - } - if( e->type() == TQEvent::Resize ) - { - TQResizeEvent* ev = TQT_TQRESIZEEVENT( e ); - // Filter out resize events that inform about size different than frame size. - // This will ensure that decoration->width() etc. and decoration->widget()->width() will be in sync. - // These events only seem to be delayed events from initial resizing before show() was called - // on the decoration widget. - if( ev->size() != size()) - return true; - } - return false; - } - -// return value matters only when filtering events before decoration gets them -bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root ) - { - if (buttonDown) - { - if( w == wrapperId()) - XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time); - return true; - } - - if( w == wrapperId() || w == frameId() || w == decorationId()) - { // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace - // FRAME something out of this would be processed before it gets decorations - updateUserTime(); - workspace()->setWasUserInteraction(); - uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ? - KKeyNative::modX(KKey::WIN) : - KKeyNative::modX(KKey::ALT); - bool bModKeyHeld = keyModX != 0 && ( state & KKeyNative::accelModMaskX()) == keyModX; - - if( isSplash() - && button == Button1 && !bModKeyHeld ) - { // hide splashwindow if the user clicks on it - hideClient( true ); - if( w == wrapperId()) - XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time); - return true; - } - - Options::MouseCommand com = Options::MouseNothing; - bool was_action = false; - bool perform_handled = false; - if ( bModKeyHeld ) - { - was_action = true; - switch (button) - { - case Button1: - com = options->commandAll1(); - break; - case Button2: - com = options->commandAll2(); - break; - case Button3: - com = options->commandAll3(); - break; - case Button4: - case Button5: - com = options->operationWindowMouseWheel( button == Button4 ? 120 : -120 ); - break; - } - } - else - { // inactive inner window - if( !isActive() && w == wrapperId()) - { - was_action = true; - perform_handled = true; - switch (button) - { - case Button1: - com = options->commandWindow1(); - break; - case Button2: - com = options->commandWindow2(); - break; - case Button3: - com = options->commandWindow3(); - break; - default: - com = Options::MouseActivateAndPassClick; - } - } - // active inner window - if( isActive() && w == wrapperId() - && options->clickRaise && button < 4 ) // exclude wheel - { - com = Options::MouseActivateRaiseAndPassClick; - was_action = true; - perform_handled = true; - } - } - if( was_action ) - { - bool replay = performMouseCommand( com, TQPoint( x_root, y_root), perform_handled ); - - if ( isSpecialWindow()) - replay = TRUE; - - if( w == wrapperId()) // these can come only from a grab - XAllowEvents(qt_xdisplay(), replay? ReplayPointer : SyncPointer, CurrentTime ); //qt_x_time); - return true; - } - } - - if( w == wrapperId()) // these can come only from a grab - { - XAllowEvents(qt_xdisplay(), ReplayPointer, CurrentTime ); //qt_x_time); - return true; - } - if( w == decorationId()) - return false; // don't eat decoration events - if( w == frameId()) - processDecorationButtonPress( button, state, x, y, x_root, y_root ); - return true; - } - - -// this function processes button press events only after decoration decides not to handle them, -// unlike buttonPressEvent(), which (when the window is decoration) filters events before decoration gets them -void Client::processDecorationButtonPress( int button, int /*state*/, int x, int y, int x_root, int y_root ) - { - Options::MouseCommand com = Options::MouseNothing; - bool active = isActive(); - if ( !wantsInput() ) // we cannot be active, use it anyway - active = TRUE; - - if ( button == Button1 ) - com = active ? options->commandActiveTitlebar1() : options->commandInactiveTitlebar1(); - else if ( button == Button2 ) - com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2(); - else if ( button == Button3 ) - com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3(); - if( button == Button1 - && com != Options::MouseOperationsMenu // actions where it's not possible to get the matching - && com != Options::MouseMinimize ) // mouse release event - { - mode = mousePosition( TQPoint( x, y )); - buttonDown = TRUE; - moveOffset = TQPoint( x, y ); - invertedMoveOffset = rect().bottomRight() - moveOffset; - unrestrictedMoveResize = false; - setCursor( mode ); // update to sizeAllCursor if about to move - } - performMouseCommand( com, TQPoint( x_root, y_root )); - } - -// called from decoration -void Client::processMousePressEvent( TQMouseEvent* e ) - { - if( e->type() != TQEvent::MouseButtonPress ) - { - kdWarning() << "processMousePressEvent()" << endl; - return; - } - int button; - switch( e->button()) - { - case Qt::LeftButton: - button = Button1; - break; - case Qt::MidButton: - button = Button2; - break; - case Qt::RightButton: - button = Button3; - break; - default: - return; - } - processDecorationButtonPress( button, e->state(), e->x(), e->y(), e->globalX(), e->globalY()); - } - -// return value matters only when filtering events before decoration gets them -bool Client::buttonReleaseEvent( Window w, int /*button*/, int state, int x, int y, int x_root, int y_root ) - { - if( w == decorationId() && !buttonDown) - return false; - if( w == wrapperId()) - { - XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time); - return true; - } - if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow()) - return true; - x = this->x(); // translate from grab window to local coords - y = this->y(); - if ( (state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 ) - { - buttonDown = FALSE; - if ( moveResizeMode ) - { - finishMoveResize( false ); - // mouse position is still relative to old Client position, adjust it - TQPoint mousepos( x_root - x, y_root - y ); - mode = mousePosition( mousepos ); - } - setCursor( mode ); - } - return true; - } - -static bool was_motion = false; -static Time next_motion_time = CurrentTime; -// Check whole incoming X queue for MotionNotify events -// checking whole queue is done by always returning False in the predicate. -// If there are more MotionNotify events in the queue, all until the last -// one may be safely discarded (if a ButtonRelease event comes, a MotionNotify -// will be faked from it, so there's no need to check other events). -// This helps avoiding being overloaded by being flooded from many events -// from the XServer. -static Bool motion_predicate( Display*, XEvent* ev, XPointer ) -{ - if( ev->type == MotionNotify ) - { - was_motion = true; - next_motion_time = ev->xmotion.time; // for setting time - } - return False; -} - -static bool waitingMotionEvent() - { -// The queue doesn't need to be checked until the X timestamp -// of processes events reaches the timestamp of the last suitable -// MotionNotify event in the queue. - if( next_motion_time != CurrentTime - && timestampCompare( GET_QT_X_TIME(), next_motion_time ) < 0 ) - return true; - was_motion = false; - XSync( qt_xdisplay(), False ); // this helps to discard more MotionNotify events - XEvent dummy; - XCheckIfEvent( qt_xdisplay(), &dummy, motion_predicate, NULL ); - return was_motion; - } - -// return value matters only when filtering events before decoration gets them -bool Client::motionNotifyEvent( Window w, int /*state*/, int x, int y, int x_root, int y_root ) - { - if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow()) - return true; // care only about the whole frame - if ( !buttonDown ) - { - Position newmode = mousePosition( TQPoint( x, y )); - if( newmode != mode ) - setCursor( newmode ); - mode = newmode; - // reset the timestamp for the optimization, otherwise with long passivity - // the option in waitingMotionEvent() may be always true - next_motion_time = CurrentTime; - return false; - } - if( w == moveResizeGrabWindow()) - { - x = this->x(); // translate from grab window to local coords - y = this->y(); - } - if( !waitingMotionEvent()) - handleMoveResize( x, y, x_root, y_root ); - return true; - } - -void Client::focusInEvent( XFocusInEvent* e ) - { - if( e->window != window()) - return; // only window gets focus - if ( e->mode == NotifyUngrab ) - return; // we don't care - if ( e->detail == NotifyPointer ) - return; // we don't care - if( !isShown( false ) || !isOnCurrentDesktop()) // we unmapped it, but it got focus meanwhile -> - return; // activateNextClient() already transferred focus elsewhere - // check if this client is in should_get_focus list or if activation is allowed - bool activate = workspace()->allowClientActivation( this, -1U, true ); - workspace()->gotFocusIn( this ); // remove from should_get_focus list - if( activate ) - setActive( TRUE ); - else - { - workspace()->restoreFocus(); - demandAttention(); - } - } - -// When a client loses focus, FocusOut events are usually immediatelly -// followed by FocusIn events for another client that gains the focus -// (unless the focus goes to another screen, or to the nofocus widget). -// Without this check, the former focused client would have to be -// deactivated, and after that, the new one would be activated, with -// a short time when there would be no active client. This can cause -// flicker sometimes, e.g. when a fullscreen is shown, and focus is transferred -// from it to its transient, the fullscreen would be kept in the Active layer -// at the beginning and at the end, but not in the middle, when the active -// client would be temporarily none (see Client::belongToLayer() ). -// Therefore, the events queue is checked, whether it contains the matching -// FocusIn event, and if yes, deactivation of the previous client will -// be skipped, as activation of the new one will automatically deactivate -// previously active client. -static bool follows_focusin = false; -static bool follows_focusin_failed = false; -static Bool predicate_follows_focusin( Display*, XEvent* e, XPointer arg ) - { - if( follows_focusin || follows_focusin_failed ) - return False; - Client* c = ( Client* ) arg; - if( e->type == FocusIn && c->workspace()->findClient( WindowMatchPredicate( e->xfocus.window ))) - { // found FocusIn - follows_focusin = true; - return False; - } - // events that may be in the queue before the FocusIn event that's being - // searched for - if( e->type == FocusIn || e->type == FocusOut || e->type == KeymapNotify ) - return False; - follows_focusin_failed = true; // a different event - stop search - return False; - } - -static bool check_follows_focusin( Client* c ) - { - follows_focusin = follows_focusin_failed = false; - XEvent dummy; - // XCheckIfEvent() is used to make the search non-blocking, the predicate - // always returns False, so nothing is removed from the events queue. - // XPeekIfEvent() would block. - XCheckIfEvent( qt_xdisplay(), &dummy, predicate_follows_focusin, (XPointer)c ); - return follows_focusin; - } - - -void Client::focusOutEvent( XFocusOutEvent* e ) - { - if( e->window != window()) - return; // only window gets focus - if ( e->mode == NotifyGrab ) - return; // we don't care - if ( isShade() ) - return; // here neither - if ( e->detail != NotifyNonlinear - && e->detail != NotifyNonlinearVirtual ) - // SELI check all this - return; // hack for motif apps like netscape - if ( TQApplication::activePopupWidget() ) - return; - if( !check_follows_focusin( this )) - setActive( FALSE ); - } - -// performs _NET_WM_MOVERESIZE -void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction ) - { - if( direction == NET::Move ) - performMouseCommand( Options::MouseMove, TQPoint( x_root, y_root )); - else if( moveResizeMode && direction == NET::MoveResizeCancel ) - { - finishMoveResize( true ); - buttonDown = FALSE; - setCursor( mode ); - } - else if( direction >= NET::TopLeft && direction <= NET::Left ) - { - static const Position convert[] = - { - PositionTopLeft, - PositionTop, - PositionTopRight, - PositionRight, - PositionBottomRight, - PositionBottom, - PositionBottomLeft, - PositionLeft - }; - if(!isResizable() || isShade()) - return; - if( moveResizeMode ) - finishMoveResize( false ); - buttonDown = TRUE; - moveOffset = TQPoint( x_root - x(), y_root - y()); // map from global - invertedMoveOffset = rect().bottomRight() - moveOffset; - unrestrictedMoveResize = false; - mode = convert[ direction ]; - setCursor( mode ); - if( !startMoveResize()) - { - buttonDown = false; - setCursor( mode ); - } - } - else if( direction == NET::KeyboardMove ) - { // ignore mouse coordinates given in the message, mouse position is used by the moving algorithm - TQCursor::setPos( geometry().center() ); - performMouseCommand( Options::MouseUnrestrictedMove, geometry().center()); - } - else if( direction == NET::KeyboardSize ) - { // ignore mouse coordinates given in the message, mouse position is used by the resizing algorithm - TQCursor::setPos( geometry().bottomRight()); - performMouseCommand( Options::MouseUnrestrictedResize, geometry().bottomRight()); - } - } - -void Client::keyPressEvent( uint key_code ) - { - updateUserTime(); - if ( !isMove() && !isResize() ) - return; - bool is_control = key_code & Qt::CTRL; - bool is_alt = key_code & Qt::ALT; - key_code = key_code & 0xffff; - int delta = is_control?1:is_alt?32:8; - TQPoint pos = TQCursor::pos(); - switch ( key_code ) - { - case Key_Left: - pos.rx() -= delta; - break; - case Key_Right: - pos.rx() += delta; - break; - case Key_Up: - pos.ry() -= delta; - break; - case Key_Down: - pos.ry() += delta; - break; - case Key_Space: - case Key_Return: - case Key_Enter: - finishMoveResize( false ); - buttonDown = FALSE; - setCursor( mode ); - break; - case Key_Escape: - finishMoveResize( true ); - buttonDown = FALSE; - setCursor( mode ); - break; - default: - return; - } - TQCursor::setPos( pos ); - } - -// **************************************** -// Group -// **************************************** - -bool Group::groupEvent( XEvent* e ) - { - unsigned long dirty[ 2 ]; - leader_info->event( e, dirty, 2 ); // pass through the NET stuff - if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 ) - getIcons(); - if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 ) - startupIdChanged(); - return false; - } - - -} // namespace |