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() && e->xfocus.detail == NotifyDetailNone ) 00418 { 00419 updateXTime(); // focusToNull() uses qt_x_time, which is old now (FocusIn has no timestamp) 00420 Window focus; 00421 int revert; 00422 XGetInputFocus( qt_xdisplay(), &focus, &revert ); 00423 if( focus == None ) 00424 { 00425 kdWarning( 1212 ) << "X focus set to None, reseting focus" << endl; 00426 focusToNull(); 00427 } 00428 } 00429 // fall through 00430 case FocusOut: 00431 return true; // always eat these, they would tell Qt that KWin is the active app 00432 default: 00433 break; 00434 } 00435 return FALSE; 00436 } 00437 00438 // Some events don't have the actual window which caused the event 00439 // as e->xany.window (e.g. ConfigureRequest), but as some other 00440 // field in the XEvent structure. 00441 Window Workspace::findSpecialEventWindow( XEvent* e ) 00442 { 00443 switch( e->type ) 00444 { 00445 case CreateNotify: 00446 return e->xcreatewindow.window; 00447 case DestroyNotify: 00448 return e->xdestroywindow.window; 00449 case UnmapNotify: 00450 return e->xunmap.window; 00451 case MapNotify: 00452 return e->xmap.window; 00453 case MapRequest: 00454 return e->xmaprequest.window; 00455 case ReparentNotify: 00456 return e->xreparent.window; 00457 case ConfigureNotify: 00458 return e->xconfigure.window; 00459 case GravityNotify: 00460 return e->xgravity.window; 00461 case ConfigureRequest: 00462 return e->xconfigurerequest.window; 00463 case CirculateNotify: 00464 return e->xcirculate.window; 00465 case CirculateRequest: 00466 return e->xcirculaterequest.window; 00467 default: 00468 return None; 00469 }; 00470 } 00471 00475 bool Workspace::netCheck( XEvent* e ) 00476 { 00477 unsigned int dirty = rootInfo->event( e ); 00478 00479 if ( dirty & NET::DesktopNames ) 00480 saveDesktopSettings(); 00481 00482 return dirty != 0; 00483 } 00484 00485 00486 // **************************************** 00487 // Client 00488 // **************************************** 00489 00493 bool Client::windowEvent( XEvent* e ) 00494 { 00495 if( e->xany.window == window()) // avoid doing stuff on frame or wrapper 00496 { 00497 unsigned long dirty[ 2 ]; 00498 info->event( e, dirty, 2 ); // pass through the NET stuff 00499 00500 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMName ) != 0 ) 00501 fetchName(); 00502 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconName ) != 0 ) 00503 fetchIconicName(); 00504 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMStrut ) != 0 ) 00505 { 00506 if( isTopMenu()) // the fallback mode of KMenuBar may alter the strut 00507 checkWorkspacePosition(); // restore it 00508 workspace()->updateClientArea(); 00509 } 00510 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 ) 00511 getIcons(); 00512 // Note there's a difference between userTime() and info->userTime() 00513 // info->userTime() is the value of the property, userTime() also includes 00514 // updates of the time done by KWin (ButtonPress on windowrapper etc.). 00515 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2UserTime ) != 0 ) 00516 { 00517 workspace()->setWasUserInteraction(); 00518 updateUserTime( info->userTime()); 00519 } 00520 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 ) 00521 startupIdChanged(); 00522 } 00523 00524 // TODO move all focus handling stuff to separate file? 00525 switch (e->type) 00526 { 00527 case UnmapNotify: 00528 unmapNotifyEvent( &e->xunmap ); 00529 break; 00530 case DestroyNotify: 00531 destroyNotifyEvent( &e->xdestroywindow ); 00532 break; 00533 case MapRequest: 00534 // this one may pass the event to workspace 00535 return mapRequestEvent( &e->xmaprequest ); 00536 case ConfigureRequest: 00537 configureRequestEvent( &e->xconfigurerequest ); 00538 break; 00539 case PropertyNotify: 00540 propertyNotifyEvent( &e->xproperty ); 00541 break; 00542 case KeyPress: 00543 updateUserTime(); 00544 workspace()->setWasUserInteraction(); 00545 break; 00546 case ButtonPress: 00547 updateUserTime(); 00548 workspace()->setWasUserInteraction(); 00549 buttonPressEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state, 00550 e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root ); 00551 break;; 00552 case KeyRelease: 00553 // don't update user time on releases 00554 // e.g. if the user presses Alt+F2, the Alt release 00555 // would appear as user input to the currently active window 00556 break; 00557 case ButtonRelease: 00558 // don't update user time on releases 00559 // e.g. if the user presses Alt+F2, the Alt release 00560 // would appear as user input to the currently active window 00561 buttonReleaseEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state, 00562 e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root ); 00563 break; 00564 case MotionNotify: 00565 motionNotifyEvent( e->xmotion.window, e->xmotion.state, 00566 e->xmotion.x, e->xmotion.y, e->xmotion.x_root, e->xmotion.y_root ); 00567 break; 00568 case EnterNotify: 00569 enterNotifyEvent( &e->xcrossing ); 00570 // MotionNotify is guaranteed to be generated only if the mouse 00571 // move start and ends in the window; for cases when it only 00572 // starts or only ends there, Enter/LeaveNotify are generated. 00573 // Fake a MotionEvent in such cases to make handle of mouse 00574 // events simpler (Qt does that too). 00575 motionNotifyEvent( e->xcrossing.window, e->xcrossing.state, 00576 e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root ); 00577 break; 00578 case LeaveNotify: 00579 motionNotifyEvent( e->xcrossing.window, e->xcrossing.state, 00580 e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root ); 00581 leaveNotifyEvent( &e->xcrossing ); 00582 break; 00583 case FocusIn: 00584 focusInEvent( &e->xfocus ); 00585 break; 00586 case FocusOut: 00587 focusOutEvent( &e->xfocus ); 00588 break; 00589 case ReparentNotify: 00590 break; 00591 case ClientMessage: 00592 clientMessageEvent( &e->xclient ); 00593 break; 00594 case ColormapChangeMask: 00595 if( e->xany.window == window()) 00596 { 00597 cmap = e->xcolormap.colormap; 00598 if ( isActive() ) 00599 workspace()->updateColormap(); 00600 } 00601 break; 00602 case VisibilityNotify: 00603 visibilityNotifyEvent( &e->xvisibility ); 00604 break; 00605 default: 00606 if( e->xany.window == window()) 00607 { 00608 if( e->type == Shape::shapeEvent() ) 00609 { 00610 is_shape = Shape::hasShape( window()); // workaround for #19644 00611 updateShape(); 00612 } 00613 } 00614 break; 00615 } 00616 return true; // eat all events 00617 } 00618 00622 bool Client::mapRequestEvent( XMapRequestEvent* e ) 00623 { 00624 if( e->window != window()) 00625 { 00626 // Special support for the save-set feature, which is a bit broken. 00627 // If there's a window from one client embedded in another one, 00628 // e.g. using XEMBED, and the embedder suddenly looses its X connection, 00629 // save-set will reparent the embedded window to its closest ancestor 00630 // that will remains. Unfortunately, with reparenting window managers, 00631 // this is not the root window, but the frame (or in KWin's case, 00632 // it's the wrapper for the client window). In this case, 00633 // the wrapper will get ReparentNotify for a window it won't know, 00634 // which will be ignored, and then it gets MapRequest, as save-set 00635 // always maps. Returning true here means that Workspace::workspaceEvent() 00636 // will handle this MapRequest and manage this window (i.e. act as if 00637 // it was reparented to root window). 00638 if( e->parent == wrapperId()) 00639 return false; 00640 return true; // no messing with frame etc. 00641 } 00642 if( isTopMenu() && workspace()->managingTopMenus()) 00643 return true; // kwin controls these 00644 switch ( mappingState() ) 00645 { 00646 case WithdrawnState: 00647 assert( false ); // WMs are not supposed to manage clients in Withdrawn state, 00648 // manage(); // after initial mapping manage() is called from createClient() 00649 break; 00650 case IconicState: 00651 // also copied in clientMessage() 00652 if( isMinimized()) 00653 unminimize(); 00654 if( isShade()) 00655 setShade( ShadeNone ); 00656 if( !isOnCurrentDesktop()) 00657 { 00658 if( workspace()->allowClientActivation( this )) 00659 workspace()->activateClient( this ); 00660 else 00661 demandAttention(); 00662 } 00663 break; 00664 case NormalState: 00665 // TODO fake MapNotify? 00666 break; 00667 } 00668 return true; 00669 } 00670 00674 void Client::unmapNotifyEvent( XUnmapEvent* e ) 00675 { 00676 if( e->window != window()) 00677 return; 00678 if( e->event != wrapperId()) 00679 { // most probably event from root window when initially reparenting 00680 bool ignore = true; 00681 if( e->event == workspace()->rootWin() && e->send_event ) 00682 ignore = false; // XWithdrawWindow() 00683 if( ignore ) 00684 return; 00685 } 00686 switch( mappingState()) 00687 { 00688 case IconicState: 00689 releaseWindow(); 00690 return; 00691 case NormalState: 00692 // maybe we will be destroyed soon. Check this first. 00693 XEvent ev; 00694 if( XCheckTypedWindowEvent (qt_xdisplay(), window(), 00695 DestroyNotify, &ev) ) // TODO I don't like this much 00696 { 00697 destroyClient(); // deletes this 00698 return; 00699 } 00700 releaseWindow(); 00701 break; 00702 default: 00703 assert( false ); 00704 } 00705 } 00706 00707 void Client::destroyNotifyEvent( XDestroyWindowEvent* e ) 00708 { 00709 if( e->window != window()) 00710 return; 00711 destroyClient(); 00712 } 00713 00714 00715 bool blockAnimation = FALSE; 00716 00720 void Client::clientMessageEvent( XClientMessageEvent* e ) 00721 { 00722 if( e->window != window()) 00723 return; // ignore frame/wrapper 00724 // WM_STATE 00725 if ( e->message_type == atoms->kde_wm_change_state ) 00726 { 00727 if( isTopMenu() && workspace()->managingTopMenus()) 00728 return; // kwin controls these 00729 if( e->data.l[ 1 ] ) 00730 blockAnimation = true; 00731 if( e->data.l[ 0 ] == IconicState ) 00732 minimize(); 00733 else if( e->data.l[ 0 ] == NormalState ) 00734 { // copied from mapRequest() 00735 if( isMinimized()) 00736 unminimize(); 00737 if( isShade()) 00738 setShade( ShadeNone ); 00739 if( !isOnCurrentDesktop()) 00740 { 00741 if( workspace()->allowClientActivation( this )) 00742 workspace()->activateClient( this ); 00743 else 00744 demandAttention(); 00745 } 00746 } 00747 blockAnimation = false; 00748 } 00749 else if ( e->message_type == atoms->wm_change_state) 00750 { 00751 if( isTopMenu() && workspace()->managingTopMenus()) 00752 return; // kwin controls these 00753 if ( e->data.l[0] == IconicState ) 00754 minimize(); 00755 return; 00756 } 00757 } 00758 00759 00763 void Client::configureRequestEvent( XConfigureRequestEvent* e ) 00764 { 00765 if( e->window != window()) 00766 return; // ignore frame/wrapper 00767 if ( isResize() || isMove()) 00768 return; // we have better things to do right now 00769 00770 if( isFullScreen() // refuse resizing of fullscreen windows 00771 || isSplash() // no manipulations with splashscreens either 00772 || isTopMenu()) // topmenus neither 00773 { 00774 sendSyntheticConfigureNotify(); 00775 return; 00776 } 00777 00778 if ( e->value_mask & CWBorderWidth ) 00779 { 00780 // first, get rid of a window border 00781 XWindowChanges wc; 00782 unsigned int value_mask = 0; 00783 00784 wc.border_width = 0; 00785 value_mask = CWBorderWidth; 00786 XConfigureWindow( qt_xdisplay(), window(), value_mask, & wc ); 00787 } 00788 00789 if( e->value_mask & ( CWX | CWY | CWHeight | CWWidth )) 00790 configureRequest( e->value_mask, e->x, e->y, e->width, e->height ); 00791 00792 if ( e->value_mask & CWStackMode ) 00793 restackWindow( e->above, e->detail, NET::FromApplication ); 00794 00795 // TODO sending a synthetic configure notify always is fine, even in cases where 00796 // the ICCCM doesn't require this - it can be though of as 'the WM decided to move 00797 // the window later'. Perhaps those unnecessary ones could be saved though. 00798 // See also Client::setGeometry()/plainResize()/move(). 00799 sendSyntheticConfigureNotify(); 00800 00801 // SELI TODO accept configure requests for isDesktop windows (because kdesktop 00802 // may get XRANDR resize event before kwin), but check it's still at the bottom? 00803 } 00804 00805 00809 void Client::propertyNotifyEvent( XPropertyEvent* e ) 00810 { 00811 if( e->window != window()) 00812 return; // ignore frame/wrapper 00813 switch ( e->atom ) 00814 { 00815 case XA_WM_NORMAL_HINTS: 00816 getWmNormalHints(); 00817 break; 00818 case XA_WM_NAME: 00819 fetchName(); 00820 break; 00821 case XA_WM_ICON_NAME: 00822 fetchIconicName(); 00823 break; 00824 case XA_WM_TRANSIENT_FOR: 00825 readTransient(); 00826 break; 00827 case XA_WM_HINTS: 00828 getWMHints(); 00829 getIcons(); // because KWin::icon() uses WMHints as fallback 00830 break; 00831 default: 00832 if ( e->atom == atoms->wm_protocols ) 00833 getWindowProtocols(); 00834 else if (e->atom == atoms->wm_client_leader ) 00835 getWmClientLeader(); 00836 else if( e->atom == qt_window_role ) 00837 window_role = getStringProperty( window(), qt_window_role ); 00838 break; 00839 } 00840 } 00841 00842 00843 void Client::enterNotifyEvent( XCrossingEvent* e ) 00844 { 00845 if( e->window != frameId()) 00846 return; // care only about entering the whole frame 00847 if( e->mode == NotifyNormal || 00848 ( !options->focusPolicyIsReasonable() && 00849 e->mode == NotifyUngrab ) ) 00850 { 00851 00852 if (options->shadeHover && isShade()) 00853 { 00854 delete shadeHoverTimer; 00855 shadeHoverTimer = new QTimer( this ); 00856 connect( shadeHoverTimer, SIGNAL( timeout() ), this, SLOT( shadeHover() )); 00857 shadeHoverTimer->start( options->shadeHoverInterval, TRUE ); 00858 } 00859 00860 if ( options->focusPolicy == Options::ClickToFocus ) 00861 return; 00862 00863 if ( options->autoRaise && !isDesktop() && 00864 !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() && 00865 workspace()->topClientOnDesktop( workspace()->currentDesktop()) != this ) 00866 { 00867 delete autoRaiseTimer; 00868 autoRaiseTimer = new QTimer( this ); 00869 connect( autoRaiseTimer, SIGNAL( timeout() ), this, SLOT( autoRaise() ) ); 00870 autoRaiseTimer->start( options->autoRaiseInterval, TRUE ); 00871 } 00872 00873 if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isTopMenu() ) ) 00874 return; 00875 00876 workspace()->requestFocus( this ); 00877 return; 00878 } 00879 } 00880 00881 void Client::leaveNotifyEvent( XCrossingEvent* e ) 00882 { 00883 if( e->window != frameId()) 00884 return; // care only about leaving the whole frame 00885 if ( e->mode == NotifyNormal ) 00886 { 00887 if ( !buttonDown ) 00888 { 00889 mode = PositionCenter; 00890 setCursor( arrowCursor ); 00891 } 00892 bool lostMouse = !rect().contains( QPoint( e->x, e->y ) ); 00893 // 'lostMouse' wouldn't work with e.g. B2 or Keramik, which have non-rectangular decorations 00894 // (i.e. the LeaveNotify event comes before leaving the rect and no LeaveNotify event 00895 // comes after leaving the rect) - so lets check if the pointer is really outside the window 00896 00897 // TODO this still sucks if a window appears above this one - it should lose the mouse 00898 // if this window is another client, but not if it's a popup ... maybe after KDE3.1 :( 00899 // (repeat after me 'AARGHL!') 00900 if ( !lostMouse && e->detail != NotifyInferior ) 00901 { 00902 int d1, d2, d3, d4; 00903 unsigned int d5; 00904 Window w, child; 00905 if( XQueryPointer( qt_xdisplay(), frameId(), &w, &child, &d1, &d2, &d3, &d4, &d5 ) == False 00906 || child == None ) 00907 lostMouse = true; // really lost the mouse 00908 } 00909 if ( lostMouse ) 00910 { 00911 cancelAutoRaise(); 00912 delete shadeHoverTimer; 00913 shadeHoverTimer = 0; 00914 if ( shade_mode == ShadeHover && !moveResizeMode && !buttonDown ) 00915 setShade( ShadeNormal ); 00916 } 00917 if ( options->focusPolicy == Options::FocusStrictlyUnderMouse ) 00918 if ( isActive() && lostMouse ) 00919 workspace()->requestFocus( 0 ) ; 00920 return; 00921 } 00922 } 00923 00924 #define XCapL KKeyNative::modXLock() 00925 #define XNumL KKeyNative::modXNumLock() 00926 #define XScrL KKeyNative::modXScrollLock() 00927 void Client::grabButton( int modifier ) 00928 { 00929 unsigned int mods[ 8 ] = 00930 { 00931 0, XCapL, XNumL, XNumL | XCapL, 00932 XScrL, XScrL | XCapL, 00933 XScrL | XNumL, XScrL | XNumL | XCapL 00934 }; 00935 for( int i = 0; 00936 i < 8; 00937 ++i ) 00938 XGrabButton( qt_xdisplay(), AnyButton, 00939 modifier | mods[ i ], 00940 wrapperId(), FALSE, ButtonPressMask, 00941 GrabModeSync, GrabModeAsync, None, None ); 00942 } 00943 00944 void Client::ungrabButton( int modifier ) 00945 { 00946 unsigned int mods[ 8 ] = 00947 { 00948 0, XCapL, XNumL, XNumL | XCapL, 00949 XScrL, XScrL | XCapL, 00950 XScrL | XNumL, XScrL | XNumL | XCapL 00951 }; 00952 for( int i = 0; 00953 i < 8; 00954 ++i ) 00955 XUngrabButton( qt_xdisplay(), AnyButton, 00956 modifier | mods[ i ], wrapperId()); 00957 } 00958 #undef XCapL 00959 #undef XNumL 00960 #undef XScrL 00961 00962 /* 00963 Releases the passive grab for some modifier combinations when a 00964 window becomes active. This helps broken X programs that 00965 missinterpret LeaveNotify events in grab mode to work properly 00966 (Motif, AWT, Tk, ...) 00967 */ 00968 void Client::updateMouseGrab() 00969 { 00970 if( isActive() ) 00971 { 00972 // remove the grab for no modifiers only if the window 00973 // is unobscured or if the user doesn't want click raise 00974 if( !options->clickRaise || not_obscured ) 00975 ungrabButton( None ); 00976 else 00977 grabButton( None ); 00978 ungrabButton( ShiftMask ); 00979 ungrabButton( ControlMask ); 00980 ungrabButton( ControlMask | ShiftMask ); 00981 } 00982 else 00983 { 00984 XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, wrapperId()); 00985 // simply grab all modifier combinations 00986 XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE, 00987 ButtonPressMask, 00988 GrabModeSync, GrabModeAsync, 00989 None, None ); 00990 } 00991 } 00992 00993 int qtToX11Button( Qt::ButtonState button ) 00994 { 00995 if( button == Qt::LeftButton ) 00996 return Button1; 00997 else if( button == Qt::MidButton ) 00998 return Button2; 00999 else if( button == Qt::RightButton ) 01000 return Button3; 01001 return AnyButton; 01002 } 01003 01004 int qtToX11State( Qt::ButtonState state ) 01005 { 01006 int ret = 0; 01007 if( state & Qt::LeftButton ) 01008 ret |= Button1Mask; 01009 if( state & Qt::MidButton ) 01010 ret |= Button2Mask; 01011 if( state & Qt::RightButton ) 01012 ret |= Button3Mask; 01013 if( state & Qt::ShiftButton ) 01014 ret |= ShiftMask; 01015 if( state & Qt::ControlButton ) 01016 ret |= ControlMask; 01017 if( state & Qt::AltButton ) 01018 ret |= KKeyNative::modX(KKey::ALT); 01019 if( state & Qt::MetaButton ) 01020 ret |= KKeyNative::modX(KKey::WIN); 01021 return ret; 01022 } 01023 01024 // Qt propagates mouse events up the widget hierachy, which means events 01025 // for the decoration window cannot be (easily) intercepted as X11 events 01026 bool Client::eventFilter( QObject* o, QEvent* e ) 01027 { 01028 if( decoration == NULL 01029 || o != decoration->widget()) 01030 return false; 01031 if( e->type() == QEvent::MouseButtonPress ) 01032 { 01033 QMouseEvent* ev = static_cast< QMouseEvent* >( e ); 01034 return buttonPressEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()), 01035 ev->x(), ev->y(), ev->globalX(), ev->globalY() ); 01036 } 01037 if( e->type() == QEvent::MouseButtonRelease ) 01038 { 01039 QMouseEvent* ev = static_cast< QMouseEvent* >( e ); 01040 return buttonReleaseEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()), 01041 ev->x(), ev->y(), ev->globalX(), ev->globalY() ); 01042 } 01043 if( e->type() == QEvent::MouseMove ) // FRAME i fake z enter/leave? 01044 { 01045 QMouseEvent* ev = static_cast< QMouseEvent* >( e ); 01046 return motionNotifyEvent( decorationId(), qtToX11State( ev->state()), 01047 ev->x(), ev->y(), ev->globalX(), ev->globalY() ); 01048 } 01049 if( e->type() == QEvent::Resize ) 01050 { 01051 QResizeEvent* ev = static_cast< QResizeEvent* >( e ); 01052 // Filter out resize events that inform about size different than frame size. 01053 // This will ensure that decoration->width() etc. and decoration->widget()->width() will be in sync. 01054 // These events only seem to be delayed events from initial resizing before show() was called 01055 // on the decoration widget. 01056 if( ev->size() != size()) 01057 return true; 01058 } 01059 return false; 01060 } 01061 01062 // return value matters only when filtering events before decoration gets them 01063 bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root ) 01064 { 01065 if (buttonDown) 01066 { 01067 if( w == wrapperId()) 01068 XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time); 01069 return true; 01070 } 01071 01072 if( w == wrapperId() || w == frameId() || w == decorationId()) 01073 { // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace 01074 updateUserTime(); 01075 workspace()->setWasUserInteraction(); 01076 uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ? 01077 KKeyNative::modX(KKey::WIN) : 01078 KKeyNative::modX(KKey::ALT); 01079 bool bModKeyHeld = ( state & KKeyNative::accelModMaskX()) == keyModX; 01080 01081 if( isSplash() 01082 && button == Button1 && !bModKeyHeld ) 01083 { // hide splashwindow if the user clicks on it 01084 hideClient( true ); 01085 if( w == wrapperId()) 01086 XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time); 01087 return true; 01088 } 01089 01090 if ( isActive() && w == wrapperId() 01091 && ( options->clickRaise && !bModKeyHeld ) ) 01092 { 01093 if ( button < 4 ) // exclude wheel 01094 autoRaise(); 01095 } 01096 01097 Options::MouseCommand com = Options::MouseNothing; 01098 bool was_action = false; 01099 if ( bModKeyHeld ) 01100 { 01101 was_action = true; 01102 switch (button) 01103 { 01104 case Button1: 01105 com = options->commandAll1(); 01106 break; 01107 case Button2: 01108 com = options->commandAll2(); 01109 break; 01110 case Button3: 01111 com = options->commandAll3(); 01112 break; 01113 } 01114 } 01115 else 01116 { // inactive inner window 01117 if( !isActive() && w == wrapperId()) 01118 { 01119 was_action = true; 01120 switch (button) 01121 { 01122 case Button1: 01123 com = options->commandWindow1(); 01124 break; 01125 case Button2: 01126 com = options->commandWindow2(); 01127 break; 01128 case Button3: 01129 com = options->commandWindow3(); 01130 break; 01131 default: 01132 com = Options::MouseActivateAndPassClick; 01133 } 01134 } 01135 } 01136 if( was_action ) 01137 { 01138 bool replay = performMouseCommand( com, QPoint( x_root, y_root) ); 01139 01140 if ( isSpecialWindow() && !isOverride()) 01141 replay = TRUE; 01142 01143 if( w == wrapperId()) // these can come only from a grab 01144 XAllowEvents(qt_xdisplay(), replay? ReplayPointer : SyncPointer, CurrentTime ); //qt_x_time); 01145 return true; 01146 } 01147 } 01148 01149 if( w == wrapperId()) // these can come only from a grab 01150 { 01151 XAllowEvents(qt_xdisplay(), ReplayPointer, CurrentTime ); //qt_x_time); 01152 return true; 01153 } 01154 if( w == decorationId()) 01155 return false; // don't eat decoration events 01156 if( w == frameId()) 01157 processDecorationButtonPress( button, state, x, y, x_root, y_root ); 01158 return true; 01159 } 01160 01161 01162 // this function processes button press events only after decoration decides not to handle them, 01163 // unlike buttonPressEvent(), which (when the window is decoration) filters events before decoration gets them 01164 void Client::processDecorationButtonPress( int button, int /*state*/, int x, int y, int x_root, int y_root ) 01165 { 01166 Options::MouseCommand com = Options::MouseNothing; 01167 bool active = isActive(); 01168 if ( !wantsInput() ) // we cannot be active, use it anyway 01169 active = TRUE; 01170 01171 if ( button == Button1 ) 01172 com = active ? options->commandActiveTitlebar1() : options->commandInactiveTitlebar1(); 01173 else if ( button == Button2 ) 01174 com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2(); 01175 else if ( button == Button3 ) 01176 com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3(); 01177 if( com != Options::MouseOperationsMenu // actions where it's not possible to get the matching 01178 && com != Options::MouseMinimize ) // mouse release event 01179 { 01180 // FRAME mouseMoveEvent( e ); shouldn't be necessary 01181 buttonDown = TRUE; 01182 moveOffset = QPoint( x, y ); 01183 invertedMoveOffset = rect().bottomRight() - moveOffset; 01184 unrestrictedMoveResize = false; 01185 setCursor( mode ); // update to sizeAllCursor if about to move 01186 } 01187 performMouseCommand( com, QPoint( x_root, y_root )); 01188 } 01189 01190 // called from decoration 01191 void Client::processMousePressEvent( QMouseEvent* e ) 01192 { 01193 if( e->type() != QEvent::MouseButtonPress ) 01194 { 01195 kdWarning() << "processMousePressEvent()" << endl; 01196 return; 01197 } 01198 int button; 01199 switch( e->button()) 01200 { 01201 case LeftButton: 01202 button = Button1; 01203 break; 01204 case MidButton: 01205 button = Button2; 01206 break; 01207 case RightButton: 01208 button = Button3; 01209 break; 01210 default: 01211 return; 01212 } 01213 processDecorationButtonPress( button, e->state(), e->x(), e->y(), e->globalX(), e->globalY()); 01214 } 01215 01216 // return value matters only when filtering events before decoration gets them 01217 bool Client::buttonReleaseEvent( Window w, int /*button*/, int state, int x, int y, int x_root, int y_root ) 01218 { 01219 if( w == decorationId() && !buttonDown) 01220 return false; 01221 if( w == wrapperId()) 01222 { 01223 XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime ); //qt_x_time); 01224 return true; 01225 } 01226 if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow()) 01227 return true; 01228 x = this->x(); // translate from grab window to local coords 01229 y = this->y(); 01230 if ( (state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 ) 01231 { 01232 buttonDown = FALSE; 01233 if ( moveResizeMode ) 01234 { 01235 finishMoveResize( false ); 01236 // mouse position is still relative to old Client position, adjust it 01237 QPoint mousepos( x_root - x, y_root - y ); 01238 mode = mousePosition( mousepos ); 01239 } 01240 setCursor( mode ); 01241 } 01242 return true; 01243 } 01244 01245 static bool was_motion = false; 01246 static Time next_motion_time = CurrentTime; 01247 // Check whole incoming X queue for MotionNotify events 01248 // checking whole queue is done by always returning False in the predicate. 01249 // If there are more MotionNotify events in the queue, all until the last 01250 // one may be safely discarded (if a ButtonRelease event comes, a MotionNotify 01251 // will be faked from it, so there's no need to check other events). 01252 // This helps avoiding being overloaded by being flooded from many events 01253 // from the XServer. 01254 static Bool motion_predicate( Display*, XEvent* ev, XPointer ) 01255 { 01256 if( ev->type == MotionNotify ) 01257 { 01258 was_motion = true; 01259 next_motion_time = ev->xmotion.time; // for setting time 01260 } 01261 return False; 01262 } 01263 01264 static bool waitingMotionEvent() 01265 { 01266 // The queue doesn't need to be checked until the X timestamp 01267 // of processes events reaches the timestamp of the last suitable 01268 // MotionNotify event in the queue. 01269 if( next_motion_time != CurrentTime 01270 && timestampCompare( qt_x_time, next_motion_time ) < 0 ) 01271 return true; 01272 was_motion = false; 01273 XSync( qt_xdisplay(), False ); // this helps to discard more MotionNotify events 01274 XEvent dummy; 01275 XCheckIfEvent( qt_xdisplay(), &dummy, motion_predicate, NULL ); 01276 return was_motion; 01277 } 01278 01279 // return value matters only when filtering events before decoration gets them 01280 bool Client::motionNotifyEvent( Window w, int /*state*/, int x, int y, int x_root, int y_root ) 01281 { 01282 if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow()) 01283 return true; // care only about the whole frame 01284 if ( !buttonDown ) 01285 { 01286 Position newmode = mousePosition( QPoint( x, y )); 01287 if( newmode != mode ) 01288 setCursor( newmode ); 01289 mode = newmode; 01290 return false; 01291 } 01292 if( w == moveResizeGrabWindow()) 01293 { 01294 x = this->x(); // translate from grab window to local coords 01295 y = this->y(); 01296 } 01297 if( !waitingMotionEvent()) 01298 handleMoveResize( x, y, x_root, y_root ); 01299 return true; 01300 } 01301 01302 void Client::focusInEvent( XFocusInEvent* e ) 01303 { 01304 if( e->window != window()) 01305 return; // only window gets focus 01306 if ( e->mode == NotifyUngrab ) 01307 return; // we don't care 01308 if ( e->detail == NotifyPointer ) 01309 return; // we don't care 01310 if( !isShown( false ) || !isOnCurrentDesktop()) // we unmapped it, but it got focus meanwhile -> 01311 return; // activateNextClient() already transferred focus elsewhere 01312 // check if this client is in should_get_focus list or if activation is allowed 01313 bool activate = workspace()->allowClientActivation( this, -1U, true ); 01314 workspace()->gotFocusIn( this ); // remove from should_get_focus list 01315 if( activate ) 01316 setActive( TRUE ); 01317 else 01318 { 01319 workspace()->restoreFocus(); 01320 demandAttention(); 01321 } 01322 } 01323 01324 // When a client loses focus, FocusOut events are usually immediatelly 01325 // followed by FocusIn events for another client that gains the focus 01326 // (unless the focus goes to another screen, or to the nofocus widget). 01327 // Without this check, the former focused client would have to be 01328 // deactivated, and after that, the new one would be activated, with 01329 // a short time when there would be no active client. This can cause 01330 // flicker sometimes, e.g. when a fullscreen is shown, and focus is transferred 01331 // from it to its transient, the fullscreen would be kept in the Active layer 01332 // at the beginning and at the end, but not in the middle, when the active 01333 // client would be temporarily none (see Client::belongToLayer() ). 01334 // Therefore, the events queue is checked, whether it contains the matching 01335 // FocusIn event, and if yes, deactivation of the previous client will 01336 // be skipped, as activation of the new one will automatically deactivate 01337 // previously active client. 01338 static bool follows_focusin = false; 01339 static bool follows_focusin_failed = false; 01340 static Bool predicate_follows_focusin( Display*, XEvent* e, XPointer arg ) 01341 { 01342 if( follows_focusin || follows_focusin_failed ) 01343 return False; 01344 Client* c = ( Client* ) arg; 01345 if( e->type == FocusIn && c->workspace()->findClient( WindowMatchPredicate( e->xfocus.window ))) 01346 { // found FocusIn 01347 follows_focusin = true; 01348 return False; 01349 } 01350 // events that may be in the queue before the FocusIn event that's being 01351 // searched for 01352 if( e->type == FocusIn || e->type == FocusOut || e->type == KeymapNotify ) 01353 return False; 01354 follows_focusin_failed = true; // a different event - stop search 01355 return False; 01356 } 01357 01358 static bool check_follows_focusin( Client* c ) 01359 { 01360 follows_focusin = follows_focusin_failed = false; 01361 XEvent dummy; 01362 // XCheckIfEvent() is used to make the search non-blocking, the predicate 01363 // always returns False, so nothing is removed from the events queue. 01364 // XPeekIfEvent() would block. 01365 XCheckIfEvent( qt_xdisplay(), &dummy, predicate_follows_focusin, (XPointer)c ); 01366 return follows_focusin; 01367 } 01368 01369 01370 void Client::focusOutEvent( XFocusOutEvent* e ) 01371 { 01372 if( e->window != window()) 01373 return; // only window gets focus 01374 if ( e->mode == NotifyGrab ) 01375 return; // we don't care 01376 if ( isShade() ) 01377 return; // here neither 01378 if ( e->detail != NotifyNonlinear 01379 && e->detail != NotifyNonlinearVirtual ) 01380 // SELI check all this 01381 return; // hack for motif apps like netscape 01382 if ( QApplication::activePopupWidget() ) 01383 return; 01384 if( !check_follows_focusin( this )) 01385 setActive( FALSE ); 01386 } 01387 01388 void Client::visibilityNotifyEvent( XVisibilityEvent * e) 01389 { 01390 if( e->window != frameId()) 01391 return; // care only about the whole frame 01392 bool new_not_obscured = e->state == VisibilityUnobscured; 01393 if( not_obscured == new_not_obscured ) 01394 return; 01395 not_obscured = new_not_obscured; 01396 updateMouseGrab(); 01397 } 01398 01399 // performs _NET_WM_MOVERESIZE 01400 void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction ) 01401 { 01402 if( direction == NET::Move ) 01403 performMouseCommand( Options::MouseMove, QPoint( x_root, y_root )); 01404 else if( direction >= NET::TopLeft && direction <= NET::Left ) 01405 { 01406 static const Position convert[] = 01407 { 01408 PositionTopLeft, 01409 PositionTop, 01410 PositionTopRight, 01411 PositionRight, 01412 PositionBottomRight, 01413 PositionBottom, 01414 PositionBottomLeft, 01415 PositionLeft 01416 }; 01417 if(!isResizable() || isShade()) 01418 return; 01419 if( moveResizeMode ) 01420 finishMoveResize( false ); 01421 buttonDown = TRUE; 01422 moveOffset = QPoint( x_root - x(), y_root - y()); // map from global 01423 invertedMoveOffset = rect().bottomRight() - moveOffset; 01424 unrestrictedMoveResize = false; 01425 mode = convert[ direction ]; 01426 setCursor( mode ); 01427 if( !startMoveResize()) 01428 { 01429 buttonDown = false; 01430 setCursor( mode ); 01431 } 01432 } 01433 else if( direction == NET::KeyboardMove ) 01434 { // ignore mouse coordinates given in the message, mouse position is used by the moving algorithm 01435 QCursor::setPos( geometry().center() ); 01436 performMouseCommand( Options::MouseUnrestrictedMove, geometry().center()); 01437 } 01438 else if( direction == NET::KeyboardSize ) 01439 { // ignore mouse coordinates given in the message, mouse position is used by the resizing algorithm 01440 QCursor::setPos( geometry().bottomRight()); 01441 performMouseCommand( Options::MouseUnrestrictedResize, geometry().bottomRight()); 01442 } 01443 } 01444 01445 void Client::keyPressEvent( uint key_code ) 01446 { 01447 updateUserTime(); 01448 if ( !isMove() && !isResize() ) 01449 return; 01450 bool is_control = key_code & Qt::CTRL; 01451 bool is_alt = key_code & Qt::ALT; 01452 key_code = key_code & 0xffff; 01453 int delta = is_control?1:is_alt?32:8; 01454 QPoint pos = QCursor::pos(); 01455 switch ( key_code ) 01456 { 01457 case Key_Left: 01458 pos.rx() -= delta; 01459 break; 01460 case Key_Right: 01461 pos.rx() += delta; 01462 break; 01463 case Key_Up: 01464 pos.ry() -= delta; 01465 break; 01466 case Key_Down: 01467 pos.ry() += delta; 01468 break; 01469 case Key_Space: 01470 case Key_Return: 01471 case Key_Enter: 01472 finishMoveResize( false ); 01473 buttonDown = FALSE; 01474 setCursor( mode ); 01475 break; 01476 case Key_Escape: 01477 finishMoveResize( true ); 01478 buttonDown = FALSE; 01479 setCursor( mode ); 01480 break; 01481 default: 01482 return; 01483 } 01484 QCursor::setPos( pos ); 01485 } 01486 01487 // **************************************** 01488 // Group 01489 // **************************************** 01490 01491 bool Group::groupEvent( XEvent* e ) 01492 { 01493 unsigned long dirty[ 2 ]; 01494 leader_info->event( e, dirty, 2 ); // pass through the NET stuff 01495 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 ) 01496 getIcons(); 01497 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 ) 01498 startupIdChanged(); 01499 return false; 01500 } 01501 01502 01503 } // namespace
KDE Logo
This file is part of the documentation for kwin Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Dec 16 19:08:40 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003