• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KWin

events.cpp

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

KWin

Skip menu "KWin"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.7
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