summaryrefslogtreecommitdiffstats
path: root/kwin/events.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kwin/events.cpp')
-rw-r--r--kwin/events.cpp1784
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