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