File indexing completed on 2024-04-28 05:30:12

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