kwin Library API Documentation

events.cpp

00001 /*****************************************************************
00002  KWin - the KDE window manager
00003  This file is part of the KDE project.
00004 
00005 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
00006 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
00007 
00008 You can Freely distribute this program under the GNU General Public
00009 License. See the file "COPYING" for the exact licensing terms.
00010 ******************************************************************/
00011 
00012 /*
00013 
00014  This file contains things relevant to handling incoming events.
00015 
00016 */
00017 
00018 #include "client.h"
00019 #include "workspace.h"
00020 #include "atoms.h"
00021 #include "tabbox.h"
00022 #include "group.h"
00023 #include "rules.h"
00024 
00025 #include <qwhatsthis.h>
00026 #include <kkeynative.h>
00027 #include <qapplication.h>
00028 
00029 #include <X11/extensions/shape.h>
00030 #include <X11/Xatom.h>
00031 
00032 extern Time qt_x_time;
00033 extern Atom qt_window_role;
00034 
00035 namespace KWinInternal
00036 {
00037 
00038 // ****************************************
00039 // WinInfo
00040 // ****************************************
00041 
00042 WinInfo::WinInfo( Client * c, Display * display, Window window,
00043     Window rwin, const unsigned long pr[], int pr_size )
00044     : NETWinInfo( display, window, rwin, pr, pr_size, NET::WindowManager ), m_client( c )
00045     {
00046     }
00047 
00048 void WinInfo::changeDesktop(int desktop)
00049     {
00050     m_client->workspace()->sendClientToDesktop( m_client, desktop, true );
00051     }
00052 
00053 void WinInfo::changeState( unsigned long state, unsigned long mask )
00054     {
00055     mask &= ~NET::Sticky; // KWin doesn't support large desktops, ignore
00056     mask &= ~NET::Hidden; // clients are not allowed to change this directly
00057     state &= mask; // for safety, clear all other bits
00058 
00059     if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) == 0 )
00060         m_client->setFullScreen( false, false );
00061     if ( (mask & NET::Max) == NET::Max )
00062         m_client->setMaximize( state & NET::MaxVert, state & NET::MaxHoriz );
00063     else if ( mask & NET::MaxVert )
00064         m_client->setMaximize( state & NET::MaxVert, m_client->maximizeMode() & Client::MaximizeHorizontal );
00065     else if ( mask & NET::MaxHoriz )
00066         m_client->setMaximize( m_client->maximizeMode() & Client::MaximizeVertical, state & NET::MaxHoriz );
00067 
00068     if ( mask & NET::Shaded )
00069         m_client->setShade( state & NET::Shaded ? ShadeNormal : ShadeNone );
00070     if ( mask & NET::KeepAbove)
00071         m_client->setKeepAbove( (state & NET::KeepAbove) != 0 );
00072     if ( mask & NET::KeepBelow)
00073         m_client->setKeepBelow( (state & NET::KeepBelow) != 0 );
00074     if( mask & NET::SkipTaskbar )
00075         m_client->setSkipTaskbar( ( state & NET::SkipTaskbar ) != 0, true );
00076     if( mask & NET::SkipPager )
00077         m_client->setSkipPager( ( state & NET::SkipPager ) != 0 );
00078     if( mask & NET::DemandsAttention )
00079         m_client->demandAttention(( state & NET::DemandsAttention ) != 0 );
00080     if( mask & NET::Modal )
00081         m_client->setModal( ( state & NET::Modal ) != 0 );
00082     // unsetting fullscreen first, setting it last (because e.g. maximize works only for !isFullScreen() )
00083     if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) != 0 )
00084         m_client->setFullScreen( true, false );
00085     }
00086 
00087 
00088 // ****************************************
00089 // RootInfo
00090 // ****************************************
00091 
00092 RootInfo::RootInfo( Workspace* ws, Display *dpy, Window w, const char *name, unsigned long pr[], int pr_num, int scr )
00093     : NETRootInfo3( dpy, w, name, pr, pr_num, scr )
00094     {
00095     workspace = ws;
00096     }
00097 
00098 void RootInfo::changeNumberOfDesktops(int n)
00099     {
00100     workspace->setNumberOfDesktops( n );
00101     }
00102 
00103 void RootInfo::changeCurrentDesktop(int d)
00104     {
00105     workspace->setCurrentDesktop( d );
00106     }
00107 
00108 void RootInfo::changeActiveWindow( Window w, NET::RequestSource src, Time timestamp, Window active_window )
00109     {
00110     if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
00111         {
00112         if( timestamp == CurrentTime )
00113             timestamp = c->userTime();
00114         if( src != NET::FromApplication && src != FromTool )
00115             src = NET::FromTool;
00116         if( src == NET::FromTool )
00117             workspace->activateClient( c, true ); // force
00118         else // NET::FromApplication
00119             {
00120             Client* c2;
00121             if( workspace->allowClientActivation( c, timestamp ))
00122                 workspace->activateClient( c );
00123             // if activation of the requestor's window would be allowed, allow activation too
00124             else if( active_window != None
00125                 && ( c2 = workspace->findClient( WindowMatchPredicate( active_window ))) != NULL
00126                 && workspace->allowClientActivation( c2,
00127                     timestampCompare( timestamp, c2->userTime() > 0 ? timestamp : c2->userTime())))
00128                 workspace->activateClient( c );
00129             else
00130                 c->demandAttention();
00131             }
00132         }
00133     }
00134 
00135 void RootInfo::restackWindow( Window w, RequestSource src, Window above, int detail, Time timestamp )
00136     {
00137     if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
00138         {
00139         if( timestamp == CurrentTime )
00140             timestamp = c->userTime();
00141         if( src != NET::FromApplication && src != FromTool )
00142             src = NET::FromTool;
00143         c->restackWindow( above, detail, src, timestamp, true );
00144         }
00145     }
00146 
00147 void RootInfo::gotTakeActivity( Window w, Time timestamp, long flags )
00148     {
00149     if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
00150         workspace->handleTakeActivity( c, timestamp, flags );
00151     }
00152 
00153 void RootInfo::closeWindow(Window w)
00154     {
00155     Client* c = workspace->findClient( WindowMatchPredicate( w ));
00156     if ( c )
00157         c->closeWindow();
00158     }
00159 
00160 void RootInfo::moveResize(Window w, int x_root, int y_root, unsigned long direction)
00161     {
00162     Client* c = workspace->findClient( WindowMatchPredicate( w ));
00163     if ( c )
00164         {
00165         updateXTime(); // otherwise grabbing may have old timestamp - this message should include timestamp
00166         c->NETMoveResize( x_root, y_root, (Direction)direction);
00167         }
00168     }
00169 
00170 void RootInfo::moveResizeWindow(Window w, int flags, int x, int y, int width, int height )
00171     {
00172     Client* c = workspace->findClient( WindowMatchPredicate( w ));
00173     if ( c )
00174         c->NETMoveResizeWindow( flags, x, y, width, height );
00175     }
00176 
00177 void RootInfo::gotPing( Window w, Time timestamp )
00178     {
00179     if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
00180         c->gotPing( timestamp );
00181     }
00182 
00183 // ****************************************
00184 // Workspace
00185 // ****************************************
00186 
00190 bool Workspace::workspaceEvent( XEvent * e )
00191     {
00192     if ( mouse_emulation && (e->type == ButtonPress || e->type == ButtonRelease ) ) 
00193         {
00194         mouse_emulation = FALSE;
00195         XUngrabKeyboard( qt_xdisplay(), qt_x_time );
00196         }
00197 
00198     if ( e->type == PropertyNotify || e->type == ClientMessage ) 
00199         {
00200         if ( netCheck( e ) )
00201             return TRUE;
00202         }
00203 
00204     // events that should be handled before Clients can get them
00205     switch (e->type) 
00206         {
00207         case ButtonPress:
00208         case ButtonRelease:
00209             was_user_interaction = true;
00210         // fallthrough
00211         case MotionNotify:
00212             if ( tab_grab || control_grab )
00213                 {
00214                 tab_box->handleMouseEvent( e );
00215                 return TRUE;
00216                 }
00217             break;
00218         case KeyPress:
00219             {
00220             was_user_interaction = true;
00221             KKeyNative keyX( (XEvent*)e );
00222             uint keyQt = keyX.keyCodeQt();
00223             kdDebug(125) << "Workspace::keyPress( " << keyX.key().toString() << " )" << endl;
00224             if (movingClient)
00225                 {
00226                 movingClient->keyPressEvent(keyQt);
00227                 return true;
00228                 }
00229             if( tab_grab || control_grab )
00230                 {
00231                 tabBoxKeyPress( keyX );
00232                 return true;
00233                 }
00234             break;
00235             }
00236         case KeyRelease:
00237             was_user_interaction = true;
00238             if( tab_grab || control_grab )
00239                 {
00240                 tabBoxKeyRelease( e->xkey );
00241                 return true;
00242                 }
00243             break;
00244         };
00245 
00246     if( Client* c = findClient( WindowMatchPredicate( e->xany.window )))
00247         {
00248         if( c->windowEvent( e ))
00249             return true;
00250         }
00251     else if( Client* c = findClient( WrapperIdMatchPredicate( e->xany.window )))
00252         {
00253         if( c->windowEvent( e ))
00254             return true;
00255         }
00256     else if( Client* c = findClient( FrameIdMatchPredicate( e->xany.window )))
00257         {
00258         if( c->windowEvent( e ))
00259             return true;
00260         }
00261     else
00262         {
00263         Window special = findSpecialEventWindow( e );
00264         if( special != None )
00265             if( Client* c = findClient( WindowMatchPredicate( special )))
00266                 {
00267                 if( c->windowEvent( e ))
00268                     return true;
00269                 }
00270         }
00271     if( movingClient != NULL && movingClient->moveResizeGrabWindow() == e->xany.window
00272         && ( e->type == MotionNotify || e->type == ButtonPress || e->type == ButtonRelease ))
00273         {
00274         if( movingClient->windowEvent( e ))
00275             return true;
00276         }
00277 
00278     switch (e->type) 
00279         {
00280         case CreateNotify:
00281             if ( e->xcreatewindow.parent == root &&
00282                  !QWidget::find( e->xcreatewindow.window) &&
00283                  !e->xcreatewindow.override_redirect )
00284             {
00285         // see comments for allowClientActivation()
00286             XChangeProperty(qt_xdisplay(), e->xcreatewindow.window,
00287                             atoms->kde_net_wm_user_creation_time, XA_CARDINAL,
00288                             32, PropModeReplace, (unsigned char *)&qt_x_time, 1);
00289             }
00290         break;
00291 
00292     case UnmapNotify:
00293             {
00294         // check for system tray windows
00295             if ( removeSystemTrayWin( e->xunmap.window, true ) ) 
00296                 {
00297         // If the system tray gets destroyed, the system tray
00298         // icons automatically get unmapped, reparented and mapped
00299         // again to the closest non-client ancestor due to
00300         // QXEmbed's SaveSet feature. Unfortunatly with kicker
00301         // this closest ancestor is not the root window, but our
00302         // decoration, so we reparent explicitely back to the root
00303         // window.
00304                 XEvent ev;
00305                 WId w = e->xunmap.window;
00306                 if ( XCheckTypedWindowEvent (qt_xdisplay(), w,
00307                                              ReparentNotify, &ev) )
00308                     {
00309                     if ( ev.xreparent.parent != root ) 
00310                         {
00311                         XReparentWindow( qt_xdisplay(), w, root, 0, 0 );
00312                         addSystemTrayWin( w );
00313                         }
00314                     }
00315                 return TRUE;
00316                 }
00317 
00318             return ( e->xunmap.event != e->xunmap.window ); // hide wm typical event from Qt
00319             }
00320         case MapNotify:
00321 
00322             return ( e->xmap.event != e->xmap.window ); // hide wm typical event from Qt
00323 
00324         case ReparentNotify:
00325             {
00326         //do not confuse Qt with these events. After all, _we_ are the
00327         //window manager who does the reparenting.
00328             return TRUE;
00329             }
00330         case DestroyNotify:
00331             {
00332             if ( removeSystemTrayWin( e->xdestroywindow.window, false ) )
00333                 return TRUE;
00334             return false;
00335             }
00336         case MapRequest:
00337             {
00338             updateXTime();
00339 
00340             // e->xmaprequest.window is different from e->xany.window
00341             // TODO this shouldn't be necessary now
00342             Client* c = findClient( WindowMatchPredicate( e->xmaprequest.window ));
00343             if ( !c ) 
00344                 {
00345 // don't check for the parent being the root window, this breaks when some app unmaps
00346 // a window, changes something and immediately maps it back, without giving KWin
00347 // a chance to reparent it back to root
00348 // since KWin can get MapRequest only for root window children and
00349 // children of WindowWrapper (=clients), the check is AFAIK useless anyway
00350 // Note: Now the save-set support in Client::mapRequestEvent() actually requires that
00351 // this code doesn't check the parent to be root.
00352 //            if ( e->xmaprequest.parent == root ) { //###TODO store previously destroyed client ids
00353                 if ( addSystemTrayWin( e->xmaprequest.window ) )
00354                     return TRUE;
00355                 c = createClient( e->xmaprequest.window, false );
00356                 if ( c != NULL && root != qt_xrootwin() ) 
00357                     { // TODO what is this?
00358                     // TODO may use QWidget::create
00359                     XReparentWindow( qt_xdisplay(), c->frameId(), root, 0, 0 );
00360                     }
00361                 if( c == NULL ) // refused to manage, simply map it (most probably override redirect)
00362                     XMapRaised( qt_xdisplay(), e->xmaprequest.window );
00363                 return true;
00364                 }
00365             if ( c ) 
00366                 {
00367                 c->windowEvent( e );
00368                 if ( !c->wantsTabFocus())
00369                     focus_chain.remove( c );  // TODO move focus_chain changes to functions
00370                 return true;
00371                 }
00372             break;
00373             }
00374         case EnterNotify:
00375             if ( QWhatsThis::inWhatsThisMode() )
00376             {
00377             QWidget* w = QWidget::find( e->xcrossing.window );
00378             if ( w )
00379                 QWhatsThis::leaveWhatsThisMode();
00380             }
00381 
00382             if (electric_have_borders &&
00383                (e->xcrossing.window == electric_top_border ||
00384                 e->xcrossing.window == electric_left_border ||
00385                 e->xcrossing.window == electric_bottom_border ||
00386                 e->xcrossing.window == electric_right_border))
00387                 {
00388                 // the user entered an electric border
00389                 electricBorder(e);
00390                 }
00391             break;
00392         case LeaveNotify:
00393             {
00394             if ( !QWhatsThis::inWhatsThisMode() )
00395                 break;
00396             // TODO is this cliente ever found, given that client events are searched above?
00397             Client* c = findClient( FrameIdMatchPredicate( e->xcrossing.window ));
00398             if ( c && e->xcrossing.detail != NotifyInferior )
00399                 QWhatsThis::leaveWhatsThisMode();
00400             break;
00401             }
00402         case ConfigureRequest:
00403             {
00404             if ( e->xconfigurerequest.parent == root ) 
00405                 {
00406                 XWindowChanges wc;
00407                 unsigned int value_mask = 0;
00408                 wc.border_width = 0;
00409                 wc.x = e->xconfigurerequest.x;
00410                 wc.y = e->xconfigurerequest.y;
00411                 wc.width = e->xconfigurerequest.width;
00412                 wc.height = e->xconfigurerequest.height;
00413                 wc.sibling = None;
00414                 wc.stack_mode = Above;
00415                 value_mask = e->xconfigurerequest.value_mask | CWBorderWidth;
00416                 XConfigureWindow( qt_xdisplay(), e->xconfigurerequest.window, value_mask, &wc );
00417                 return true;
00418                 }
00419             break;
00420             }
00421         case KeyPress:
00422             if ( mouse_emulation )
00423                 return keyPressMouseEmulation( e->xkey );
00424             break;
00425         case KeyRelease:
00426             if ( mouse_emulation )
00427                 return FALSE;
00428             break;
00429         case FocusIn:
00430             if( e->xfocus.window == rootWin()
00431                 && ( e->xfocus.detail == NotifyDetailNone || e->xfocus.detail == NotifyPointerRoot ))
00432                 {
00433                 updateXTime(); // focusToNull() uses qt_x_time, which is old now (FocusIn has no timestamp)
00434                 Window focus;
00435                 int revert;
00436                 XGetInputFocus( qt_xdisplay(), &focus, &revert );
00437                 if( focus == None || focus == PointerRoot )
00438                     {
00439                     //kdWarning( 1212 ) << "X focus set to None/PointerRoot, reseting focus" << endl;
00440                     if( mostRecentlyActivatedClient() != NULL )
00441                         requestFocus( mostRecentlyActivatedClient(), true );
00442                     else
00443                         focusToNull();
00444                     }
00445                 }
00446             // fall through
00447         case FocusOut:
00448             return true; // always eat these, they would tell Qt that KWin is the active app
00449         default:
00450             break;
00451         }
00452     return FALSE;
00453     }
00454 
00455 // Some events don't have the actual window which caused the event
00456 // as e->xany.window (e.g. ConfigureRequest), but as some other
00457 // field in the XEvent structure.
00458 Window Workspace::findSpecialEventWindow( XEvent* e )
00459     {
00460     switch( e->type )
00461         {
00462         case CreateNotify:
00463             return e->xcreatewindow.window;
00464         case DestroyNotify:
00465             return e->xdestroywindow.window;
00466         case UnmapNotify:
00467             return e->xunmap.window;
00468         case MapNotify:
00469             return e->xmap.window;
00470         case MapRequest:
00471             return e->xmaprequest.window;
00472         case ReparentNotify:
00473             return e->xreparent.window;
00474         case ConfigureNotify:
00475             return e->xconfigure.window;
00476         case GravityNotify:
00477             return e->xgravity.window;
00478         case ConfigureRequest:
00479             return e->xconfigurerequest.window;
00480         case CirculateNotify:
00481             return e->xcirculate.window;
00482         case CirculateRequest:
00483             return e->xcirculaterequest.window;
00484         default:
00485             return None;
00486         };
00487     }
00488 
00492 bool Workspace::netCheck( XEvent* e )
00493     {
00494     unsigned int dirty = rootInfo->event( e );
00495 
00496     if ( dirty & NET::DesktopNames )
00497         saveDesktopSettings();
00498 
00499     return dirty != 0;
00500     }
00501 
00502 
00503 // ****************************************
00504 // Client
00505 // ****************************************
00506 
00510 bool Client::windowEvent( XEvent* e )
00511     {
00512     if( e->xany.window == window()) // avoid doing stuff on frame or wrapper
00513         {
00514         unsigned long dirty[ 2 ];
00515         info->event( e, dirty, 2 ); // pass through the NET stuff
00516 
00517         if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMName ) != 0 )
00518             fetchName();
00519         if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconName ) != 0 )
00520             fetchIconicName();
00521         if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMStrut ) != 0
00522             || ( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2ExtendedStrut ) != 0 )
00523             {
00524             if( isTopMenu())  // the fallback mode of KMenuBar may alter the strut
00525                 checkWorkspacePosition();  // restore it
00526             workspace()->updateClientArea();
00527             }
00528         if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
00529             getIcons();
00530         // Note there's a difference between userTime() and info->userTime()
00531         // info->userTime() is the value of the property, userTime() also includes
00532         // updates of the time done by KWin (ButtonPress on windowrapper etc.).
00533         if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2UserTime ) != 0 )
00534             {
00535             workspace()->setWasUserInteraction();
00536             updateUserTime( info->userTime());
00537             }
00538         if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
00539             startupIdChanged();
00540         }
00541 
00542 // TODO move all focus handling stuff to separate file?
00543     switch (e->type) 
00544         {
00545         case UnmapNotify:
00546             unmapNotifyEvent( &e->xunmap );
00547             break;
00548         case DestroyNotify:
00549             destroyNotifyEvent( &e->xdestroywindow );
00550             break;
00551         case MapRequest:
00552             // this one may pass the event to workspace
00553             return mapRequestEvent( &e->xmaprequest );
00554         case ConfigureRequest:
00555             configureRequestEvent( &e->xconfigurerequest );
00556             break;
00557         case PropertyNotify:
00558             propertyNotifyEvent( &e->xproperty );
00559             break;
00560         case KeyPress:
00561             updateUserTime();
00562             workspace()->setWasUserInteraction();
00563             break;
00564         case ButtonPress:
00565             updateUserTime();
00566             workspace()->setWasUserInteraction();
00567             buttonPressEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
00568                 e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
00569             break;;
00570         case KeyRelease:
00571     // don't update user time on releases
00572     // e.g. if the user presses Alt+F2, the Alt release
00573     // would appear as user input to the currently active window
00574             break;
00575         case ButtonRelease:
00576     // don't update user time on releases
00577     // e.g. if the user presses Alt+F2, the Alt release
00578     // would appear as user input to the currently active window
00579             buttonReleaseEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
00580                 e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
00581             break;
00582         case MotionNotify:
00583             motionNotifyEvent( e->xmotion.window, e->xmotion.state,
00584                 e->xmotion.x, e->xmotion.y, e->xmotion.x_root, e->xmotion.y_root );
00585             break;
00586         case EnterNotify:
00587             enterNotifyEvent( &e->xcrossing );
00588             // MotionNotify is guaranteed to be generated only if the mouse
00589             // move start and ends in the window; for cases when it only
00590             // starts or only ends there, Enter/LeaveNotify are generated.
00591             // Fake a MotionEvent in such cases to make handle of mouse
00592             // events simpler (Qt does that too).
00593             motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
00594                 e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
00595             break;
00596         case LeaveNotify:
00597             motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
00598                 e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
00599             leaveNotifyEvent( &e->xcrossing );
00600             break;
00601         case FocusIn:
00602             focusInEvent( &e->xfocus );
00603             break;
00604         case FocusOut:
00605             focusOutEvent( &e->xfocus );
00606             break;
00607         case ReparentNotify:
00608             break;
00609         case ClientMessage:
00610             clientMessageEvent( &e->xclient );
00611             break;
00612         case ColormapChangeMask:
00613             if( e->xany.window == window())
00614             {
00615             cmap = e->xcolormap.colormap;
00616             if ( isActive() )
00617                 workspace()->updateColormap();
00618             }
00619             break;
00620         case VisibilityNotify:
00621             visibilityNotifyEvent( &e->xvisibility );
00622             break;
00623         default:
00624             if( e->xany.window == window())
00625             {
00626             if( e->type == Shape::shapeEvent() )
00627                 {
00628                 is_shape = Shape::hasShape( window()); // workaround for #19644
00629                 updateShape();
00630                 }
00631             }
00632             break;
00633         }
00634     return true; // eat all events
00635     }
00636 
00640 bool Client::mapRequestEvent( XMapRequestEvent* e )
00641     {
00642     if( e->window != window())
00643         {
00644         // Special support for the save-set feature, which is a bit broken.
00645         // If there's a window from one client embedded in another one,
00646         // e.g. using XEMBED, and the embedder suddenly looses its X connection,
00647         // save-set will reparent the embedded window to its closest ancestor
00648         // that will remains. Unfortunately, with reparenting window managers,
00649         // this is not the root window, but the frame (or in KWin's case,
00650         // it's the wrapper for the client window). In this case,
00651         // the wrapper will get ReparentNotify for a window it won't know,
00652         // which will be ignored, and then it gets MapRequest, as save-set
00653         // always maps. Returning true here means that Workspace::workspaceEvent()
00654         // will handle this MapRequest and manage this window (i.e. act as if
00655         // it was reparented to root window).
00656         if( e->parent == wrapperId())
00657             return false;
00658         return true; // no messing with frame etc.
00659         }
00660     if( isTopMenu() && workspace()->managingTopMenus())
00661         return true; // kwin controls these
00662     switch ( mappingState() )
00663         {
00664         case WithdrawnState:
00665             assert( false ); // WMs are not supposed to manage clients in Withdrawn state,
00666 //        manage();      // after initial mapping manage() is called from createClient()
00667             break;
00668         case IconicState:
00669     // also copied in clientMessage()
00670             if( isMinimized())
00671                 unminimize();
00672             if( isShade())
00673                 setShade( ShadeNone );
00674             if( !isOnCurrentDesktop())
00675                 {
00676                 if( workspace()->allowClientActivation( this ))
00677                     workspace()->activateClient( this );
00678                 else
00679                     demandAttention();
00680                 }
00681             break;
00682         case NormalState:
00683         // TODO fake MapNotify?
00684             break;
00685         }
00686     return true;
00687     }
00688 
00692 void Client::unmapNotifyEvent( XUnmapEvent* e )
00693     {
00694     if( e->window != window())
00695         return;
00696     if( e->event != wrapperId())
00697         { // most probably event from root window when initially reparenting
00698         bool ignore = true;
00699         if( e->event == workspace()->rootWin() && e->send_event )
00700             ignore = false; // XWithdrawWindow()
00701         if( ignore )
00702             return;
00703         }
00704     switch( mappingState())
00705         {
00706         case IconicState:
00707             releaseWindow();
00708           return;
00709         case NormalState:
00710             // maybe we will be destroyed soon. Check this first.
00711             XEvent ev;
00712             if( XCheckTypedWindowEvent (qt_xdisplay(), window(),
00713                 DestroyNotify, &ev) ) // TODO I don't like this much
00714                 {
00715                 destroyClient(); // deletes this
00716                 return;
00717                 }
00718             releaseWindow();
00719           break;
00720     default:
00721         assert( false );
00722         }
00723     }
00724 
00725 void Client::destroyNotifyEvent( XDestroyWindowEvent* e )
00726     {
00727     if( e->window != window())
00728         return;
00729     destroyClient();
00730     }
00731     
00732     
00733 bool         blockAnimation = FALSE;
00734 
00738 void Client::clientMessageEvent( XClientMessageEvent* e )
00739     {
00740     if( e->window != window())
00741         return; // ignore frame/wrapper
00742     // WM_STATE
00743     if ( e->message_type == atoms->kde_wm_change_state )
00744         {
00745         if( isTopMenu() && workspace()->managingTopMenus())
00746             return; // kwin controls these
00747         if( e->data.l[ 1 ] )
00748             blockAnimation = true;
00749         if( e->data.l[ 0 ] == IconicState )
00750             minimize();
00751         else if( e->data.l[ 0 ] == NormalState )
00752             { // copied from mapRequest()
00753             if( isMinimized())
00754                 unminimize();
00755             if( isShade())
00756                 setShade( ShadeNone );
00757             if( !isOnCurrentDesktop())
00758                 {
00759                 if( workspace()->allowClientActivation( this ))
00760                     workspace()->activateClient( this );
00761                 else
00762                     demandAttention();
00763                 }
00764             }
00765         blockAnimation = false;
00766         }
00767     else if ( e->message_type == atoms->wm_change_state)
00768         {
00769         if( isTopMenu() && workspace()->managingTopMenus())
00770             return; // kwin controls these
00771         if ( e->data.l[0] == IconicState )
00772             minimize();
00773         return;
00774         }
00775     }
00776 
00777 
00781 void Client::configureRequestEvent( XConfigureRequestEvent* e )
00782     {
00783     if( e->window != window())
00784         return; // ignore frame/wrapper
00785     if ( isResize() || isMove())
00786         return; // we have better things to do right now
00787 
00788     if( fullscreen_mode == FullScreenNormal ) // refuse resizing of fullscreen windows
00789         { // but allow resizing fullscreen hacks in order to let them cancel fullscreen mode
00790         sendSyntheticConfigureNotify();
00791         return;
00792         }
00793     if( isSplash() // no manipulations with splashscreens either
00794         || isTopMenu()) // topmenus neither
00795         {
00796         sendSyntheticConfigureNotify();
00797         return;
00798         }
00799 
00800     if ( e->value_mask & CWBorderWidth ) 
00801         {
00802         // first, get rid of a window border
00803         XWindowChanges wc;
00804         unsigned int value_mask = 0;
00805 
00806         wc.border_width = 0;
00807         value_mask = CWBorderWidth;
00808         XConfigureWindow( qt_xdisplay(), window(), value_mask, & wc );
00809         }
00810 
00811     if( e->value_mask & ( CWX | CWY | CWHeight | CWWidth ))
00812         configureRequest( e->value_mask, e->x, e->y, e->width, e->height, 0, false );
00813 
00814     if ( e->value_mask & CWStackMode )
00815         restackWindow( e->above, e->detail, NET::FromApplication, userTime(), false );
00816 
00817     // TODO sending a synthetic configure notify always is fine, even in cases where
00818     // the ICCCM doesn't require this - it can be though of as 'the WM decided to move
00819     // the window later'. The client should not cause that many configure request,
00820     // so this should not have any significant impact. With user moving/resizing
00821     // the it should be optimized though (see also Client::setGeometry()/plainResize()/move()).
00822     sendSyntheticConfigureNotify();
00823 
00824     // SELI TODO accept configure requests for isDesktop windows (because kdesktop
00825     // may get XRANDR resize event before kwin), but check it's still at the bottom?
00826     }
00827 
00828 
00832 void Client::propertyNotifyEvent( XPropertyEvent* e )
00833     {
00834     if( e->window != window())
00835         return; // ignore frame/wrapper
00836     switch ( e->atom ) 
00837         {
00838         case XA_WM_NORMAL_HINTS:
00839             getWmNormalHints();
00840             break;
00841         case XA_WM_NAME:
00842             fetchName();
00843             break;
00844         case XA_WM_ICON_NAME:
00845             fetchIconicName();
00846             break;
00847         case XA_WM_TRANSIENT_FOR:
00848             readTransient();
00849             break;
00850         case XA_WM_HINTS:
00851             getWMHints();
00852             getIcons(); // because KWin::icon() uses WMHints as fallback
00853             break;
00854         default:
00855             if ( e->atom == atoms->wm_protocols )
00856                 getWindowProtocols();
00857             else if (e->atom == atoms->wm_client_leader )
00858                 getWmClientLeader();
00859             else if( e->atom == qt_window_role )
00860                 window_role = staticWindowRole( window());
00861             else if( e->atom == atoms->motif_wm_hints )
00862                 getMotifHints();
00863             break;
00864         }
00865     }
00866 
00867 
00868 void Client::enterNotifyEvent( XCrossingEvent* e )
00869     {
00870     if( e->window != frameId())
00871         return; // care only about entering the whole frame
00872     if( e->mode == NotifyNormal ||
00873          ( !options->focusPolicyIsReasonable() &&
00874              e->mode == NotifyUngrab ) ) 
00875         {
00876 
00877         if (options->shadeHover && isShade()) 
00878             {
00879             delete shadeHoverTimer;
00880             shadeHoverTimer = new QTimer( this );
00881             connect( shadeHoverTimer, SIGNAL( timeout() ), this, SLOT( shadeHover() ));
00882             shadeHoverTimer->start( options->shadeHoverInterval, TRUE );
00883             }
00884 
00885         if ( options->focusPolicy == Options::ClickToFocus )
00886             return;
00887 
00888         if ( options->autoRaise && !isDesktop() &&
00889              !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() &&
00890              workspace()->topClientOnDesktop( workspace()->currentDesktop()) != this ) 
00891             {
00892             delete autoRaiseTimer;
00893             autoRaiseTimer = new QTimer( this );
00894             connect( autoRaiseTimer, SIGNAL( timeout() ), this, SLOT( autoRaise() ) );
00895             autoRaiseTimer->start( options->autoRaiseInterval, TRUE  );
00896             }
00897 
00898         if ( options->focusPolicy !=  Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isTopMenu() ) )
00899             return;
00900         if ( options->delayFocus )
00901             workspace()->requestDelayFocus( this );
00902         else
00903             workspace()->requestFocus( this );
00904 
00905         return;
00906         }
00907     }
00908 
00909 void Client::leaveNotifyEvent( XCrossingEvent* e )
00910     {
00911     if( e->window != frameId())
00912         return; // care only about leaving the whole frame
00913     if ( e->mode == NotifyNormal ) 
00914         {
00915         if ( !buttonDown ) 
00916             {
00917             mode = PositionCenter;
00918             setCursor( arrowCursor );
00919             }
00920         bool lostMouse = !rect().contains( QPoint( e->x, e->y ) );
00921         // 'lostMouse' wouldn't work with e.g. B2 or Keramik, which have non-rectangular decorations
00922         // (i.e. the LeaveNotify event comes before leaving the rect and no LeaveNotify event
00923         // comes after leaving the rect) - so lets check if the pointer is really outside the window
00924 
00925         // TODO this still sucks if a window appears above this one - it should lose the mouse
00926         // if this window is another client, but not if it's a popup ... maybe after KDE3.1 :(
00927         // (repeat after me 'AARGHL!')
00928         if ( !lostMouse && e->detail != NotifyInferior ) 
00929             {
00930             int d1, d2, d3, d4;
00931             unsigned int d5;
00932             Window w, child;
00933             if( XQueryPointer( qt_xdisplay(), frameId(), &w, &child, &d1, &d2, &d3, &d4, &d5 ) == False
00934                 || child == None )
00935                 lostMouse = true; // really lost the mouse
00936             }
00937         if ( lostMouse ) 
00938             {
00939             cancelAutoRaise();
00940             workspace()->cancelDelayFocus();
00941             delete shadeHoverTimer;
00942             shadeHoverTimer = 0;
00943             if ( shade_mode == ShadeHover && !moveResizeMode && !buttonDown )
00944                setShade( ShadeNormal );
00945             }
00946         if ( options->focusPolicy == Options::FocusStrictlyUnderMouse )
00947             if ( isActive() && lostMouse )
00948                 workspace()->requestFocus( 0 ) ;
00949         return;
00950         }
00951     }
00952 
00953 #define XCapL KKeyNative::modXLock()
00954 #define XNumL KKeyNative::modXNumLock()
00955 #define XScrL KKeyNative::modXScrollLock()
00956 void Client::grabButton( int modifier )
00957     {
00958     unsigned int mods[ 8 ] = 
00959         {
00960         0, XCapL, XNumL, XNumL | XCapL,
00961         XScrL, XScrL | XCapL,
00962         XScrL | XNumL, XScrL | XNumL | XCapL
00963         };
00964     for( int i = 0;
00965          i < 8;
00966          ++i )
00967         XGrabButton( qt_xdisplay(), AnyButton,
00968             modifier | mods[ i ],
00969             wrapperId(),  FALSE, ButtonPressMask,
00970             GrabModeSync, GrabModeAsync, None, None );
00971     }
00972 
00973 void Client::ungrabButton( int modifier )
00974     {
00975     unsigned int mods[ 8 ] = 
00976         {
00977         0, XCapL, XNumL, XNumL | XCapL,
00978         XScrL, XScrL | XCapL,
00979         XScrL | XNumL, XScrL | XNumL | XCapL
00980         };
00981     for( int i = 0;
00982          i < 8;
00983          ++i )
00984         XUngrabButton( qt_xdisplay(), AnyButton,
00985             modifier | mods[ i ], wrapperId());
00986     }
00987 #undef XCapL
00988 #undef XNumL
00989 #undef XScrL
00990 
00991 /*
00992   Releases the passive grab for some modifier combinations when a
00993   window becomes active. This helps broken X programs that
00994   missinterpret LeaveNotify events in grab mode to work properly
00995   (Motif, AWT, Tk, ...)
00996  */
00997 void Client::updateMouseGrab()
00998     {                   // see Workspace::establishTabBoxGrab()
00999     if( isActive() && !workspace()->forcedGlobalMouseGrab())
01000         {
01001         // remove the grab for no modifiers only if the window
01002         // is unobscured or if the user doesn't want click raise
01003         if( !options->clickRaise || not_obscured )
01004             ungrabButton( None );
01005         else
01006             grabButton( None );
01007         ungrabButton( ShiftMask );
01008         ungrabButton( ControlMask );
01009         ungrabButton( ControlMask | ShiftMask );
01010         }
01011     else
01012         {
01013         XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, wrapperId());
01014         // simply grab all modifier combinations
01015         XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE,
01016             ButtonPressMask,
01017             GrabModeSync, GrabModeAsync,
01018             None, None );
01019         }
01020     }
01021 
01022 int qtToX11Button( Qt::ButtonState button )
01023     {
01024     if( button == Qt::LeftButton )
01025         return Button1;
01026     else if( button == Qt::MidButton )
01027         return Button2;
01028     else if( button == Qt::RightButton )
01029         return Button3;
01030     return AnyButton;
01031     }
01032     
01033 int qtToX11State( Qt::ButtonState state )
01034     {
01035     int ret = 0;
01036     if( state & Qt::LeftButton )
01037         ret |= Button1Mask;
01038     if( state & Qt::MidButton )
01039         ret |= Button2Mask;
01040     if( state & Qt::RightButton )
01041         ret |= Button3Mask;
01042     if( state & Qt::ShiftButton )
01043         ret |= ShiftMask;
01044     if( state & Qt::ControlButton )
01045         ret |= ControlMask;
01046     if( state & Qt::AltButton )
01047         ret |= KKeyNative::modX(KKey::ALT);
01048     if( state & Qt::MetaButton )
01049         ret |= KKeyNative::modX(KKey::WIN);
01050     return ret;
01051     }
01052 
01053 // Qt propagates mouse events up the widget hierachy, which means events
01054 // for the decoration window cannot be (easily) intercepted as X11 events
01055 bool Client::eventFilter( QObject* o, QEvent* e )
01056     {
01057     if( decoration == NULL
01058         || o != decoration->widget())
01059         return false;
01060     if( e->type() == QEvent::MouseButtonPress )
01061         {
01062         QMouseEvent* ev = static_cast< QMouseEvent* >( e );
01063         return buttonPressEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
01064             ev->x(), ev->y(), ev->globalX(), ev->globalY() );
01065         }
01066     if( e->type() == QEvent::MouseButtonRelease )
01067         {
01068         QMouseEvent* ev = static_cast< QMouseEvent* >( e );
01069         return buttonReleaseEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
01070             ev->x(), ev->y(), ev->globalX(), ev->globalY() );
01071         }
01072     if( e->type() == QEvent::MouseMove ) // FRAME i fake z enter/leave?
01073         {
01074         QMouseEvent* ev = static_cast< QMouseEvent* >( e );
01075         return motionNotifyEvent( decorationId(), qtToX11State( ev->state()),
01076             ev->x(), ev->y(), ev->globalX(), ev->globalY() );
01077         }
01078     if( e->type() == QEvent::Resize )
01079         {
01080         QResizeEvent* ev = static_cast< QResizeEvent* >( e );
01081         // Filter out resize events that inform about size different than frame size.
01082         // This will ensure that decoration->width() etc. and decoration->widget()->width() will be in sync.
01083         // These events only seem to be delayed events from initial resizing before show() was called
01084         // on the decoration widget.
01085         if( ev->size() != size())
01086             return true;
01087         }
01088     return false;
01089     }
01090 
01091 // return value matters only when filtering events before decoration gets them
01092 bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root )
01093     {
01094     if (buttonDown)
01095         {
01096         if( w == wrapperId())
01097             XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time);
01098         return true;
01099         }
01100 
01101     if( w == wrapperId() || w == frameId() || w == decorationId())
01102         { // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace
01103         updateUserTime();
01104         workspace()->setWasUserInteraction();
01105         uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ?
01106             KKeyNative::modX(KKey::WIN) :
01107             KKeyNative::modX(KKey::ALT);
01108         bool bModKeyHeld = keyModX != 0 && ( state & KKeyNative::accelModMaskX()) == keyModX;
01109 
01110         if( isSplash()
01111             && button == Button1 && !bModKeyHeld )
01112             { // hide splashwindow if the user clicks on it
01113             hideClient( true );
01114             if( w == wrapperId())
01115                     XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time);
01116             return true;
01117             }
01118 
01119         Options::MouseCommand com = Options::MouseNothing;
01120         bool was_action = false;
01121         bool perform_handled = false;
01122         if ( bModKeyHeld )
01123             {
01124             was_action = true;
01125             switch (button) 
01126                 {
01127                 case Button1:
01128                     com = options->commandAll1();
01129                     break;
01130                 case Button2:
01131                     com = options->commandAll2();
01132                     break;
01133                 case Button3:
01134                     com = options->commandAll3();
01135                     break;
01136                 }
01137             }
01138         else
01139             { // inactive inner window
01140             if( !isActive() && w == wrapperId())
01141                 {
01142                 was_action = true;
01143                 perform_handled = true;
01144                 switch (button) 
01145                     {
01146                     case Button1:
01147                         com = options->commandWindow1();
01148                         break;
01149                     case Button2:
01150                         com = options->commandWindow2();
01151                         break;
01152                     case Button3:
01153                         com = options->commandWindow3();
01154                         break;
01155                     default:
01156                         com = Options::MouseActivateAndPassClick;
01157                     }
01158                 }
01159             // active inner window
01160             if( isActive() && w == wrapperId()
01161                 && options->clickRaise && button < 4 ) // exclude wheel
01162                 {
01163                 com = Options::MouseActivateRaiseAndPassClick;
01164                 was_action = true;
01165                 perform_handled = true;
01166                 }
01167             }
01168         if( was_action )
01169             {
01170             bool replay = performMouseCommand( com, QPoint( x_root, y_root), perform_handled );
01171 
01172             if ( isSpecialWindow() && !isOverride())
01173                 replay = TRUE;
01174 
01175                 if( w == wrapperId()) // these can come only from a grab
01176                     XAllowEvents(qt_xdisplay(), replay? ReplayPointer : SyncPointer, CurrentTime ); //qt_x_time);
01177             return true;
01178             }
01179         }
01180 
01181     if( w == wrapperId()) // these can come only from a grab
01182         {
01183         XAllowEvents(qt_xdisplay(), ReplayPointer, CurrentTime ); //qt_x_time);
01184         return true;
01185         }
01186     if( w == decorationId())
01187         return false; // don't eat decoration events
01188     if( w == frameId())
01189         processDecorationButtonPress( button, state, x, y, x_root, y_root );
01190     return true;
01191     }
01192 
01193 
01194 // this function processes button press events only after decoration decides not to handle them,
01195 // unlike buttonPressEvent(), which (when the window is decoration) filters events before decoration gets them
01196 void Client::processDecorationButtonPress( int button, int /*state*/, int x, int y, int x_root, int y_root )
01197     {
01198     Options::MouseCommand com = Options::MouseNothing;
01199     bool active = isActive();
01200     if ( !wantsInput() ) // we cannot be active, use it anyway
01201         active = TRUE;
01202 
01203     if ( button == Button1 )
01204         com = active ? options->commandActiveTitlebar1() : options->commandInactiveTitlebar1();
01205     else if ( button == Button2 )
01206         com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2();
01207     else if ( button == Button3 )
01208         com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3();
01209     if( com != Options::MouseOperationsMenu // actions where it's not possible to get the matching
01210         && com != Options::MouseMinimize )  // mouse release event
01211         {
01212 // FRAME      mouseMoveEvent( e ); shouldn't be necessary
01213         buttonDown = TRUE;
01214         moveOffset = QPoint( x, y );
01215         invertedMoveOffset = rect().bottomRight() - moveOffset;
01216         unrestrictedMoveResize = false;
01217         setCursor( mode ); // update to sizeAllCursor if about to move
01218         }
01219     performMouseCommand( com, QPoint( x_root, y_root ));
01220     }
01221 
01222 // called from decoration
01223 void Client::processMousePressEvent( QMouseEvent* e )
01224     {
01225     if( e->type() != QEvent::MouseButtonPress )
01226         {
01227         kdWarning() << "processMousePressEvent()" << endl;
01228         return;
01229         }
01230     int button;
01231     switch( e->button())
01232         {
01233         case LeftButton:
01234             button = Button1;
01235           break;
01236         case MidButton:
01237             button = Button2;
01238           break;
01239         case RightButton:
01240             button = Button3;
01241           break;
01242         default:
01243             return;
01244         }
01245     processDecorationButtonPress( button, e->state(), e->x(), e->y(), e->globalX(), e->globalY());
01246     }
01247 
01248 // return value matters only when filtering events before decoration gets them
01249 bool Client::buttonReleaseEvent( Window w, int /*button*/, int state, int x, int y, int x_root, int y_root )
01250     {
01251     if( w == decorationId() && !buttonDown)
01252         return false;
01253     if( w == wrapperId())
01254         {
01255         XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time);
01256         return true;
01257         }
01258     if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
01259         return true;
01260     x = this->x(); // translate from grab window to local coords
01261     y = this->y();
01262     if ( (state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 )
01263         {
01264         buttonDown = FALSE;
01265         if ( moveResizeMode ) 
01266             {
01267             finishMoveResize( false );
01268             // mouse position is still relative to old Client position, adjust it
01269             QPoint mousepos( x_root - x, y_root - y );
01270             mode = mousePosition( mousepos );
01271             }
01272         setCursor( mode );
01273         }
01274     return true;
01275     }
01276 
01277 static bool was_motion = false;
01278 static Time next_motion_time = CurrentTime;
01279 // Check whole incoming X queue for MotionNotify events
01280 // checking whole queue is done by always returning False in the predicate.
01281 // If there are more MotionNotify events in the queue, all until the last
01282 // one may be safely discarded (if a ButtonRelease event comes, a MotionNotify
01283 // will be faked from it, so there's no need to check other events).
01284 // This helps avoiding being overloaded by being flooded from many events
01285 // from the XServer.
01286 static Bool motion_predicate( Display*, XEvent* ev, XPointer )
01287 {
01288     if( ev->type == MotionNotify )
01289         {
01290     was_motion = true;
01291         next_motion_time = ev->xmotion.time;  // for setting time
01292         }
01293     return False;
01294 }
01295 
01296 static bool waitingMotionEvent()
01297     {
01298 // The queue doesn't need to be checked until the X timestamp
01299 // of processes events reaches the timestamp of the last suitable
01300 // MotionNotify event in the queue.
01301     if( next_motion_time != CurrentTime
01302         && timestampCompare( qt_x_time, next_motion_time ) < 0 )
01303         return true;
01304     was_motion = false;
01305     XSync( qt_xdisplay(), False ); // this helps to discard more MotionNotify events
01306     XEvent dummy;
01307     XCheckIfEvent( qt_xdisplay(), &dummy, motion_predicate, NULL );
01308     return was_motion;
01309     }
01310 
01311 // return value matters only when filtering events before decoration gets them
01312 bool Client::motionNotifyEvent( Window w, int /*state*/, int x, int y, int x_root, int y_root )
01313     {
01314     if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
01315         return true; // care only about the whole frame
01316     if ( !buttonDown ) 
01317         {
01318         Position newmode = mousePosition( QPoint( x, y ));
01319         if( newmode != mode )
01320             setCursor( newmode );
01321         mode = newmode;
01322         // reset the timestamp for the optimization, otherwise with long passivity
01323         // the option in waitingMotionEvent() may be always true
01324         next_motion_time = CurrentTime;
01325         return false;
01326         }
01327     if( w == moveResizeGrabWindow())
01328         {
01329         x = this->x(); // translate from grab window to local coords
01330         y = this->y();
01331         }
01332     if( !waitingMotionEvent())
01333         handleMoveResize( x, y, x_root, y_root );
01334     return true;
01335     }
01336     
01337 void Client::focusInEvent( XFocusInEvent* e )
01338     {
01339     if( e->window != window())
01340         return; // only window gets focus
01341     if ( e->mode == NotifyUngrab )
01342         return; // we don't care
01343     if ( e->detail == NotifyPointer )
01344         return;  // we don't care
01345     if( !isShown( false ) || !isOnCurrentDesktop()) // we unmapped it, but it got focus meanwhile ->
01346         return;            // activateNextClient() already transferred focus elsewhere
01347     // check if this client is in should_get_focus list or if activation is allowed
01348     bool activate =  workspace()->allowClientActivation( this, -1U, true );
01349     workspace()->gotFocusIn( this ); // remove from should_get_focus list
01350     if( activate )
01351         setActive( TRUE );
01352     else
01353         {
01354         workspace()->restoreFocus();
01355         demandAttention();
01356         }
01357     }
01358 
01359 // When a client loses focus, FocusOut events are usually immediatelly
01360 // followed by FocusIn events for another client that gains the focus
01361 // (unless the focus goes to another screen, or to the nofocus widget).
01362 // Without this check, the former focused client would have to be
01363 // deactivated, and after that, the new one would be activated, with
01364 // a short time when there would be no active client. This can cause
01365 // flicker sometimes, e.g. when a fullscreen is shown, and focus is transferred
01366 // from it to its transient, the fullscreen would be kept in the Active layer
01367 // at the beginning and at the end, but not in the middle, when the active
01368 // client would be temporarily none (see Client::belongToLayer() ).
01369 // Therefore, the events queue is checked, whether it contains the matching
01370 // FocusIn event, and if yes, deactivation of the previous client will
01371 // be skipped, as activation of the new one will automatically deactivate
01372 // previously active client.
01373 static bool follows_focusin = false;
01374 static bool follows_focusin_failed = false;
01375 static Bool predicate_follows_focusin( Display*, XEvent* e, XPointer arg )
01376     {
01377     if( follows_focusin || follows_focusin_failed )
01378         return False;
01379     Client* c = ( Client* ) arg;
01380     if( e->type == FocusIn && c->workspace()->findClient( WindowMatchPredicate( e->xfocus.window )))
01381         { // found FocusIn
01382         follows_focusin = true;
01383         return False;
01384         }
01385     // events that may be in the queue before the FocusIn event that's being
01386     // searched for
01387     if( e->type == FocusIn || e->type == FocusOut || e->type == KeymapNotify )
01388         return False;
01389     follows_focusin_failed = true; // a different event - stop search
01390     return False;
01391     }
01392 
01393 static bool check_follows_focusin( Client* c )
01394     {
01395     follows_focusin = follows_focusin_failed = false;
01396     XEvent dummy;
01397     // XCheckIfEvent() is used to make the search non-blocking, the predicate
01398     // always returns False, so nothing is removed from the events queue.
01399     // XPeekIfEvent() would block.
01400     XCheckIfEvent( qt_xdisplay(), &dummy, predicate_follows_focusin, (XPointer)c );
01401     return follows_focusin;
01402     }
01403 
01404 
01405 void Client::focusOutEvent( XFocusOutEvent* e )
01406     {
01407     if( e->window != window())
01408         return; // only window gets focus
01409     if ( e->mode == NotifyGrab )
01410         return; // we don't care
01411     if ( isShade() )
01412         return; // here neither
01413     if ( e->detail != NotifyNonlinear
01414         && e->detail != NotifyNonlinearVirtual )
01415         // SELI check all this
01416         return; // hack for motif apps like netscape
01417     if ( QApplication::activePopupWidget() )
01418         return;
01419     if( !check_follows_focusin( this ))
01420         setActive( FALSE );
01421     }
01422 
01423 void Client::visibilityNotifyEvent( XVisibilityEvent * e)
01424     {
01425     if( e->window != frameId())
01426         return; // care only about the whole frame
01427     bool new_not_obscured = e->state == VisibilityUnobscured;
01428     if( not_obscured == new_not_obscured )
01429         return;
01430     not_obscured = new_not_obscured;
01431     updateMouseGrab();
01432     }
01433 
01434 // performs _NET_WM_MOVERESIZE
01435 void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction )
01436     {
01437     if( direction == NET::Move )
01438         performMouseCommand( Options::MouseMove, QPoint( x_root, y_root ));
01439     else if( direction >= NET::TopLeft && direction <= NET::Left ) 
01440         {
01441         static const Position convert[] =
01442             {
01443             PositionTopLeft,
01444             PositionTop,
01445             PositionTopRight,
01446             PositionRight,
01447             PositionBottomRight,
01448             PositionBottom,
01449             PositionBottomLeft,
01450             PositionLeft
01451             };
01452         if(!isResizable() || isShade())
01453             return;
01454         if( moveResizeMode )
01455             finishMoveResize( false );
01456         buttonDown = TRUE;
01457         moveOffset = QPoint( x_root - x(), y_root - y()); // map from global
01458         invertedMoveOffset = rect().bottomRight() - moveOffset;
01459         unrestrictedMoveResize = false;
01460         mode = convert[ direction ];
01461         setCursor( mode );
01462         if( !startMoveResize())
01463             {
01464             buttonDown = false;
01465             setCursor( mode );
01466             }
01467         }
01468     else if( direction == NET::KeyboardMove )
01469         { // ignore mouse coordinates given in the message, mouse position is used by the moving algorithm
01470         QCursor::setPos( geometry().center() );
01471         performMouseCommand( Options::MouseUnrestrictedMove, geometry().center());
01472         }
01473     else if( direction == NET::KeyboardSize )
01474         { // ignore mouse coordinates given in the message, mouse position is used by the resizing algorithm
01475         QCursor::setPos( geometry().bottomRight());
01476         performMouseCommand( Options::MouseUnrestrictedResize, geometry().bottomRight());
01477         }
01478     }
01479 
01480 void Client::keyPressEvent( uint key_code )
01481     {
01482     updateUserTime();
01483     if ( !isMove() && !isResize() )
01484         return;
01485     bool is_control = key_code & Qt::CTRL;
01486     bool is_alt = key_code & Qt::ALT;
01487     key_code = key_code & 0xffff;
01488     int delta = is_control?1:is_alt?32:8;
01489     QPoint pos = QCursor::pos();
01490     switch ( key_code ) 
01491         {
01492         case Key_Left:
01493             pos.rx() -= delta;
01494             break;
01495         case Key_Right:
01496             pos.rx() += delta;
01497             break;
01498         case Key_Up:
01499             pos.ry() -= delta;
01500             break;
01501         case Key_Down:
01502             pos.ry() += delta;
01503             break;
01504         case Key_Space:
01505         case Key_Return:
01506         case Key_Enter:
01507             finishMoveResize( false );
01508             buttonDown = FALSE;
01509             setCursor( mode );
01510             break;
01511         case Key_Escape:
01512             finishMoveResize( true );
01513             buttonDown = FALSE;
01514             setCursor( mode );
01515             break;
01516         default:
01517             return;
01518         }
01519     QCursor::setPos( pos );
01520     }
01521 
01522 // ****************************************
01523 // Group
01524 // ****************************************
01525 
01526 bool Group::groupEvent( XEvent* e )
01527     {
01528     unsigned long dirty[ 2 ];
01529     leader_info->event( e, dirty, 2 ); // pass through the NET stuff
01530     if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
01531         getIcons();
01532     if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
01533         startupIdChanged();
01534     return false;
01535     }
01536 
01537 
01538 } // namespace
KDE Logo
This file is part of the documentation for kwin Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Aug 20 13:39:10 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003