File indexing completed on 2024-11-10 04:57:41
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_windows.begin(); it != m_windows.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 if (window->isHiddenByShowDesktop()) { 0293 ++block_focus; 0294 setShowingDesktop(false); 0295 --block_focus; 0296 } 0297 raiseWindow(window); 0298 if (!window->isOnCurrentDesktop()) { 0299 ++block_focus; 0300 switch (options->activationDesktopPolicy()) { 0301 case Options::ActivationDesktopPolicy::SwitchToOtherDesktop: 0302 VirtualDesktopManager::self()->setCurrent(window->desktops().constLast()); 0303 break; 0304 case Options::ActivationDesktopPolicy::BringToCurrentDesktop: 0305 window->enterDesktop(VirtualDesktopManager::self()->currentDesktop()); 0306 break; 0307 case Options::ActivationDesktopPolicy::DoNothing: 0308 break; 0309 } 0310 --block_focus; 0311 } 0312 #if KWIN_BUILD_ACTIVITIES 0313 if (!window->isOnCurrentActivity()) { 0314 ++block_focus; 0315 // DBUS! 0316 // first isn't necessarily best, but it's easiest 0317 m_activities->setCurrent(window->activities().constFirst()); 0318 --block_focus; 0319 } 0320 #endif 0321 if (window->isMinimized()) { 0322 window->setMinimized(false); 0323 } 0324 0325 // ensure the window is really visible - could eg. be a hidden utility window, see bug #348083 0326 window->setHidden(false); 0327 0328 // TODO force should perhaps allow this only if the window already contains the mouse 0329 if (options->focusPolicyIsReasonable() || force) { 0330 requestFocus(window, force); 0331 } 0332 0333 // Don't update user time for windows that have focus stealing workaround. 0334 // As they usually belong to the current active window but fail to provide 0335 // this information, updating their user time would make the user time 0336 // of the currently active window old, and reject further activation for it. 0337 // E.g. typing URL in minicli which will show kio_uiserver dialog (with workaround), 0338 // and then kdesktop shows dialog about SSL certificate. 0339 // This needs also avoiding user creation time in X11Window::readUserTimeMapTimestamp(). 0340 if (X11Window *x11Window = dynamic_cast<X11Window *>(window)) { 0341 // updateUserTime is X11 specific 0342 x11Window->updateUserTime(); 0343 } 0344 0345 m_quickTileCombineTimer->stop(); 0346 } 0347 0348 /** 0349 * Tries to activate the window by asking X for the input focus. This 0350 * function does not perform any show, raise or desktop switching. See 0351 * Workspace::activateWindow() instead. 0352 * 0353 * @see activateWindow 0354 */ 0355 bool Workspace::requestFocus(Window *window, bool force) 0356 { 0357 return takeActivity(window, force ? ActivityFocusForce : ActivityFocus); 0358 } 0359 0360 bool Workspace::takeActivity(Window *window, ActivityFlags flags) 0361 { 0362 // the 'if ( window == m_activeWindow ) return;' optimization mustn't be done here 0363 if (!focusChangeEnabled() && (window != m_activeWindow)) { 0364 flags &= ~ActivityFocus; 0365 } 0366 0367 if (!window) { 0368 focusToNull(); 0369 return true; 0370 } 0371 0372 if (flags & ActivityFocus) { 0373 Window *modal = window->findModal(); 0374 if (modal != nullptr && modal != window) { 0375 if (modal->desktops() != window->desktops()) { 0376 modal->setDesktops(window->desktops()); 0377 } 0378 if (!modal->isShown() && !modal->isMinimized()) { // forced desktop or utility window 0379 activateWindow(modal); // activating a minimized blocked window will unminimize its modal implicitly 0380 } 0381 // if the click was inside the window (i.e. handled is set), 0382 // but it has a modal, there's no need to use handled mode, because 0383 // the modal doesn't get the click anyway 0384 // raising of the original window needs to be still done 0385 if (flags & ActivityRaise) { 0386 raiseWindow(window); 0387 } 0388 window = modal; 0389 } 0390 cancelDelayFocus(); 0391 } 0392 if (!flags.testFlag(ActivityFocusForce) && (window->isDock() || window->isSplash())) { 0393 // toplevel menus and dock windows don't take focus if not forced 0394 // and don't have a flag that they take focus 0395 if (!window->dockWantsInput()) { 0396 flags &= ~ActivityFocus; 0397 } 0398 } 0399 if (window->isShade()) { 0400 if (window->wantsInput() && (flags & ActivityFocus)) { 0401 // window cannot accept focus, but at least the window should be active (window menu, et. al. ) 0402 window->setActive(true); 0403 focusToNull(); 0404 } 0405 flags &= ~ActivityFocus; 0406 } 0407 if (!window->isShown()) { // shouldn't happen, call activateWindow() if needed 0408 qCWarning(KWIN_CORE) << "takeActivity: not shown"; 0409 return false; 0410 } 0411 0412 bool ret = true; 0413 0414 if (flags & ActivityFocus) { 0415 ret &= window->takeFocus(); 0416 } 0417 if (flags & ActivityRaise) { 0418 workspace()->raiseWindow(window); 0419 } 0420 0421 if (!window->isOnActiveOutput()) { 0422 setActiveOutput(window->output()); 0423 } 0424 0425 return ret; 0426 } 0427 0428 /** 0429 * Informs the workspace that the window \a window has been hidden. If it 0430 * was the active window (or to-become the active window), 0431 * the workspace activates another one. 0432 * 0433 * @note @p c may already be destroyed. 0434 */ 0435 void Workspace::windowHidden(Window *window) 0436 { 0437 Q_ASSERT(!window->isShown() || !window->isOnCurrentDesktop() || !window->isOnCurrentActivity()); 0438 activateNextWindow(window); 0439 } 0440 0441 Window *Workspace::windowUnderMouse(Output *output) const 0442 { 0443 auto it = stackingOrder().constEnd(); 0444 while (it != stackingOrder().constBegin()) { 0445 auto window = *(--it); 0446 if (!window->isClient()) { 0447 continue; 0448 } 0449 0450 // rule out windows which are not really visible. 0451 // the screen test is rather superfluous for xrandr & twinview since the geometry would differ -> TODO: might be dropped 0452 if (!(window->isShown() && window->isOnCurrentDesktop() && window->isOnCurrentActivity() && window->isOnOutput(output) && !window->isShade())) { 0453 continue; 0454 } 0455 0456 if (exclusiveContains(window->frameGeometry(), Cursors::self()->mouse()->pos())) { 0457 return window; 0458 } 0459 } 0460 return nullptr; 0461 } 0462 0463 // deactivates 'window' and activates next window 0464 bool Workspace::activateNextWindow(Window *window) 0465 { 0466 // if 'c' is not the active or the to-become active one, do nothing 0467 if (!(window == m_activeWindow || (should_get_focus.count() > 0 && window == should_get_focus.last()))) { 0468 return false; 0469 } 0470 0471 closeActivePopup(); 0472 0473 if (window != nullptr) { 0474 if (window == m_activeWindow) { 0475 setActiveWindow(nullptr); 0476 } 0477 should_get_focus.removeAll(window); 0478 } 0479 0480 // if blocking focus, move focus to the desktop later if needed 0481 // in order to avoid flickering 0482 if (!focusChangeEnabled()) { 0483 focusToNull(); 0484 return true; 0485 } 0486 0487 if (!options->focusPolicyIsReasonable()) { 0488 return false; 0489 } 0490 0491 Window *focusCandidate = nullptr; 0492 0493 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop(); 0494 0495 if (!focusCandidate && showingDesktop()) { 0496 focusCandidate = findDesktop(true, desktop); // to not break the state 0497 } 0498 0499 if (!focusCandidate && options->isNextFocusPrefersMouse()) { 0500 focusCandidate = windowUnderMouse(window ? window->output() : workspace()->activeOutput()); 0501 if (focusCandidate && (focusCandidate == window || focusCandidate->isDesktop())) { 0502 // should rather not happen, but it cannot get the focus. rest of usability is tested above 0503 focusCandidate = nullptr; 0504 } 0505 } 0506 0507 if (!focusCandidate) { // no suitable window under the mouse -> find sth. else 0508 // first try to pass the focus to the (former) active clients leader 0509 if (window && window->isTransient()) { 0510 auto leaders = window->mainWindows(); 0511 if (leaders.count() == 1 && m_focusChain->isUsableFocusCandidate(leaders.at(0), window)) { 0512 focusCandidate = leaders.at(0); 0513 raiseWindow(focusCandidate); // also raise - we don't know where it came from 0514 } 0515 } 0516 if (!focusCandidate) { 0517 // nope, ask the focus chain for the next candidate 0518 focusCandidate = m_focusChain->nextForDesktop(window, desktop); 0519 } 0520 } 0521 0522 if (focusCandidate == nullptr) { // last chance: focus the desktop 0523 focusCandidate = findDesktop(true, desktop); 0524 } 0525 0526 if (focusCandidate != nullptr) { 0527 requestFocus(focusCandidate); 0528 } else { 0529 focusToNull(); 0530 } 0531 0532 return true; 0533 } 0534 0535 void Workspace::switchToOutput(Output *output) 0536 { 0537 if (!options->focusPolicyIsReasonable()) { 0538 return; 0539 } 0540 closeActivePopup(); 0541 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop(); 0542 Window *get_focus = m_focusChain->getForActivation(desktop, output); 0543 if (get_focus == nullptr) { 0544 get_focus = findDesktop(true, desktop); 0545 } 0546 if (get_focus != nullptr && get_focus != mostRecentlyActivatedWindow()) { 0547 requestFocus(get_focus); 0548 } 0549 setActiveOutput(output); 0550 } 0551 0552 void Workspace::gotFocusIn(const Window *window) 0553 { 0554 if (should_get_focus.contains(window)) { 0555 // remove also all sooner elements that should have got FocusIn, 0556 // but didn't for some reason (and also won't anymore, because they were sooner) 0557 while (should_get_focus.first() != window) { 0558 should_get_focus.pop_front(); 0559 } 0560 should_get_focus.pop_front(); // remove 'window' 0561 } 0562 } 0563 0564 void Workspace::setShouldGetFocus(Window *window) 0565 { 0566 should_get_focus.append(window); 0567 updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active 0568 } 0569 0570 // basically the same like allowWindowActivation(), this time allowing 0571 // a window to be fully raised upon its own request (XRaiseWindow), 0572 // if refused, it will be raised only on top of windows belonging 0573 // to the same application 0574 bool Workspace::allowFullClientRaising(const KWin::Window *window, xcb_timestamp_t time) 0575 { 0576 int level = window->rules()->checkFSP(options->focusStealingPreventionLevel()); 0577 if (sessionManager()->state() == SessionState::Saving && level <= 2) { // <= normal 0578 return true; 0579 } 0580 Window *ac = mostRecentlyActivatedWindow(); 0581 if (level == 0) { // none 0582 return true; 0583 } 0584 if (level == 4) { // extreme 0585 return false; 0586 } 0587 if (ac == nullptr || ac->isDesktop()) { 0588 qCDebug(KWIN_CORE) << "Raising: No window active, allowing"; 0589 return true; // no active window -> always allow 0590 } 0591 // TODO window urgency -> return true? 0592 if (Window::belongToSameApplication(window, ac, Window::SameApplicationCheck::RelaxedForActive)) { 0593 qCDebug(KWIN_CORE) << "Raising: Belongs to active application"; 0594 return true; 0595 } 0596 if (level == 3) { // high 0597 return false; 0598 } 0599 xcb_timestamp_t user_time = ac->userTime(); 0600 qCDebug(KWIN_CORE) << "Raising, compared:" << time << ":" << user_time 0601 << ":" << (NET::timestampCompare(time, user_time) >= 0); 0602 return NET::timestampCompare(time, user_time) >= 0; // time >= user_time 0603 } 0604 0605 /** 0606 * Called from X11Window after FocusIn that wasn't initiated by KWin and the window wasn't 0607 * allowed to activate. 0608 * 0609 * Returns @c true if the focus has been restored successfully; otherwise returns @c false. 0610 */ 0611 bool Workspace::restoreFocus() 0612 { 0613 // this updateXTime() is necessary - as FocusIn events don't have 0614 // a timestamp *sigh*, kwin's timestamp would be older than the timestamp 0615 // that was used by whoever caused the focus change, and therefore 0616 // the attempt to restore the focus would fail due to old timestamp 0617 kwinApp()->updateXTime(); 0618 if (should_get_focus.count() > 0) { 0619 return requestFocus(should_get_focus.last()); 0620 } else if (m_lastActiveWindow) { 0621 return requestFocus(m_lastActiveWindow); 0622 } 0623 return true; 0624 } 0625 0626 void Workspace::windowAttentionChanged(Window *window, bool set) 0627 { 0628 if (set) { 0629 attention_chain.removeAll(window); 0630 attention_chain.prepend(window); 0631 } else { 0632 attention_chain.removeAll(window); 0633 } 0634 } 0635 0636 //******************************************** 0637 // Client 0638 //******************************************** 0639 0640 /** 0641 * Updates the user time (time of last action in the active window). 0642 * This is called inside kwin for every action with the window 0643 * that qualifies for user interaction (clicking on it, activate it 0644 * externally, etc.). 0645 */ 0646 void X11Window::updateUserTime(xcb_timestamp_t time) 0647 { 0648 // copied in Group::updateUserTime 0649 if (time == XCB_TIME_CURRENT_TIME) { 0650 kwinApp()->updateXTime(); 0651 time = xTime(); 0652 } 0653 if (time != -1U 0654 && (m_userTime == XCB_TIME_CURRENT_TIME 0655 || NET::timestampCompare(time, m_userTime) > 0)) { // time > user_time 0656 m_userTime = time; 0657 shade_below = nullptr; // do not hover re-shade a window after it got interaction 0658 } 0659 group()->updateUserTime(m_userTime); 0660 } 0661 0662 xcb_timestamp_t X11Window::readUserCreationTime() const 0663 { 0664 Xcb::Property prop(false, window(), atoms->kde_net_wm_user_creation_time, XCB_ATOM_CARDINAL, 0, 1); 0665 return prop.value<xcb_timestamp_t>(-1); 0666 } 0667 0668 xcb_timestamp_t X11Window::readUserTimeMapTimestamp(const KStartupInfoId *asn_id, const KStartupInfoData *asn_data, 0669 bool session) const 0670 { 0671 xcb_timestamp_t time = info->userTime(); 0672 // qDebug() << "User timestamp, initial:" << time; 0673 //^^ this deadlocks kwin --replace sometimes. 0674 0675 // newer ASN timestamp always replaces user timestamp, unless user timestamp is 0 0676 // helps e.g. with konqy reusing 0677 if (asn_data != nullptr && time != 0) { 0678 if (asn_id->timestamp() != 0 0679 && (time == -1U || NET::timestampCompare(asn_id->timestamp(), time) > 0)) { 0680 time = asn_id->timestamp(); 0681 } 0682 } 0683 qCDebug(KWIN_CORE) << "User timestamp, ASN:" << time; 0684 if (time == -1U) { 0685 // The window doesn't have any timestamp. 0686 // If it's the first window for its application 0687 // (i.e. there's no other window from the same app), 0688 // use the _KDE_NET_WM_USER_CREATION_TIME trick. 0689 // Otherwise, refuse activation of a window 0690 // from already running application if this application 0691 // is not the active one (unless focus stealing prevention is turned off). 0692 X11Window *act = dynamic_cast<X11Window *>(workspace()->mostRecentlyActivatedWindow()); 0693 if (act != nullptr && !belongToSameApplication(act, this, SameApplicationCheck::RelaxedForActive)) { 0694 bool first_window = true; 0695 auto sameApplicationActiveHackPredicate = [this](const X11Window *cl) { 0696 // ignore already existing splashes, toolbars, utilities and menus, 0697 // as the app may show those before the main window 0698 return !cl->isSplash() && !cl->isToolbar() && !cl->isUtility() && !cl->isMenu() 0699 && cl != this && X11Window::belongToSameApplication(cl, this, SameApplicationCheck::RelaxedForActive); 0700 }; 0701 if (isTransient()) { 0702 auto clientMainClients = [this]() { 0703 QList<X11Window *> ret; 0704 const auto mcs = mainWindows(); 0705 for (auto mc : mcs) { 0706 if (X11Window *c = dynamic_cast<X11Window *>(mc)) { 0707 ret << c; 0708 } 0709 } 0710 return ret; 0711 }; 0712 if (act->hasTransient(this, true)) { 0713 ; // is transient for currently active window, even though it's not 0714 // the same app (e.g. kcookiejar dialog) -> allow activation 0715 } else if (groupTransient() && findInList<X11Window, X11Window>(clientMainClients(), sameApplicationActiveHackPredicate) == nullptr) { 0716 ; // standalone transient 0717 } else { 0718 first_window = false; 0719 } 0720 } else { 0721 if (workspace()->findClient(sameApplicationActiveHackPredicate)) { 0722 first_window = false; 0723 } 0724 } 0725 // don't refuse if focus stealing prevention is turned off 0726 if (!first_window && rules()->checkFSP(options->focusStealingPreventionLevel()) > 0) { 0727 qCDebug(KWIN_CORE) << "User timestamp, already exists:" << 0; 0728 return 0; // refuse activation 0729 } 0730 } 0731 // Creation time would just mess things up during session startup, 0732 // as possibly many apps are started up at the same time. 0733 // If there's no active window yet, no timestamp will be needed, 0734 // as plain Workspace::allowWindowActivation() will return true 0735 // in such case. And if there's already active window, 0736 // it's better not to activate the new one. 0737 // Unless it was the active window at the time 0738 // of session saving and there was no user interaction yet, 0739 // this check will be done in manage(). 0740 if (session) { 0741 return -1U; 0742 } 0743 time = readUserCreationTime(); 0744 } 0745 qCDebug(KWIN_CORE) << "User timestamp, final:" << this << ":" << time; 0746 return time; 0747 } 0748 0749 xcb_timestamp_t X11Window::userTime() const 0750 { 0751 xcb_timestamp_t time = m_userTime; 0752 if (time == 0) { // doesn't want focus after showing 0753 return 0; 0754 } 0755 Q_ASSERT(group() != nullptr); 0756 if (time == -1U 0757 || (group()->userTime() != -1U 0758 && NET::timestampCompare(group()->userTime(), time) > 0)) { 0759 time = group()->userTime(); 0760 } 0761 return time; 0762 } 0763 0764 void X11Window::doSetActive() 0765 { 0766 updateUrgency(); // demand attention again if it's still urgent 0767 info->setState(isActive() ? NET::Focused : NET::States(), NET::Focused); 0768 } 0769 0770 void X11Window::startupIdChanged() 0771 { 0772 KStartupInfoId asn_id; 0773 KStartupInfoData asn_data; 0774 bool asn_valid = workspace()->checkStartupNotification(window(), asn_id, asn_data); 0775 if (!asn_valid) { 0776 return; 0777 } 0778 // If the ASN contains desktop, move it to the desktop, otherwise move it to the current 0779 // desktop (since the new ASN should make the window act like if it's a new application 0780 // launched). However don't affect the window's desktop if it's set to be on all desktops. 0781 0782 if (asn_data.desktop() != 0 && !isOnAllDesktops()) { 0783 if (asn_data.desktop() == -1) { 0784 workspace()->sendWindowToDesktops(this, {}, true); 0785 } else { 0786 if (VirtualDesktop *desktop = VirtualDesktopManager::self()->desktopForX11Id(asn_data.desktop())) { 0787 workspace()->sendWindowToDesktops(this, {desktop}, true); 0788 } 0789 } 0790 } 0791 0792 if (asn_data.xinerama() != -1) { 0793 Output *output = workspace()->xineramaIndexToOutput(asn_data.xinerama()); 0794 if (output) { 0795 workspace()->sendWindowToOutput(this, output); 0796 } 0797 } 0798 const xcb_timestamp_t timestamp = asn_id.timestamp(); 0799 if (timestamp != 0) { 0800 bool activate = allowWindowActivation(timestamp); 0801 if (activate) { 0802 workspace()->activateWindow(this); 0803 } else { 0804 demandAttention(); 0805 } 0806 } 0807 } 0808 0809 void X11Window::updateUrgency() 0810 { 0811 if (info->urgency()) { 0812 demandAttention(); 0813 } 0814 } 0815 0816 namespace FSP 0817 { 0818 enum Level { 0819 None = 0, 0820 Low, 0821 Medium, 0822 High, 0823 Extreme, 0824 }; 0825 } 0826 0827 // focus_in -> the window got FocusIn event 0828 bool X11Window::allowWindowActivation(xcb_timestamp_t time, bool focus_in) 0829 { 0830 auto window = this; 0831 // options->focusStealingPreventionLevel : 0832 // 0 - none - old KWin behaviour, new windows always get focus 0833 // 1 - low - focus stealing prevention is applied normally, when unsure, activation is allowed 0834 // 2 - normal - focus stealing prevention is applied normally, when unsure, activation is not allowed, 0835 // this is the default 0836 // 3 - high - new window gets focus only if it belongs to the active application, 0837 // or when no window is currently active 0838 // 4 - extreme - no window gets focus without user intervention 0839 if (time == -1U) { 0840 time = window->userTime(); 0841 } 0842 const FSP::Level level = (FSP::Level)window->rules()->checkFSP(options->focusStealingPreventionLevel()); 0843 if (workspace()->sessionManager()->state() == SessionState::Saving && level <= FSP::Medium) { // <= normal 0844 return true; 0845 } 0846 Window *ac = workspace()->mostRecentlyActivatedWindow(); 0847 if (focus_in) { 0848 if (workspace()->inShouldGetFocus(window)) { 0849 return true; // FocusIn was result of KWin's action 0850 } 0851 // Before getting FocusIn, the active Client already 0852 // got FocusOut, and therefore got deactivated. 0853 ac = workspace()->lastActiveWindow(); 0854 } 0855 if (time == 0) { // explicitly asked not to get focus 0856 if (!window->rules()->checkAcceptFocus(false)) { 0857 return false; 0858 } 0859 } 0860 const FSP::Level protection = (FSP::Level)(ac ? ac->rules()->checkFPP(2) : FSP::None); 0861 0862 // stealing is unconditionally allowed (NETWM behavior) 0863 if (level == FSP::None || protection == FSP::None) { 0864 return true; 0865 } 0866 0867 // The active window "grabs" the focus or stealing is generally forbidden 0868 if (level == FSP::Extreme || protection == FSP::Extreme) { 0869 return false; 0870 } 0871 0872 // No active window, it's ok to pass focus 0873 // NOTICE that extreme protection needs to be handled before to allow protection on unmanged windows 0874 if (ac == nullptr || ac->isDesktop()) { 0875 qCDebug(KWIN_CORE) << "Activation: No window active, allowing"; 0876 return true; // no active window -> always allow 0877 } 0878 0879 // TODO window urgency -> return true? 0880 0881 // Unconditionally allow intra-window passing around for lower stealing protections 0882 // unless the active window has High interest 0883 if (Window::belongToSameApplication(window, ac, Window::SameApplicationCheck::RelaxedForActive) && protection < FSP::High) { 0884 qCDebug(KWIN_CORE) << "Activation: Belongs to active application"; 0885 return true; 0886 } 0887 0888 // High FPS, not intr-window change. Only allow if the active window has only minor interest 0889 if (level > FSP::Medium && protection > FSP::Low) { 0890 return false; 0891 } 0892 0893 if (time == -1U) { // no time known 0894 qCDebug(KWIN_CORE) << "Activation: No timestamp at all"; 0895 // Only allow for Low protection unless active window has High interest in focus 0896 if (level < FSP::Medium && protection < FSP::High) { 0897 return true; 0898 } 0899 // no timestamp at all, don't activate - because there's also creation timestamp 0900 // done on CreateNotify, this case should happen only in case application 0901 // maps again already used window, i.e. this won't happen after app startup 0902 return false; 0903 } 0904 0905 // Low or medium FSP, usertime comparism is possible 0906 const xcb_timestamp_t user_time = ac->userTime(); 0907 qCDebug(KWIN_CORE) << "Activation, compared:" << window << ":" << time << ":" << user_time 0908 << ":" << (NET::timestampCompare(time, user_time) >= 0); 0909 return NET::timestampCompare(time, user_time) >= 0; // time >= user_time 0910 } 0911 0912 //**************************************** 0913 // Group 0914 //**************************************** 0915 0916 void Group::startupIdChanged() 0917 { 0918 KStartupInfoId asn_id; 0919 KStartupInfoData asn_data; 0920 bool asn_valid = workspace()->checkStartupNotification(leader_wid, asn_id, asn_data); 0921 if (!asn_valid) { 0922 return; 0923 } 0924 if (asn_id.timestamp() != 0 && user_time != -1U 0925 && NET::timestampCompare(asn_id.timestamp(), user_time) > 0) { 0926 user_time = asn_id.timestamp(); 0927 } 0928 } 0929 0930 void Group::updateUserTime(xcb_timestamp_t time) 0931 { 0932 // copy of X11Window::updateUserTime 0933 if (time == XCB_CURRENT_TIME) { 0934 kwinApp()->updateXTime(); 0935 time = xTime(); 0936 } 0937 if (time != -1U 0938 && (user_time == XCB_CURRENT_TIME 0939 || NET::timestampCompare(time, user_time) > 0)) { // time > user_time 0940 user_time = time; 0941 } 0942 } 0943 0944 } // namespace