activation.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 window activation and focus 00015 stealing prevention. 00016 00017 */ 00018 00019 #include <tqpopupmenu.h> 00020 #include <kxerrorhandler.h> 00021 #include <tdestartupinfo.h> 00022 #include <kstringhandler.h> 00023 #include <tdelocale.h> 00024 00025 #include "client.h" 00026 #include "workspace.h" 00027 #include <fixx11h.h> 00028 00029 #include "notifications.h" 00030 #include "atoms.h" 00031 #include "group.h" 00032 #include "rules.h" 00033 00034 namespace KWinInternal 00035 { 00036 00037 /* 00038 Prevention of focus stealing: 00039 00040 KWin tries to prevent unwanted changes of focus, that would result 00041 from mapping a new window. Also, some nasty applications may try 00042 to force focus change even in cases when ICCCM 4.2.7 doesn't allow it 00043 (e.g. they may try to activate their main window because the user 00044 definitely "needs" to see something happened - misusing 00045 of TQWidget::setActiveWindow() may be such case). 00046 00047 There are 4 ways how a window may become active: 00048 - the user changes the active window (e.g. focus follows mouse, clicking 00049 on some window's titlebar) - the change of focus will 00050 be done by KWin, so there's nothing to solve in this case 00051 - the change of active window will be requested using the _NET_ACTIVE_WINDOW 00052 message (handled in RootInfo::changeActiveWindow()) - such requests 00053 will be obeyed, because this request is meant mainly for e.g. taskbar 00054 asking the WM to change the active window as a result of some user action. 00055 Normal applications should use this request only rarely in special cases. 00056 See also below the discussion of _NET_ACTIVE_WINDOW_TRANSFER. 00057 - the change of active window will be done by performing XSetInputFocus() 00058 on a window that's not currently active. ICCCM 4.2.7 describes when 00059 the application may perform change of input focus. In order to handle 00060 misbehaving applications, KWin will try to detect focus changes to 00061 windows that don't belong to currently active application, and restore 00062 focus back to the currently active window, instead of activating the window 00063 that got focus (unfortunately there's no way to FocusChangeRedirect similar 00064 to e.g. SubstructureRedirect, so there will be short time when the focus 00065 will be changed). The check itself that's done is 00066 Workspace::allowClientActivation() (see below). 00067 - a new window will be mapped - this is the most complicated case. If 00068 the new window belongs to the currently active application, it may be safely 00069 mapped on top and activated. The same if there's no active window, 00070 or the active window is the desktop. These checks are done by 00071 Workspace::allowClientActivation(). 00072 Following checks need to compare times. One time is the timestamp 00073 of last user action in the currently active window, the other time is 00074 the timestamp of the action that originally caused mapping of the new window 00075 (e.g. when the application was started). If the first time is newer than 00076 the second one, the window will not be activated, as that indicates 00077 futher user actions took place after the action leading to this new 00078 mapped window. This check is done by Workspace::allowClientActivation(). 00079 There are several ways how to get the timestamp of action that caused 00080 the new mapped window (done in Client::readUserTimeMapTimestamp()) : 00081 - the window may have the _NET_WM_USER_TIME property. This way 00082 the application may either explicitly request that the window is not 00083 activated (by using 0 timestamp), or the property contains the time 00084 of last user action in the application. 00085 - KWin itself tries to detect time of last user action in every window, 00086 by watching KeyPress and ButtonPress events on windows. This way some 00087 events may be missed (if they don't propagate to the toplevel window), 00088 but it's good as a fallback for applications that don't provide 00089 _NET_WM_USER_TIME, and missing some events may at most lead 00090 to unwanted focus stealing. 00091 - the timestamp may come from application startup notification. 00092 Application startup notification, if it exists for the new mapped window, 00093 should include time of the user action that caused it. 00094 - if there's no timestamp available, it's checked whether the new window 00095 belongs to some already running application - if yes, the timestamp 00096 will be 0 (i.e. refuse activation) 00097 - if the window is from session restored window, the timestamp will 00098 be 0 too, unless this application was the active one at the time 00099 when the session was saved, in which case the window will be 00100 activated if there wasn't any user interaction since the time 00101 KWin was started. 00102 - as the last resort, the _KDE_NET_USER_CREATION_TIME timestamp 00103 is used. For every toplevel window that is created (see CreateNotify 00104 handling), this property is set to the at that time current time. 00105 Since at this time it's known that the new window doesn't belong 00106 to any existing application (better said, the application doesn't 00107 have any other window mapped), it is either the very first window 00108 of the application, or its the only window of the application 00109 that was hidden before. The latter case is handled by removing 00110 the property from windows before withdrawing them, making 00111 the timestamp empty for next mapping of the window. In the sooner 00112 case, the timestamp will be used. This helps in case when 00113 an application is launched without application startup notification, 00114 it creates its mainwindow, and starts its initialization (that 00115 may possibly take long time). The timestamp used will be older 00116 than any user action done after launching this application. 00117 - if no timestamp is found at all, the window is activated. 00118 The check whether two windows belong to the same application (same 00119 process) is done in Client::belongToSameApplication(). Not 100% reliable, 00120 but hopefully 99,99% reliable. 00121 00122 As a somewhat special case, window activation is always enabled when 00123 session saving is in progress. When session saving, the session 00124 manager allows only one application to interact with the user. 00125 Not allowing window activation in such case would result in e.g. dialogs 00126 not becoming active, so focus stealing prevention would cause here 00127 more harm than good. 00128 00129 Windows that attempted to become active but KWin prevented this will 00130 be marked as demanding user attention. They'll get 00131 the _NET_WM_STATE_DEMANDS_ATTENTION state, and the taskbar should mark 00132 them specially (blink, etc.). The state will be reset when the window 00133 eventually really becomes active. 00134 00135 There are one more ways how a window can become obstrusive, window stealing 00136 focus: By showing above the active window, by either raising itself, 00137 or by moving itself on the active desktop. 00138 - KWin will refuse raising non-active window above the active one, 00139 unless they belong to the same application. Applications shouldn't 00140 raise their windows anyway (unless the app wants to raise one 00141 of its windows above another of its windows). 00142 - KWin activates windows moved to the current desktop (as that seems 00143 logical from the user's point of view, after sending the window 00144 there directly from KWin, or e.g. using pager). This means 00145 applications shouldn't send their windows to another desktop 00146 (SELI TODO - but what if they do?) 00147 00148 Special cases I can think of: 00149 - konqueror reusing, i.e. kfmclient tells running Konqueror instance 00150 to open new window 00151 - without focus stealing prevention - no problem 00152 - with ASN (application startup notification) - ASN is forwarded, 00153 and because it's newer than the instance's user timestamp, 00154 it takes precedence 00155 - without ASN - user timestamp needs to be reset, otherwise it would 00156 be used, and it's old; moreover this new window mustn't be detected 00157 as window belonging to already running application, or it wouldn't 00158 be activated - see Client::sameAppWindowRoleMatch() for the (rather ugly) 00159 hack 00160 - konqueror preloading, i.e. window is created in advance, and kfmclient 00161 tells this Konqueror instance to show it later 00162 - without focus stealing prevention - no problem 00163 - with ASN - ASN is forwarded, and because it's newer than the instance's 00164 user timestamp, it takes precedence 00165 - without ASN - user timestamp needs to be reset, otherwise it would 00166 be used, and it's old; also, creation timestamp is changed to 00167 the time the instance starts (re-)initializing the window, 00168 this ensures creation timestamp will still work somewhat even in this case 00169 - KUniqueApplication - when the window is already visible, and the new instance 00170 wants it to activate 00171 - without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem 00172 - with ASN - ASN is forwarded, and set on the already visible window, KWin 00173 treats the window as new with that ASN 00174 - without ASN - _NET_ACTIVE_WINDOW as application request is used, 00175 and there's no really usable timestamp, only timestamp 00176 from the time the (new) application instance was started, 00177 so KWin will activate the window *sigh* 00178 - the bad thing here is that there's absolutely no chance to recognize 00179 the case of starting this KUniqueApp from Konsole (and thus wanting 00180 the already visible window to become active) from the case 00181 when something started this KUniqueApp without ASN (in which case 00182 the already visible window shouldn't become active) 00183 - the only solution is using ASN for starting applications, at least silent 00184 (i.e. without feedback) 00185 - when one application wants to activate another application's window (e.g. KMail 00186 activating already running KAddressBook window ?) 00187 - without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem 00188 - with ASN - can't be here, it's the KUniqueApp case then 00189 - without ASN - _NET_ACTIVE_WINDOW as application request should be used, 00190 KWin will activate the new window depending on the timestamp and 00191 whether it belongs to the currently active application 00192 00193 _NET_ACTIVE_WINDOW usage: 00194 data.l[0]= 1 ->app request 00195 = 2 ->pager request 00196 = 0 - backwards compatibility 00197 data.l[1]= timestamp 00198 */ 00199 00200 00201 //**************************************** 00202 // Workspace 00203 //**************************************** 00204 00205 00214 void Workspace::setActiveClient( Client* c, allowed_t ) 00215 { 00216 if ( active_client == c ) 00217 return; 00218 if( active_popup && active_popup_client != c && set_active_client_recursion == 0 ) 00219 closeActivePopup(); 00220 StackingUpdatesBlocker blocker( this ); 00221 ++set_active_client_recursion; 00222 updateFocusMousePosition( TQCursor::pos()); 00223 if( active_client != NULL ) 00224 { // note that this may call setActiveClient( NULL ), therefore the recursion counter 00225 active_client->setActive( false, !c || !c->isModal() || c != active_client->transientFor() ); 00226 } 00227 active_client = c; 00228 if (set_active_client_recursion == 1) 00229 { 00230 // Only unset next_active_client if activateClient() wasn't called by 00231 // Client::setActive() to set the active window to null before 00232 // activating another window. 00233 next_active_client = NULL; 00234 } 00235 Q_ASSERT( c == NULL || c->isActive()); 00236 if( active_client != NULL ) 00237 last_active_client = active_client; 00238 if ( active_client ) 00239 { 00240 updateFocusChains( active_client, FocusChainMakeFirst ); 00241 active_client->demandAttention( false ); 00242 } 00243 pending_take_activity = NULL; 00244 00245 updateCurrentTopMenu(); 00246 updateToolWindows( false ); 00247 if( c ) 00248 disableGlobalShortcutsForClient( c->rules()->checkDisableGlobalShortcuts( false )); 00249 else 00250 disableGlobalShortcutsForClient( false ); 00251 00252 updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active 00253 00254 rootInfo->setActiveWindow( active_client? active_client->window() : 0 ); 00255 updateColormap(); 00256 --set_active_client_recursion; 00257 } 00258 00270 void Workspace::activateClient( Client* c, bool force ) 00271 { 00272 if( c == NULL ) 00273 { 00274 focusToNull(); 00275 setActiveClient( NULL, Allowed ); 00276 return; 00277 } 00278 raiseClient( c ); 00279 if (!c->isOnDesktop(currentDesktop()) ) 00280 { 00281 ++block_focus; 00282 setCurrentDesktop( c->desktop() ); 00283 --block_focus; 00284 } 00285 if( c->isMinimized()) 00286 c->unminimize(); 00287 00288 // TODO force should perhaps allow this only if the window already contains the mouse 00289 if( options->focusPolicyIsReasonable() || force ) 00290 requestFocus( c, force ); 00291 00292 // Don't update user time for clients that have focus stealing workaround. 00293 // As they usually belong to the current active window but fail to provide 00294 // this information, updating their user time would make the user time 00295 // of the currently active window old, and reject further activation for it. 00296 // E.g. typing URL in minicli which will show tdeio_uiserver dialog (with workaround), 00297 // and then kdesktop shows dialog about SSL certificate. 00298 // This needs also avoiding user creation time in Client::readUserTimeMapTimestamp(). 00299 if( !c->ignoreFocusStealing()) 00300 c->updateUserTime(); 00301 } 00302 00310 void Workspace::requestFocus( Client* c, bool force ) 00311 { 00312 takeActivity( c, ActivityFocus | ( force ? ActivityFocusForce : 0 ), false); 00313 } 00314 00315 void Workspace::takeActivity( Client* c, int flags, bool handled ) 00316 { 00317 // the 'if( c == active_client ) return;' optimization must not be done here 00318 if (!focusChangeEnabled() && ( c != active_client) ) 00319 flags &= ~ActivityFocus; 00320 00321 if ( !c ) 00322 { 00323 focusToNull(); 00324 return; 00325 } 00326 00327 if( flags & ActivityFocus ) 00328 { 00329 Client* modal = c->findModal(); 00330 if( modal != NULL && modal != c ) 00331 { 00332 next_active_client = modal; 00333 if( !modal->isOnDesktop( c->desktop())) 00334 { 00335 modal->setDesktop( c->desktop()); 00336 if( modal->desktop() != c->desktop()) // forced desktop 00337 activateClient( modal ); 00338 } 00339 // if the click was inside the window (i.e. handled is set), 00340 // but it has a modal, there's no need to use handled mode, because 00341 // the modal doesn't get the click anyway 00342 // raising of the original window needs to be still done 00343 if( flags & ActivityRaise ) 00344 raiseClient( c ); 00345 c = modal; 00346 handled = false; 00347 } 00348 cancelDelayFocus(); 00349 } 00350 if ( !( flags & ActivityFocusForce ) && ( c->isTopMenu() || c->isDock() || c->isSplash()) ) 00351 flags &= ~ActivityFocus; // toplevel menus and dock windows don't take focus if not forced 00352 if( c->isShade()) 00353 { 00354 if( c->wantsInput() && ( flags & ActivityFocus )) 00355 { 00356 // client cannot accept focus, but at least the window should be active (window menu, et. al. ) 00357 c->setActive( true ); 00358 focusToNull(); 00359 } 00360 if( c->wantsInput()) 00361 next_active_client = c; 00362 flags &= ~ActivityFocus; 00363 handled = false; // no point, can't get clicks 00364 } 00365 if( !c->isShown( true )) // shouldn't happen, call activateClient() if needed 00366 { 00367 next_active_client = c; 00368 kdWarning( 1212 ) << "takeActivity: not shown" << endl; 00369 return; 00370 } 00371 c->takeActivity( flags, handled, Allowed ); 00372 if( !c->isOnScreen( active_screen )) 00373 active_screen = c->screen(); 00374 } 00375 00376 void Workspace::handleTakeActivity( Client* c, Time /*timestamp*/, int flags ) 00377 { 00378 if( pending_take_activity != c ) // pending_take_activity is reset when doing restack or activation 00379 return; 00380 if(( flags & ActivityRaise ) != 0 ) 00381 raiseClient( c ); 00382 if(( flags & ActivityFocus ) != 0 && c->isShown( false )) 00383 c->takeFocus( Allowed ); 00384 pending_take_activity = NULL; 00385 } 00386 00394 void Workspace::clientHidden( Client* c ) 00395 { 00396 assert( !c->isShown( true ) || !c->isOnCurrentDesktop()); 00397 activateNextClient( c ); 00398 } 00399 00400 // deactivates 'c' and activates next client 00401 bool Workspace::activateNextClient( Client* c ) 00402 { 00403 // if 'c' is not the active or the to-become active one, do nothing 00404 if( !( c == active_client 00405 || ( should_get_focus.count() > 0 && c == should_get_focus.last()))) 00406 return false; 00407 closeActivePopup(); 00408 if( c != NULL ) 00409 { 00410 if( c == active_client ) 00411 { 00412 setActiveClient( NULL, Allowed ); 00413 } 00414 should_get_focus.remove( c ); 00415 } 00416 if( focusChangeEnabled()) 00417 { 00418 if ( options->focusPolicyIsReasonable()) 00419 { // search the focus_chain for a client to transfer focus to 00420 // if 'c' is transient, transfer focus to the first suitable mainwindow 00421 Client* get_focus = NULL; 00422 const ClientList mainwindows = ( c != NULL ? c->mainClients() : ClientList()); 00423 for( ClientList::ConstIterator it = focus_chain[currentDesktop()].fromLast(); 00424 it != focus_chain[currentDesktop()].end(); 00425 --it ) 00426 { 00427 if( !(*it)->isShown( false ) || !(*it)->isOnCurrentDesktop()) 00428 continue; 00429 if( options->separateScreenFocus ) 00430 { 00431 if( c != NULL && !(*it)->isOnScreen( c->screen())) 00432 continue; 00433 if( c == NULL && !(*it)->isOnScreen( activeScreen())) 00434 continue; 00435 } 00436 if( mainwindows.contains( *it )) 00437 { 00438 get_focus = *it; 00439 break; 00440 } 00441 if( get_focus == NULL ) 00442 get_focus = *it; 00443 } 00444 if( get_focus == NULL ) 00445 get_focus = findDesktop( true, currentDesktop()); 00446 if( get_focus != NULL ) 00447 { 00448 requestFocus( get_focus ); 00449 } 00450 else 00451 focusToNull(); 00452 } 00453 else 00454 return false; 00455 } 00456 else 00457 // if blocking focus, move focus to the desktop later if needed 00458 // in order to avoid flickering 00459 focusToNull(); 00460 return true; 00461 } 00462 00463 void Workspace::setCurrentScreen( int new_screen ) 00464 { 00465 if (new_screen < 0 || new_screen > numScreens()) 00466 return; 00467 if ( !options->focusPolicyIsReasonable()) 00468 return; 00469 closeActivePopup(); 00470 Client* get_focus = NULL; 00471 for( ClientList::ConstIterator it = focus_chain[currentDesktop()].fromLast(); 00472 it != focus_chain[currentDesktop()].end(); 00473 --it ) 00474 { 00475 if( !(*it)->isShown( false ) || !(*it)->isOnCurrentDesktop()) 00476 continue; 00477 if( !(*it)->screen() == new_screen ) 00478 continue; 00479 get_focus = *it; 00480 break; 00481 } 00482 if( get_focus == NULL ) 00483 get_focus = findDesktop( true, currentDesktop()); 00484 if( get_focus != NULL && get_focus != mostRecentlyActivatedClient()) 00485 requestFocus( get_focus ); 00486 active_screen = new_screen; 00487 } 00488 00489 void Workspace::gotFocusIn( const Client* c ) 00490 { 00491 if( should_get_focus.contains( const_cast< Client* >( c ))) 00492 { // remove also all sooner elements that should have got FocusIn, 00493 // but didn't for some reason (and also won't anymore, because they were sooner) 00494 while( should_get_focus.first() != c ) 00495 should_get_focus.pop_front(); 00496 should_get_focus.pop_front(); // remove 'c' 00497 } 00498 } 00499 00500 void Workspace::setShouldGetFocus( Client* c ) 00501 { 00502 should_get_focus.append( c ); 00503 updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active 00504 } 00505 00506 // focus_in -> the window got FocusIn event 00507 // session_active -> the window was active when saving session 00508 bool Workspace::allowClientActivation( const Client* c, Time time, bool focus_in ) 00509 { 00510 // options->focusStealingPreventionLevel : 00511 // 0 - none - old KWin behaviour, new windows always get focus 00512 // 1 - low - focus stealing prevention is applied normally, when unsure, activation is allowed 00513 // 2 - normal - focus stealing prevention is applied normally, when unsure, activation is not allowed, 00514 // this is the default 00515 // 3 - high - new window gets focus only if it belongs to the active application, 00516 // or when no window is currently active 00517 // 4 - extreme - no window gets focus without user intervention 00518 if( time == -1U ) 00519 time = c->userTime(); 00520 int level = c->rules()->checkFSP( options->focusStealingPreventionLevel ); 00521 if( session_saving && level <= 2 ) // <= normal 00522 { 00523 return true; 00524 } 00525 Client* ac = mostRecentlyActivatedClient(); 00526 if( focus_in ) 00527 { 00528 if( should_get_focus.contains( const_cast< Client* >( c ))) 00529 return true; // FocusIn was result of KWin's action 00530 // Before getting FocusIn, the active Client already 00531 // got FocusOut, and therefore got deactivated. 00532 ac = last_active_client; 00533 } 00534 if( time == 0 ) // explicitly asked not to get focus 00535 return false; 00536 if( level == 0 ) // none 00537 return true; 00538 if( level == 4 ) // extreme 00539 return false; 00540 if( !c->isOnCurrentDesktop()) 00541 return false; // allow only with level == 0 00542 if( c->ignoreFocusStealing()) 00543 return true; 00544 if( ac == NULL || ac->isDesktop()) 00545 { 00546 // kdDebug( 1212 ) << "Activation: No client active, allowing" << endl; 00547 return true; // no active client -> always allow 00548 } 00549 // TODO window urgency -> return true? 00550 if( Client::belongToSameApplication( c, ac, true )) 00551 { 00552 // kdDebug( 1212 ) << "Activation: Belongs to active application" << endl; 00553 return true; 00554 } 00555 if( level == 3 ) // high 00556 return false; 00557 if( time == -1U ) // no time known 00558 { 00559 // kdDebug( 1212 ) << "Activation: No timestamp at all" << endl; 00560 if( level == 1 ) // low 00561 return true; 00562 // no timestamp at all, don't activate - because there's also creation timestamp 00563 // done on CreateNotify, this case should happen only in case application 00564 // maps again already used window, i.e. this won't happen after app startup 00565 return false; 00566 } 00567 // level == 2 // normal 00568 Time user_time = ac->userTime(); 00569 // kdDebug( 1212 ) << "Activation, compared:" << c << ":" << time << ":" << user_time 00570 // << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl; 00571 return timestampCompare( time, user_time ) >= 0; // time >= user_time 00572 } 00573 00574 // basically the same like allowClientActivation(), this time allowing 00575 // a window to be fully raised upon its own request (XRaiseWindow), 00576 // if refused, it will be raised only on top of windows belonging 00577 // to the same application 00578 bool Workspace::allowFullClientRaising( const Client* c, Time time ) 00579 { 00580 int level = c->rules()->checkFSP( options->focusStealingPreventionLevel ); 00581 if( session_saving && level <= 2 ) // <= normal 00582 { 00583 return true; 00584 } 00585 Client* ac = mostRecentlyActivatedClient(); 00586 if( level == 0 ) // none 00587 return true; 00588 if( level == 4 ) // extreme 00589 return false; 00590 if( ac == NULL || ac->isDesktop()) 00591 { 00592 // kdDebug( 1212 ) << "Raising: No client active, allowing" << endl; 00593 return true; // no active client -> always allow 00594 } 00595 if( c->ignoreFocusStealing()) 00596 return true; 00597 // TODO window urgency -> return true? 00598 if( Client::belongToSameApplication( c, ac, true )) 00599 { 00600 // kdDebug( 1212 ) << "Raising: Belongs to active application" << endl; 00601 return true; 00602 } 00603 if( level == 3 ) // high 00604 return false; 00605 Time user_time = ac->userTime(); 00606 // kdDebug( 1212 ) << "Raising, compared:" << time << ":" << user_time 00607 // << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl; 00608 return timestampCompare( time, user_time ) >= 0; // time >= user_time 00609 } 00610 00611 // called from Client after FocusIn that wasn't initiated by KWin and the client 00612 // wasn't allowed to activate 00613 void Workspace::restoreFocus() 00614 { 00615 // this updateXTime() is necessary - as FocusIn events don't have 00616 // a timestamp *sigh*, twin's timestamp would be older than the timestamp 00617 // that was used by whoever caused the focus change, and therefore 00618 // the attempt to restore the focus would fail due to old timestamp 00619 updateXTime(); 00620 if( should_get_focus.count() > 0 ) 00621 requestFocus( should_get_focus.last()); 00622 else if( last_active_client ) 00623 requestFocus( last_active_client ); 00624 } 00625 00626 void Workspace::clientAttentionChanged( Client* c, bool set ) 00627 { 00628 if( set ) 00629 { 00630 attention_chain.remove( c ); 00631 attention_chain.prepend( c ); 00632 } 00633 else 00634 attention_chain.remove( c ); 00635 } 00636 00637 // This is used when a client should be shown active immediately after requestFocus(), 00638 // without waiting for the matching FocusIn that will really make the window the active one. 00639 // Used only in special cases, e.g. for MouseActivateRaiseandMove with transparent windows, 00640 bool Workspace::fakeRequestedActivity( Client* c ) 00641 { 00642 if( should_get_focus.count() > 0 && should_get_focus.last() == c ) 00643 { 00644 if( c->isActive()) 00645 return false; 00646 c->setActive( true ); 00647 return true; 00648 } 00649 return false; 00650 } 00651 00652 void Workspace::unfakeActivity( Client* c ) 00653 { 00654 if( should_get_focus.count() > 0 && should_get_focus.last() == c ) 00655 { // TODO this will cause flicker, and probably is not needed 00656 if( last_active_client != NULL ) 00657 last_active_client->setActive( true ); 00658 else 00659 c->setActive( false ); 00660 } 00661 } 00662 00663 00664 //******************************************** 00665 // Client 00666 //******************************************** 00667 00674 void Client::updateUserTime( Time time ) 00675 { // copied in Group::updateUserTime 00676 if( time == CurrentTime ) 00677 time = GET_QT_X_TIME(); 00678 if( time != -1U 00679 && ( user_time == CurrentTime 00680 || timestampCompare( time, user_time ) > 0 )) // time > user_time 00681 user_time = time; 00682 group()->updateUserTime( user_time ); 00683 } 00684 00685 Time Client::readUserCreationTime() const 00686 { 00687 long result = -1; // Time == -1 means none 00688 Atom type; 00689 int format, status; 00690 unsigned long nitems = 0; 00691 unsigned long extra = 0; 00692 unsigned char *data = 0; 00693 KXErrorHandler handler; // ignore errors? 00694 status = XGetWindowProperty( tqt_xdisplay(), window(), 00695 atoms->kde_net_wm_user_creation_time, 0, 10000, FALSE, XA_CARDINAL, 00696 &type, &format, &nitems, &extra, &data ); 00697 if (status == Success ) 00698 { 00699 if (data && nitems > 0) 00700 result = *((long*) data); 00701 XFree(data); 00702 } 00703 return result; 00704 } 00705 00706 void Client::demandAttention( bool set ) 00707 { 00708 if( isActive()) 00709 set = false; 00710 if( demands_attention == set ) 00711 return; 00712 demands_attention = set; 00713 if( demands_attention ) 00714 { 00715 // Demand attention flag is often set right from manage(), when focus stealing prevention 00716 // steps in. At that time the window has no taskbar entry yet, so KNotify cannot place 00717 // e.g. the passive popup next to it. So wait up to 1 second for the icon geometry 00718 // to be set. 00719 // Delayed call to KNotify also solves the problem of having X server grab in manage(), 00720 // which may deadlock when KNotify (or TDELauncher when launching KNotify) need to access X. 00721 Notify::Event e = isOnCurrentDesktop() ? Notify::DemandAttentionCurrent : Notify::DemandAttentionOther; 00722 // Setting the demands attention state needs to be done directly in KWin, because 00723 // KNotify would try to set it, resulting in a call to KNotify again, etc. 00724 if( Notify::makeDemandAttention( e )) 00725 info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention ); 00726 00727 if( demandAttentionKNotifyTimer == NULL ) 00728 { 00729 demandAttentionKNotifyTimer = new TQTimer( this ); 00730 connect( demandAttentionKNotifyTimer, TQT_SIGNAL( timeout()), TQT_SLOT( demandAttentionKNotify())); 00731 } 00732 demandAttentionKNotifyTimer->start( 1000, true ); 00733 } 00734 else 00735 info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention ); 00736 workspace()->clientAttentionChanged( this, set ); 00737 } 00738 00739 void Client::demandAttentionKNotify() 00740 { 00741 Notify::Event e = isOnCurrentDesktop() ? Notify::DemandAttentionCurrent : Notify::DemandAttentionOther; 00742 Notify::raise( e, i18n( "Window '%1' demands attention." ).arg( KStringHandler::csqueeze(caption())), this ); 00743 demandAttentionKNotifyTimer->stop(); 00744 demandAttentionKNotifyTimer->deleteLater(); 00745 demandAttentionKNotifyTimer = NULL; 00746 } 00747 00748 // TODO I probably shouldn't be lazy here and do it without the macro, so that people can read it 00749 KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, const Client*, 00750 // ignore already existing splashes, toolbars, utilities, menus and topmenus, 00751 // as the app may show those before the main window 00752 !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu() 00753 && Client::belongToSameApplication( cl, value, true ) && cl != value); 00754 00755 Time Client::readUserTimeMapTimestamp( const TDEStartupInfoId* asn_id, const TDEStartupInfoData* asn_data, 00756 bool session ) const 00757 { 00758 Time time = info->userTime(); 00759 // kdDebug( 1212 ) << "User timestamp, initial:" << time << endl; 00760 // newer ASN timestamp always replaces user timestamp, unless user timestamp is 0 00761 // helps e.g. with konqy reusing 00762 if( asn_data != NULL && time != 0 ) 00763 { 00764 // prefer timestamp from ASN id (timestamp from data is obsolete way) 00765 if( asn_id->timestamp() != 0 00766 && ( time == -1U || timestampCompare( asn_id->timestamp(), time ) > 0 )) 00767 { 00768 time = asn_id->timestamp(); 00769 } 00770 else if( asn_data->timestamp() != -1U 00771 && ( time == -1U || timestampCompare( asn_data->timestamp(), time ) > 0 )) 00772 { 00773 time = asn_data->timestamp(); 00774 } 00775 } 00776 // kdDebug( 1212 ) << "User timestamp, ASN:" << time << endl; 00777 if( time == -1U ) 00778 { // The window doesn't have any timestamp. 00779 // If it's the first window for its application 00780 // (i.e. there's no other window from the same app), 00781 // use the _TDE_NET_WM_USER_CREATION_TIME trick. 00782 // Otherwise, refuse activation of a window 00783 // from already running application if this application 00784 // is not the active one (unless focus stealing prevention is turned off). 00785 Client* act = workspace()->mostRecentlyActivatedClient(); 00786 if( act != NULL && !belongToSameApplication( act, this, true )) 00787 { 00788 bool first_window = true; 00789 if( isTransient()) 00790 { 00791 if( act->hasTransient( this, true )) 00792 ; // is transient for currently active window, even though it's not 00793 // the same app (e.g. kcookiejar dialog) -> allow activation 00794 else if( groupTransient() && 00795 findClientInList( mainClients(), SameApplicationActiveHackPredicate( this )) == NULL ) 00796 ; // standalone transient 00797 else 00798 first_window = false; 00799 } 00800 else 00801 { 00802 if( workspace()->findClient( SameApplicationActiveHackPredicate( this ))) 00803 first_window = false; 00804 } 00805 // don't refuse if focus stealing prevention is turned off 00806 if( !first_window && rules()->checkFSP( options->focusStealingPreventionLevel ) > 0 ) 00807 { 00808 // kdDebug( 1212 ) << "User timestamp, already exists:" << 0 << endl; 00809 return 0; // refuse activation 00810 } 00811 } 00812 // Creation time would just mess things up during session startup, 00813 // as possibly many apps are started up at the same time. 00814 // If there's no active window yet, no timestamp will be needed, 00815 // as plain Workspace::allowClientActivation() will return true 00816 // in such case. And if there's already active window, 00817 // it's better not to activate the new one. 00818 // Unless it was the active window at the time 00819 // of session saving and there was no user interaction yet, 00820 // this check will be done in manage(). 00821 if( session ) 00822 return -1U; 00823 if( ignoreFocusStealing() && act != NULL ) 00824 time = act->userTime(); 00825 else 00826 time = readUserCreationTime(); 00827 } 00828 // kdDebug( 1212 ) << "User timestamp, final:" << this << ":" << time << endl; 00829 return time; 00830 } 00831 00832 Time Client::userTime() const 00833 { 00834 Time time = user_time; 00835 if( time == 0 ) // doesn't want focus after showing 00836 return 0; 00837 assert( group() != NULL ); 00838 if( time == -1U 00839 || ( group()->userTime() != -1U 00840 && timestampCompare( group()->userTime(), time ) > 0 )) 00841 time = group()->userTime(); 00842 return time; 00843 } 00844 00856 void Client::setActive( bool act, bool updateOpacity_) 00857 { 00858 if ( active == act ) 00859 return; 00860 active = act; 00861 workspace()->setActiveClient( act ? this : NULL, Allowed ); 00862 00863 if (updateOpacity_) updateOpacity(); 00864 if (isModal() && transientFor()) 00865 { 00866 if (!act) transientFor()->updateOpacity(); 00867 else if (!transientFor()->custom_opacity) transientFor()->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity); 00868 } 00869 updateShadowSize(); 00870 00871 if ( active ) 00872 { 00873 Notify::raise( Notify::Activate ); 00874 if (options->shadowEnabled(true)) 00875 { 00876 if (options->shadowEnabled(false)) 00877 { 00878 // Wait for inactive shadow to expose occluded windows and give 00879 // them a chance to redraw before painting the active shadow 00880 removeShadow(); 00881 drawDelayedShadow(); 00882 if (!isDesktop() && 00883 this != workspace()->topClientOnDesktop(desktop())) 00884 // If the newly activated window's isn't the desktop, wait 00885 // for its shadow to draw, then redraw any shadows 00886 // overlapping it. 00887 drawOverlappingShadows(true); 00888 } 00889 else 00890 drawShadow(); 00891 } 00892 } 00893 else 00894 { 00895 removeShadow(); 00896 00897 if (options->shadowEnabled(false)) 00898 { 00899 if (this == workspace()->topClientOnDesktop(desktop())) 00900 { 00901 /* If the newly deactivated window is the top client on the 00902 * desktop, then the newly activated window is below it; ensure 00903 * that the deactivated window's shadow draws after the 00904 * activated window's shadow. 00905 */ 00906 if ((shadowAfterClient = workspace()->activeClient())) 00907 { 00908 drawShadowAfter(shadowAfterClient); 00909 } 00910 } 00911 else 00912 { 00913 drawDelayedShadow(); 00914 } 00915 } 00916 } 00917 00918 if( !active ) 00919 cancelAutoRaise(); 00920 00921 if( !active && shade_mode == ShadeActivated ) 00922 setShade( ShadeNormal ); 00923 00924 StackingUpdatesBlocker blocker( workspace()); 00925 workspace()->updateClientLayer( this ); // active windows may get different layer 00926 // TODO optimize? mainClients() may be a bit expensive 00927 ClientList mainclients = mainClients(); 00928 for( ClientList::ConstIterator it = mainclients.begin(); 00929 it != mainclients.end(); 00930 ++it ) 00931 if( (*it)->isFullScreen()) // fullscreens go high even if their transient is active 00932 workspace()->updateClientLayer( *it ); 00933 if( decoration != NULL ) 00934 decoration->activeChange(); 00935 updateMouseGrab(); 00936 updateUrgency(); // demand attention again if it's still urgent 00937 } 00938 00939 void Client::startupIdChanged() 00940 { 00941 TDEStartupInfoId asn_id; 00942 TDEStartupInfoData asn_data; 00943 bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data ); 00944 if( !asn_valid ) 00945 return; 00946 // If the ASN contains desktop, move it to the desktop, otherwise move it to the current 00947 // desktop (since the new ASN should make the window act like if it's a new application 00948 // launched). However don't affect the window's desktop if it's set to be on all desktops. 00949 int desktop = workspace()->currentDesktop(); 00950 if( asn_data.desktop() != 0 ) 00951 desktop = asn_data.desktop(); 00952 if( !isOnAllDesktops()) 00953 workspace()->sendClientToDesktop( this, desktop, true ); 00954 if( asn_data.xinerama() != -1 ) 00955 workspace()->sendClientToScreen( this, asn_data.xinerama()); 00956 Time timestamp = asn_id.timestamp(); 00957 if( timestamp == 0 && asn_data.timestamp() != -1U ) 00958 timestamp = asn_data.timestamp(); 00959 if( timestamp != 0 ) 00960 { 00961 bool activate = workspace()->allowClientActivation( this, timestamp ); 00962 if( asn_data.desktop() != 0 && !isOnCurrentDesktop()) 00963 activate = false; // it was started on different desktop than current one 00964 if( activate ) 00965 workspace()->activateClient( this ); 00966 else 00967 demandAttention(); 00968 } 00969 } 00970 00971 void Client::updateUrgency() 00972 { 00973 if( urgency ) 00974 demandAttention(); 00975 } 00976 00977 void Client::shortcutActivated() 00978 { 00979 workspace()->activateClient( this, true ); // force 00980 } 00981 00982 //**************************************** 00983 // Group 00984 //**************************************** 00985 00986 void Group::startupIdChanged() 00987 { 00988 TDEStartupInfoId asn_id; 00989 TDEStartupInfoData asn_data; 00990 bool asn_valid = workspace()->checkStartupNotification( leader_wid, asn_id, asn_data ); 00991 if( !asn_valid ) 00992 return; 00993 if( asn_id.timestamp() != 0 && user_time != -1U 00994 && timestampCompare( asn_id.timestamp(), user_time ) > 0 ) 00995 { 00996 user_time = asn_id.timestamp(); 00997 } 00998 else if( asn_data.timestamp() != -1U && user_time != -1U 00999 && timestampCompare( asn_data.timestamp(), user_time ) > 0 ) 01000 { 01001 user_time = asn_data.timestamp(); 01002 } 01003 } 01004 01005 void Group::updateUserTime( Time time ) 01006 { // copy of Client::updateUserTime 01007 if( time == CurrentTime ) 01008 time = GET_QT_X_TIME(); 01009 if( time != -1U 01010 && ( user_time == CurrentTime 01011 || timestampCompare( time, user_time ) > 0 )) // time > user_time 01012 user_time = time; 01013 } 01014 01015 } // namespace