• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • twin
 

twin

events.cpp

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

twin

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

twin

Skip menu "twin"
  • kate
  • libkonq
  • twin
  •   lib
Generated for twin by doxygen 1.6.3
This website is maintained by Timothy Pearson.