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