File indexing completed on 2024-04-28 16:48:39

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