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