kwin Library API Documentation

events.cpp

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