• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • @topname@
  • Sitemap
  • Contact Us
 

kwin

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

kwin

Skip menu "kwin"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members

@topname@

Skip menu "@topname@"
  • kate
  • kwin
  •   lib
  • libkonq
Generated for @topname@ by doxygen 1.5.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal