Warning, file /plasma/kwin/src/activation.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org> 0006 SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 /* 0012 0013 This file contains things relevant to window activation and focus 0014 stealing prevention. 0015 0016 */ 0017 0018 #include "cursor.h" 0019 #include "focuschain.h" 0020 #include "netinfo.h" 0021 #include "workspace.h" 0022 #include "x11window.h" 0023 #if KWIN_BUILD_ACTIVITIES 0024 #include "activities.h" 0025 #endif 0026 #include "virtualdesktops.h" 0027 0028 #include <KLocalizedString> 0029 #include <kstartupinfo.h> 0030 #include <kstringhandler.h> 0031 0032 #include "atoms.h" 0033 #include "group.h" 0034 #include "rules.h" 0035 #include "useractions.h" 0036 #include <QDebug> 0037 0038 namespace KWin 0039 { 0040 0041 /* 0042 Prevention of focus stealing: 0043 0044 KWin tries to prevent unwanted changes of focus, that would result 0045 from mapping a new window. Also, some nasty applications may try 0046 to force focus change even in cases when ICCCM 4.2.7 doesn't allow it 0047 (e.g. they may try to activate their main window because the user 0048 definitely "needs" to see something happened - misusing 0049 of QWidget::setActiveWindow() may be such case). 0050 0051 There are 4 ways how a window may become active: 0052 - the user changes the active window (e.g. focus follows mouse, clicking 0053 on some window's titlebar) - the change of focus will 0054 be done by KWin, so there's nothing to solve in this case 0055 - the change of active window will be requested using the _NET_ACTIVE_WINDOW 0056 message (handled in RootInfo::changeActiveWindow()) - such requests 0057 will be obeyed, because this request is meant mainly for e.g. taskbar 0058 asking the WM to change the active window as a result of some user action. 0059 Normal applications should use this request only rarely in special cases. 0060 See also below the discussion of _NET_ACTIVE_WINDOW_TRANSFER. 0061 - the change of active window will be done by performing XSetInputFocus() 0062 on a window that's not currently active. ICCCM 4.2.7 describes when 0063 the application may perform change of input focus. In order to handle 0064 misbehaving applications, KWin will try to detect focus changes to 0065 windows that don't belong to currently active application, and restore 0066 focus back to the currently active window, instead of activating the window 0067 that got focus (unfortunately there's no way to FocusChangeRedirect similar 0068 to e.g. SubstructureRedirect, so there will be short time when the focus 0069 will be changed). The check itself that's done is 0070 Workspace::allowWindowActivation() (see below). 0071 - a new window will be mapped - this is the most complicated case. If 0072 the new window belongs to the currently active application, it may be safely 0073 mapped on top and activated. The same if there's no active window, 0074 or the active window is the desktop. These checks are done by 0075 Workspace::allowWindowActivation(). 0076 Following checks need to compare times. One time is the timestamp 0077 of last user action in the currently active window, the other time is 0078 the timestamp of the action that originally caused mapping of the new window 0079 (e.g. when the application was started). If the first time is newer than 0080 the second one, the window will not be activated, as that indicates 0081 futher user actions took place after the action leading to this new 0082 mapped window. This check is done by Workspace::allowWindowActivation(). 0083 There are several ways how to get the timestamp of action that caused 0084 the new mapped window (done in X11Window::readUserTimeMapTimestamp()) : 0085 - the window may have the _NET_WM_USER_TIME property. This way 0086 the application may either explicitly request that the window is not 0087 activated (by using 0 timestamp), or the property contains the time 0088 of last user action in the application. 0089 - KWin itself tries to detect time of last user action in every window, 0090 by watching KeyPress and ButtonPress events on windows. This way some 0091 events may be missed (if they don't propagate to the toplevel window), 0092 but it's good as a fallback for applications that don't provide 0093 _NET_WM_USER_TIME, and missing some events may at most lead 0094 to unwanted focus stealing. 0095 - the timestamp may come from application startup notification. 0096 Application startup notification, if it exists for the new mapped window, 0097 should include time of the user action that caused it. 0098 - if there's no timestamp available, it's checked whether the new window 0099 belongs to some already running application - if yes, the timestamp 0100 will be 0 (i.e. refuse activation) 0101 - if the window is from session restored window, the timestamp will 0102 be 0 too, unless this application was the active one at the time 0103 when the session was saved, in which case the window will be 0104 activated if there wasn't any user interaction since the time 0105 KWin was started. 0106 - as the last resort, the _KDE_NET_USER_CREATION_TIME timestamp 0107 is used. For every toplevel window that is created (see CreateNotify 0108 handling), this property is set to the at that time current time. 0109 Since at this time it's known that the new window doesn't belong 0110 to any existing application (better said, the application doesn't 0111 have any other window mapped), it is either the very first window 0112 of the application, or it is the only window of the application 0113 that was hidden before. The latter case is handled by removing 0114 the property from windows before withdrawing them, making 0115 the timestamp empty for next mapping of the window. In the sooner 0116 case, the timestamp will be used. This helps in case when 0117 an application is launched without application startup notification, 0118 it creates its mainwindow, and starts its initialization (that 0119 may possibly take long time). The timestamp used will be older 0120 than any user action done after launching this application. 0121 - if no timestamp is found at all, the window is activated. 0122 The check whether two windows belong to the same application (same 0123 process) is done in X11Window::belongToSameApplication(). Not 100% reliable, 0124 but hopefully 99,99% reliable. 0125 0126 As a somewhat special case, window activation is always enabled when 0127 session saving is in progress. When session saving, the session 0128 manager allows only one application to interact with the user. 0129 Not allowing window activation in such case would result in e.g. dialogs 0130 not becoming active, so focus stealing prevention would cause here 0131 more harm than good. 0132 0133 Windows that attempted to become active but KWin prevented this will 0134 be marked as demanding user attention. They'll get 0135 the _NET_WM_STATE_DEMANDS_ATTENTION state, and the taskbar should mark 0136 them specially (blink, etc.). The state will be reset when the window 0137 eventually really becomes active. 0138 0139 There are two more ways how a window can become obtrusive, window stealing 0140 focus: By showing above the active window, by either raising itself, 0141 or by moving itself on the active desktop. 0142 - KWin will refuse raising non-active window above the active one, 0143 unless they belong to the same application. Applications shouldn't 0144 raise their windows anyway (unless the app wants to raise one 0145 of its windows above another of its windows). 0146 - KWin activates windows moved to the current desktop (as that seems 0147 logical from the user's point of view, after sending the window 0148 there directly from KWin, or e.g. using pager). This means 0149 applications shouldn't send their windows to another desktop 0150 (SELI TODO - but what if they do?) 0151 0152 Special cases I can think of: 0153 - konqueror reusing, i.e. kfmclient tells running Konqueror instance 0154 to open new window 0155 - without focus stealing prevention - no problem 0156 - with ASN (application startup notification) - ASN is forwarded, 0157 and because it's newer than the instance's user timestamp, 0158 it takes precedence 0159 - without ASN - user timestamp needs to be reset, otherwise it would 0160 be used, and it's old; moreover this new window mustn't be detected 0161 as window belonging to already running application, or it wouldn't 0162 be activated - see X11Window::sameAppWindowRoleMatch() for the (rather ugly) 0163 hack 0164 - konqueror preloading, i.e. window is created in advance, and kfmclient 0165 tells this Konqueror instance to show it later 0166 - without focus stealing prevention - no problem 0167 - with ASN - ASN is forwarded, and because it's newer than the instance's 0168 user timestamp, it takes precedence 0169 - without ASN - user timestamp needs to be reset, otherwise it would 0170 be used, and it's old; also, creation timestamp is changed to 0171 the time the instance starts (re-)initializing the window, 0172 this ensures creation timestamp will still work somewhat even in this case 0173 - KUniqueApplication - when the window is already visible, and the new instance 0174 wants it to activate 0175 - without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem 0176 - with ASN - ASN is forwarded, and set on the already visible window, KWin 0177 treats the window as new with that ASN 0178 - without ASN - _NET_ACTIVE_WINDOW as application request is used, 0179 and there's no really usable timestamp, only timestamp 0180 from the time the (new) application instance was started, 0181 so KWin will activate the window *sigh* 0182 - the bad thing here is that there's absolutely no chance to recognize 0183 the case of starting this KUniqueApp from Konsole (and thus wanting 0184 the already visible window to become active) from the case 0185 when something started this KUniqueApp without ASN (in which case 0186 the already visible window shouldn't become active) 0187 - the only solution is using ASN for starting applications, at least silent 0188 (i.e. without feedback) 0189 - when one application wants to activate another application's window (e.g. KMail 0190 activating already running KAddressBook window ?) 0191 - without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem 0192 - with ASN - can't be here, it's the KUniqueApp case then 0193 - without ASN - _NET_ACTIVE_WINDOW as application request should be used, 0194 KWin will activate the new window depending on the timestamp and 0195 whether it belongs to the currently active application 0196 0197 _NET_ACTIVE_WINDOW usage: 0198 data.l[0]= 1 ->app request 0199 = 2 ->pager request 0200 = 0 - backwards compatibility 0201 data.l[1]= timestamp 0202 */ 0203 0204 //**************************************** 0205 // Workspace 0206 //**************************************** 0207 0208 /** 0209 * Informs the workspace about the active window, i.e. the window that 0210 * has the focus (or None if no window has the focus). This functions 0211 * is called by the window itself that gets focus. It has no other 0212 * effect than fixing the focus chain and the return value of 0213 * activeWindow(). And of course, to propagate the active window to the 0214 * world. 0215 */ 0216 void Workspace::setActiveWindow(Window *window) 0217 { 0218 if (m_activeWindow == window) { 0219 return; 0220 } 0221 0222 if (active_popup && m_activePopupWindow != window && m_setActiveWindowRecursion == 0) { 0223 closeActivePopup(); 0224 } 0225 if (m_userActionsMenu->hasWindow() && !m_userActionsMenu->isMenuWindow(window) && m_setActiveWindowRecursion == 0) { 0226 m_userActionsMenu->close(); 0227 } 0228 StackingUpdatesBlocker blocker(this); 0229 ++m_setActiveWindowRecursion; 0230 updateFocusMousePosition(Cursors::self()->mouse()->pos()); 0231 if (m_activeWindow != nullptr) { 0232 // note that this may call setActiveWindow( NULL ), therefore the recursion counter 0233 m_activeWindow->setActive(false); 0234 } 0235 m_activeWindow = window; 0236 Q_ASSERT(window == nullptr || window->isActive()); 0237 0238 if (m_activeWindow) { 0239 m_lastActiveWindow = m_activeWindow; 0240 m_focusChain->update(m_activeWindow, FocusChain::MakeFirst); 0241 m_activeWindow->demandAttention(false); 0242 0243 // activating a client can cause a non active fullscreen window to loose the ActiveLayer status on > 1 screens 0244 if (outputs().count() > 1) { 0245 for (auto it = m_allClients.begin(); it != m_allClients.end(); ++it) { 0246 if (*it != m_activeWindow && (*it)->layer() == ActiveLayer && (*it)->output() == m_activeWindow->output()) { 0247 (*it)->updateLayer(); 0248 } 0249 } 0250 } 0251 } 0252 0253 updateToolWindows(false); 0254 if (window) { 0255 disableGlobalShortcutsForClient(window->rules()->checkDisableGlobalShortcuts(false)); 0256 } else { 0257 disableGlobalShortcutsForClient(false); 0258 } 0259 0260 updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active 0261 0262 if (rootInfo()) { 0263 rootInfo()->setActiveClient(m_activeWindow); 0264 } 0265 0266 Q_EMIT windowActivated(m_activeWindow); 0267 --m_setActiveWindowRecursion; 0268 } 0269 0270 /** 0271 * Tries to activate the window \a window. This function performs what you 0272 * expect when clicking the respective entry in a taskbar: showing and 0273 * raising the window (this may imply switching to the another virtual 0274 * desktop) and putting the focus onto it. Once X really gave focus to 0275 * the window window as requested, the window itself will call 0276 * setActiveWindow() and the operation is complete. This may not happen 0277 * with certain focus policies, though. 0278 * 0279 * @see setActiveWindow 0280 * @see requestFocus 0281 */ 0282 void Workspace::activateWindow(Window *window, bool force) 0283 { 0284 if (window == nullptr) { 0285 focusToNull(); 0286 setActiveWindow(nullptr); 0287 return; 0288 } 0289 if (window->isDeleted()) { 0290 return; 0291 } 0292 raiseWindow(window); 0293 if (!window->isOnCurrentDesktop()) { 0294 ++block_focus; 0295 switch (options->activationDesktopPolicy()) { 0296 case Options::ActivationDesktopPolicy::SwitchToOtherDesktop: 0297 VirtualDesktopManager::self()->setCurrent(window->desktops().constLast()); 0298 break; 0299 case Options::ActivationDesktopPolicy::BringToCurrentDesktop: 0300 window->enterDesktop(VirtualDesktopManager::self()->currentDesktop()); 0301 break; 0302 } 0303 --block_focus; 0304 } 0305 #if KWIN_BUILD_ACTIVITIES 0306 if (!window->isOnCurrentActivity()) { 0307 ++block_focus; 0308 // DBUS! 0309 // first isn't necessarily best, but it's easiest 0310 m_activities->setCurrent(window->activities().constFirst()); 0311 --block_focus; 0312 } 0313 #endif 0314 if (window->isMinimized()) { 0315 window->unminimize(); 0316 } 0317 0318 // ensure the window is really visible - could eg. be a hidden utility window, see bug #348083 0319 window->showClient(); 0320 0321 // TODO force should perhaps allow this only if the window already contains the mouse 0322 if (options->focusPolicyIsReasonable() || force) { 0323 requestFocus(window, force); 0324 } 0325 0326 // Don't update user time for windows that have focus stealing workaround. 0327 // As they usually belong to the current active window but fail to provide 0328 // this information, updating their user time would make the user time 0329 // of the currently active window old, and reject further activation for it. 0330 // E.g. typing URL in minicli which will show kio_uiserver dialog (with workaround), 0331 // and then kdesktop shows dialog about SSL certificate. 0332 // This needs also avoiding user creation time in X11Window::readUserTimeMapTimestamp(). 0333 if (X11Window *x11Window = dynamic_cast<X11Window *>(window)) { 0334 // updateUserTime is X11 specific 0335 x11Window->updateUserTime(); 0336 } 0337 } 0338 0339 /** 0340 * Tries to activate the window by asking X for the input focus. This 0341 * function does not perform any show, raise or desktop switching. See 0342 * Workspace::activateWindow() instead. 0343 * 0344 * @see activateWindow 0345 */ 0346 bool Workspace::requestFocus(Window *window, bool force) 0347 { 0348 return takeActivity(window, force ? ActivityFocusForce : ActivityFocus); 0349 } 0350 0351 bool Workspace::takeActivity(Window *window, ActivityFlags flags) 0352 { 0353 // the 'if ( window == m_activeWindow ) return;' optimization mustn't be done here 0354 if (!focusChangeEnabled() && (window != m_activeWindow)) { 0355 flags &= ~ActivityFocus; 0356 } 0357 0358 if (!window) { 0359 focusToNull(); 0360 return true; 0361 } 0362 0363 if (flags & ActivityFocus) { 0364 Window *modal = window->findModal(); 0365 if (modal != nullptr && modal != window) { 0366 if (modal->desktops() != window->desktops()) { 0367 modal->setDesktops(window->desktops()); 0368 } 0369 if (!modal->isShown() && !modal->isMinimized()) { // forced desktop or utility window 0370 activateWindow(modal); // activating a minimized blocked window will unminimize its modal implicitly 0371 } 0372 // if the click was inside the window (i.e. handled is set), 0373 // but it has a modal, there's no need to use handled mode, because 0374 // the modal doesn't get the click anyway 0375 // raising of the original window needs to be still done 0376 if (flags & ActivityRaise) { 0377 raiseWindow(window); 0378 } 0379 window = modal; 0380 } 0381 cancelDelayFocus(); 0382 } 0383 if (!flags.testFlag(ActivityFocusForce) && (window->isDock() || window->isSplash())) { 0384 // toplevel menus and dock windows don't take focus if not forced 0385 // and don't have a flag that they take focus 0386 if (!window->dockWantsInput()) { 0387 flags &= ~ActivityFocus; 0388 } 0389 } 0390 if (window->isShade()) { 0391 if (window->wantsInput() && (flags & ActivityFocus)) { 0392 // window cannot accept focus, but at least the window should be active (window menu, et. al. ) 0393 window->setActive(true); 0394 focusToNull(); 0395 } 0396 flags &= ~ActivityFocus; 0397 } 0398 if (!window->isShown()) { // shouldn't happen, call activateWindow() if needed 0399 qCWarning(KWIN_CORE) << "takeActivity: not shown"; 0400 return false; 0401 } 0402 0403 bool ret = true; 0404 0405 if (flags & ActivityFocus) { 0406 ret &= window->takeFocus(); 0407 } 0408 if (flags & ActivityRaise) { 0409 workspace()->raiseWindow(window); 0410 } 0411 0412 if (!window->isOnActiveOutput()) { 0413 setActiveOutput(window->output()); 0414 } 0415 0416 return ret; 0417 } 0418 0419 /** 0420 * Informs the workspace that the window \a window has been hidden. If it 0421 * was the active window (or to-become the active window), 0422 * the workspace activates another one. 0423 * 0424 * @note @p c may already be destroyed. 0425 */ 0426 void Workspace::windowHidden(Window *window) 0427 { 0428 Q_ASSERT(!window->isShown() || !window->isOnCurrentDesktop() || !window->isOnCurrentActivity()); 0429 activateNextWindow(window); 0430 } 0431 0432 Window *Workspace::windowUnderMouse(Output *output) const 0433 { 0434 auto it = stackingOrder().constEnd(); 0435 while (it != stackingOrder().constBegin()) { 0436 auto window = *(--it); 0437 if (!window->isClient()) { 0438 continue; 0439 } 0440 0441 // rule out windows which are not really visible. 0442 // the screen test is rather superfluous for xrandr & twinview since the geometry would differ -> TODO: might be dropped 0443 if (!(window->isShown() && window->isOnCurrentDesktop() && window->isOnCurrentActivity() && window->isOnOutput(output) && !window->isShade())) { 0444 continue; 0445 } 0446 0447 if (window->frameGeometry().contains(Cursors::self()->mouse()->pos())) { 0448 return window; 0449 } 0450 } 0451 return nullptr; 0452 } 0453 0454 // deactivates 'window' and activates next window 0455 bool Workspace::activateNextWindow(Window *window) 0456 { 0457 // if 'c' is not the active or the to-become active one, do nothing 0458 if (!(window == m_activeWindow || (should_get_focus.count() > 0 && window == should_get_focus.last()))) { 0459 return false; 0460 } 0461 0462 closeActivePopup(); 0463 0464 if (window != nullptr) { 0465 if (window == m_activeWindow) { 0466 setActiveWindow(nullptr); 0467 } 0468 should_get_focus.removeAll(window); 0469 } 0470 0471 // if blocking focus, move focus to the desktop later if needed 0472 // in order to avoid flickering 0473 if (!focusChangeEnabled()) { 0474 focusToNull(); 0475 return true; 0476 } 0477 0478 if (!options->focusPolicyIsReasonable()) { 0479 return false; 0480 } 0481 0482 Window *focusCandidate = nullptr; 0483 0484 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop(); 0485 0486 if (!focusCandidate && showingDesktop()) { 0487 focusCandidate = findDesktop(true, desktop); // to not break the state 0488 } 0489 0490 if (!focusCandidate && options->isNextFocusPrefersMouse()) { 0491 focusCandidate = windowUnderMouse(window ? window->output() : workspace()->activeOutput()); 0492 if (focusCandidate && (focusCandidate == window || focusCandidate->isDesktop())) { 0493 // should rather not happen, but it cannot get the focus. rest of usability is tested above 0494 focusCandidate = nullptr; 0495 } 0496 } 0497 0498 if (!focusCandidate) { // no suitable window under the mouse -> find sth. else 0499 // first try to pass the focus to the (former) active clients leader 0500 if (window && window->isTransient()) { 0501 auto leaders = window->mainWindows(); 0502 if (leaders.count() == 1 && m_focusChain->isUsableFocusCandidate(leaders.at(0), window)) { 0503 focusCandidate = leaders.at(0); 0504 raiseWindow(focusCandidate); // also raise - we don't know where it came from 0505 } 0506 } 0507 if (!focusCandidate) { 0508 // nope, ask the focus chain for the next candidate 0509 focusCandidate = m_focusChain->nextForDesktop(window, desktop); 0510 } 0511 } 0512 0513 if (focusCandidate == nullptr) { // last chance: focus the desktop 0514 focusCandidate = findDesktop(true, desktop); 0515 } 0516 0517 if (focusCandidate != nullptr) { 0518 requestFocus(focusCandidate); 0519 } else { 0520 focusToNull(); 0521 } 0522 0523 return true; 0524 } 0525 0526 void Workspace::switchToOutput(Output *output) 0527 { 0528 if (!options->focusPolicyIsReasonable()) { 0529 return; 0530 } 0531 closeActivePopup(); 0532 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop(); 0533 Window *get_focus = m_focusChain->getForActivation(desktop, output); 0534 if (get_focus == nullptr) { 0535 get_focus = findDesktop(true, desktop); 0536 } 0537 if (get_focus != nullptr && get_focus != mostRecentlyActivatedWindow()) { 0538 requestFocus(get_focus); 0539 } 0540 setActiveOutput(output); 0541 } 0542 0543 void Workspace::gotFocusIn(const Window *window) 0544 { 0545 if (should_get_focus.contains(const_cast<Window *>(window))) { 0546 // remove also all sooner elements that should have got FocusIn, 0547 // but didn't for some reason (and also won't anymore, because they were sooner) 0548 while (should_get_focus.first() != window) { 0549 should_get_focus.pop_front(); 0550 } 0551 should_get_focus.pop_front(); // remove 'window' 0552 } 0553 } 0554 0555 void Workspace::setShouldGetFocus(Window *window) 0556 { 0557 should_get_focus.append(window); 0558 updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active 0559 } 0560 0561 // basically the same like allowWindowActivation(), this time allowing 0562 // a window to be fully raised upon its own request (XRaiseWindow), 0563 // if refused, it will be raised only on top of windows belonging 0564 // to the same application 0565 bool Workspace::allowFullClientRaising(const KWin::Window *window, xcb_timestamp_t time) 0566 { 0567 int level = window->rules()->checkFSP(options->focusStealingPreventionLevel()); 0568 if (sessionManager()->state() == SessionState::Saving && level <= 2) { // <= normal 0569 return true; 0570 } 0571 Window *ac = mostRecentlyActivatedWindow(); 0572 if (level == 0) { // none 0573 return true; 0574 } 0575 if (level == 4) { // extreme 0576 return false; 0577 } 0578 if (ac == nullptr || ac->isDesktop()) { 0579 qCDebug(KWIN_CORE) << "Raising: No window active, allowing"; 0580 return true; // no active window -> always allow 0581 } 0582 // TODO window urgency -> return true? 0583 if (Window::belongToSameApplication(window, ac, Window::SameApplicationCheck::RelaxedForActive)) { 0584 qCDebug(KWIN_CORE) << "Raising: Belongs to active application"; 0585 return true; 0586 } 0587 if (level == 3) { // high 0588 return false; 0589 } 0590 xcb_timestamp_t user_time = ac->userTime(); 0591 qCDebug(KWIN_CORE) << "Raising, compared:" << time << ":" << user_time 0592 << ":" << (NET::timestampCompare(time, user_time) >= 0); 0593 return NET::timestampCompare(time, user_time) >= 0; // time >= user_time 0594 } 0595 0596 /** 0597 * Called from X11Window after FocusIn that wasn't initiated by KWin and the window wasn't 0598 * allowed to activate. 0599 * 0600 * Returns @c true if the focus has been restored successfully; otherwise returns @c false. 0601 */ 0602 bool Workspace::restoreFocus() 0603 { 0604 // this updateXTime() is necessary - as FocusIn events don't have 0605 // a timestamp *sigh*, kwin's timestamp would be older than the timestamp 0606 // that was used by whoever caused the focus change, and therefore 0607 // the attempt to restore the focus would fail due to old timestamp 0608 kwinApp()->updateXTime(); 0609 if (should_get_focus.count() > 0) { 0610 return requestFocus(should_get_focus.last()); 0611 } else if (m_lastActiveWindow) { 0612 return requestFocus(m_lastActiveWindow); 0613 } 0614 return true; 0615 } 0616 0617 void Workspace::windowAttentionChanged(Window *window, bool set) 0618 { 0619 if (set) { 0620 attention_chain.removeAll(window); 0621 attention_chain.prepend(window); 0622 } else { 0623 attention_chain.removeAll(window); 0624 } 0625 Q_EMIT windowDemandsAttentionChanged(window, set); 0626 } 0627 0628 //******************************************** 0629 // Client 0630 //******************************************** 0631 0632 /** 0633 * Updates the user time (time of last action in the active window). 0634 * This is called inside kwin for every action with the window 0635 * that qualifies for user interaction (clicking on it, activate it 0636 * externally, etc.). 0637 */ 0638 void X11Window::updateUserTime(xcb_timestamp_t time) 0639 { 0640 // copied in Group::updateUserTime 0641 if (time == XCB_TIME_CURRENT_TIME) { 0642 kwinApp()->updateXTime(); 0643 time = xTime(); 0644 } 0645 if (time != -1U 0646 && (m_userTime == XCB_TIME_CURRENT_TIME 0647 || NET::timestampCompare(time, m_userTime) > 0)) { // time > user_time 0648 m_userTime = time; 0649 shade_below = nullptr; // do not hover re-shade a window after it got interaction 0650 } 0651 group()->updateUserTime(m_userTime); 0652 } 0653 0654 xcb_timestamp_t X11Window::readUserCreationTime() const 0655 { 0656 Xcb::Property prop(false, window(), atoms->kde_net_wm_user_creation_time, XCB_ATOM_CARDINAL, 0, 1); 0657 return prop.value<xcb_timestamp_t>(-1); 0658 } 0659 0660 xcb_timestamp_t X11Window::readUserTimeMapTimestamp(const KStartupInfoId *asn_id, const KStartupInfoData *asn_data, 0661 bool session) const 0662 { 0663 xcb_timestamp_t time = info->userTime(); 0664 // qDebug() << "User timestamp, initial:" << time; 0665 //^^ this deadlocks kwin --replace sometimes. 0666 0667 // newer ASN timestamp always replaces user timestamp, unless user timestamp is 0 0668 // helps e.g. with konqy reusing 0669 if (asn_data != nullptr && time != 0) { 0670 if (asn_id->timestamp() != 0 0671 && (time == -1U || NET::timestampCompare(asn_id->timestamp(), time) > 0)) { 0672 time = asn_id->timestamp(); 0673 } 0674 } 0675 qCDebug(KWIN_CORE) << "User timestamp, ASN:" << time; 0676 if (time == -1U) { 0677 // The window doesn't have any timestamp. 0678 // If it's the first window for its application 0679 // (i.e. there's no other window from the same app), 0680 // use the _KDE_NET_WM_USER_CREATION_TIME trick. 0681 // Otherwise, refuse activation of a window 0682 // from already running application if this application 0683 // is not the active one (unless focus stealing prevention is turned off). 0684 X11Window *act = dynamic_cast<X11Window *>(workspace()->mostRecentlyActivatedWindow()); 0685 if (act != nullptr && !belongToSameApplication(act, this, SameApplicationCheck::RelaxedForActive)) { 0686 bool first_window = true; 0687 auto sameApplicationActiveHackPredicate = [this](const X11Window *cl) { 0688 // ignore already existing splashes, toolbars, utilities and menus, 0689 // as the app may show those before the main window 0690 return !cl->isSplash() && !cl->isToolbar() && !cl->isUtility() && !cl->isMenu() 0691 && cl != this && X11Window::belongToSameApplication(cl, this, SameApplicationCheck::RelaxedForActive); 0692 }; 0693 if (isTransient()) { 0694 auto clientMainClients = [this]() { 0695 QList<X11Window *> ret; 0696 const auto mcs = mainWindows(); 0697 for (auto mc : mcs) { 0698 if (X11Window *c = dynamic_cast<X11Window *>(mc)) { 0699 ret << c; 0700 } 0701 } 0702 return ret; 0703 }; 0704 if (act->hasTransient(this, true)) { 0705 ; // is transient for currently active window, even though it's not 0706 // the same app (e.g. kcookiejar dialog) -> allow activation 0707 } else if (groupTransient() && findInList<X11Window, X11Window>(clientMainClients(), sameApplicationActiveHackPredicate) == nullptr) { 0708 ; // standalone transient 0709 } else { 0710 first_window = false; 0711 } 0712 } else { 0713 if (workspace()->findClient(sameApplicationActiveHackPredicate)) { 0714 first_window = false; 0715 } 0716 } 0717 // don't refuse if focus stealing prevention is turned off 0718 if (!first_window && rules()->checkFSP(options->focusStealingPreventionLevel()) > 0) { 0719 qCDebug(KWIN_CORE) << "User timestamp, already exists:" << 0; 0720 return 0; // refuse activation 0721 } 0722 } 0723 // Creation time would just mess things up during session startup, 0724 // as possibly many apps are started up at the same time. 0725 // If there's no active window yet, no timestamp will be needed, 0726 // as plain Workspace::allowWindowActivation() will return true 0727 // in such case. And if there's already active window, 0728 // it's better not to activate the new one. 0729 // Unless it was the active window at the time 0730 // of session saving and there was no user interaction yet, 0731 // this check will be done in manage(). 0732 if (session) { 0733 return -1U; 0734 } 0735 time = readUserCreationTime(); 0736 } 0737 qCDebug(KWIN_CORE) << "User timestamp, final:" << this << ":" << time; 0738 return time; 0739 } 0740 0741 xcb_timestamp_t X11Window::userTime() const 0742 { 0743 xcb_timestamp_t time = m_userTime; 0744 if (time == 0) { // doesn't want focus after showing 0745 return 0; 0746 } 0747 Q_ASSERT(group() != nullptr); 0748 if (time == -1U 0749 || (group()->userTime() != -1U 0750 && NET::timestampCompare(group()->userTime(), time) > 0)) { 0751 time = group()->userTime(); 0752 } 0753 return time; 0754 } 0755 0756 void X11Window::doSetActive() 0757 { 0758 updateUrgency(); // demand attention again if it's still urgent 0759 info->setState(isActive() ? NET::Focused : NET::States(), NET::Focused); 0760 } 0761 0762 void X11Window::startupIdChanged() 0763 { 0764 KStartupInfoId asn_id; 0765 KStartupInfoData asn_data; 0766 bool asn_valid = workspace()->checkStartupNotification(window(), asn_id, asn_data); 0767 if (!asn_valid) { 0768 return; 0769 } 0770 // If the ASN contains desktop, move it to the desktop, otherwise move it to the current 0771 // desktop (since the new ASN should make the window act like if it's a new application 0772 // launched). However don't affect the window's desktop if it's set to be on all desktops. 0773 0774 if (asn_data.desktop() != 0 && !isOnAllDesktops()) { 0775 workspace()->sendWindowToDesktop(this, asn_data.desktop(), true); 0776 } 0777 0778 if (asn_data.xinerama() != -1) { 0779 Output *output = workspace()->xineramaIndexToOutput(asn_data.xinerama()); 0780 if (output) { 0781 workspace()->sendWindowToOutput(this, output); 0782 } 0783 } 0784 const xcb_timestamp_t timestamp = asn_id.timestamp(); 0785 if (timestamp != 0) { 0786 bool activate = allowWindowActivation(timestamp); 0787 if (activate) { 0788 workspace()->activateWindow(this); 0789 } else { 0790 demandAttention(); 0791 } 0792 } 0793 } 0794 0795 void X11Window::updateUrgency() 0796 { 0797 if (info->urgency()) { 0798 demandAttention(); 0799 } 0800 } 0801 0802 namespace FSP 0803 { 0804 enum Level { 0805 None = 0, 0806 Low, 0807 Medium, 0808 High, 0809 Extreme, 0810 }; 0811 } 0812 0813 // focus_in -> the window got FocusIn event 0814 // ignore_desktop - call comes from _NET_ACTIVE_WINDOW message, don't refuse just because of window 0815 // is on a different desktop 0816 bool X11Window::allowWindowActivation(xcb_timestamp_t time, bool focus_in, bool ignore_desktop) 0817 { 0818 auto window = this; 0819 // options->focusStealingPreventionLevel : 0820 // 0 - none - old KWin behaviour, new windows always get focus 0821 // 1 - low - focus stealing prevention is applied normally, when unsure, activation is allowed 0822 // 2 - normal - focus stealing prevention is applied normally, when unsure, activation is not allowed, 0823 // this is the default 0824 // 3 - high - new window gets focus only if it belongs to the active application, 0825 // or when no window is currently active 0826 // 4 - extreme - no window gets focus without user intervention 0827 if (time == -1U) { 0828 time = window->userTime(); 0829 } 0830 const FSP::Level level = (FSP::Level)window->rules()->checkFSP(options->focusStealingPreventionLevel()); 0831 if (workspace()->sessionManager()->state() == SessionState::Saving && level <= FSP::Medium) { // <= normal 0832 return true; 0833 } 0834 Window *ac = workspace()->mostRecentlyActivatedWindow(); 0835 if (focus_in) { 0836 if (workspace()->inShouldGetFocus(window)) { 0837 return true; // FocusIn was result of KWin's action 0838 } 0839 // Before getting FocusIn, the active Client already 0840 // got FocusOut, and therefore got deactivated. 0841 ac = workspace()->lastActiveWindow(); 0842 } 0843 if (time == 0) { // explicitly asked not to get focus 0844 if (!window->rules()->checkAcceptFocus(false)) { 0845 return false; 0846 } 0847 } 0848 const FSP::Level protection = (FSP::Level)(ac ? ac->rules()->checkFPP(2) : FSP::None); 0849 0850 // stealing is unconditionally allowed (NETWM behavior) 0851 if (level == FSP::None || protection == FSP::None) { 0852 return true; 0853 } 0854 0855 // The active window "grabs" the focus or stealing is generally forbidden 0856 if (level == FSP::Extreme || protection == FSP::Extreme) { 0857 return false; 0858 } 0859 0860 // Desktop switching is only allowed in the "no protection" case 0861 if (!ignore_desktop && !window->isOnCurrentDesktop()) { 0862 return false; // allow only with level == 0 0863 } 0864 0865 // No active window, it's ok to pass focus 0866 // NOTICE that extreme protection needs to be handled before to allow protection on unmanged windows 0867 if (ac == nullptr || ac->isDesktop()) { 0868 qCDebug(KWIN_CORE) << "Activation: No window active, allowing"; 0869 return true; // no active window -> always allow 0870 } 0871 0872 // TODO window urgency -> return true? 0873 0874 // Unconditionally allow intra-window passing around for lower stealing protections 0875 // unless the active window has High interest 0876 if (Window::belongToSameApplication(window, ac, Window::SameApplicationCheck::RelaxedForActive) && protection < FSP::High) { 0877 qCDebug(KWIN_CORE) << "Activation: Belongs to active application"; 0878 return true; 0879 } 0880 0881 if (!window->isOnCurrentDesktop()) { // we allowed explicit self-activation across virtual desktops 0882 return false; // inside a window or if no window was active, but not otherwise 0883 } 0884 0885 // High FPS, not intr-window change. Only allow if the active window has only minor interest 0886 if (level > FSP::Medium && protection > FSP::Low) { 0887 return false; 0888 } 0889 0890 if (time == -1U) { // no time known 0891 qCDebug(KWIN_CORE) << "Activation: No timestamp at all"; 0892 // Only allow for Low protection unless active window has High interest in focus 0893 if (level < FSP::Medium && protection < FSP::High) { 0894 return true; 0895 } 0896 // no timestamp at all, don't activate - because there's also creation timestamp 0897 // done on CreateNotify, this case should happen only in case application 0898 // maps again already used window, i.e. this won't happen after app startup 0899 return false; 0900 } 0901 0902 // Low or medium FSP, usertime comparism is possible 0903 const xcb_timestamp_t user_time = ac->userTime(); 0904 qCDebug(KWIN_CORE) << "Activation, compared:" << window << ":" << time << ":" << user_time 0905 << ":" << (NET::timestampCompare(time, user_time) >= 0); 0906 return NET::timestampCompare(time, user_time) >= 0; // time >= user_time 0907 } 0908 0909 //**************************************** 0910 // Group 0911 //**************************************** 0912 0913 void Group::startupIdChanged() 0914 { 0915 KStartupInfoId asn_id; 0916 KStartupInfoData asn_data; 0917 bool asn_valid = workspace()->checkStartupNotification(leader_wid, asn_id, asn_data); 0918 if (!asn_valid) { 0919 return; 0920 } 0921 if (asn_id.timestamp() != 0 && user_time != -1U 0922 && NET::timestampCompare(asn_id.timestamp(), user_time) > 0) { 0923 user_time = asn_id.timestamp(); 0924 } 0925 } 0926 0927 void Group::updateUserTime(xcb_timestamp_t time) 0928 { 0929 // copy of X11Window::updateUserTime 0930 if (time == XCB_CURRENT_TIME) { 0931 kwinApp()->updateXTime(); 0932 time = xTime(); 0933 } 0934 if (time != -1U 0935 && (user_time == XCB_CURRENT_TIME 0936 || NET::timestampCompare(time, user_time) > 0)) { // time > user_time 0937 user_time = time; 0938 } 0939 } 0940 0941 } // namespace