1/********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program. If not, see <http://www.gnu.org/licenses/>.
20*********************************************************************/
21
22/*
23
24 This file contains things relevant to window activation and focus
25 stealing prevention.
26
27*/
28
29#include "client.h"
30#include "cursor.h"
31#include "focuschain.h"
32#include "netinfo.h"
33#include "workspace.h"
34#ifdef KWIN_BUILD_ACTIVITIES
35#include "activities.h"
36#endif
37
38#include <fixx11h.h>
39#include <kxerrorhandler.h>
40#include <kstartupinfo.h>
41#include <kstringhandler.h>
42#include <KDE/KLocalizedString>
43
44#include "atoms.h"
45#include "group.h"
46#include "rules.h"
47#include "screens.h"
48#include "useractions.h"
49#include <QX11Info>
50
51namespace KWin
52{
53
54/*
55 Prevention of focus stealing:
56
57 KWin tries to prevent unwanted changes of focus, that would result
58 from mapping a new window. Also, some nasty applications may try
59 to force focus change even in cases when ICCCM 4.2.7 doesn't allow it
60 (e.g. they may try to activate their main window because the user
61 definitely "needs" to see something happened - misusing
62 of QWidget::setActiveWindow() may be such case).
63
64 There are 4 ways how a window may become active:
65 - the user changes the active window (e.g. focus follows mouse, clicking
66 on some window's titlebar) - the change of focus will
67 be done by KWin, so there's nothing to solve in this case
68 - the change of active window will be requested using the _NET_ACTIVE_WINDOW
69 message (handled in RootInfo::changeActiveWindow()) - such requests
70 will be obeyed, because this request is meant mainly for e.g. taskbar
71 asking the WM to change the active window as a result of some user action.
72 Normal applications should use this request only rarely in special cases.
73 See also below the discussion of _NET_ACTIVE_WINDOW_TRANSFER.
74 - the change of active window will be done by performing XSetInputFocus()
75 on a window that's not currently active. ICCCM 4.2.7 describes when
76 the application may perform change of input focus. In order to handle
77 misbehaving applications, KWin will try to detect focus changes to
78 windows that don't belong to currently active application, and restore
79 focus back to the currently active window, instead of activating the window
80 that got focus (unfortunately there's no way to FocusChangeRedirect similar
81 to e.g. SubstructureRedirect, so there will be short time when the focus
82 will be changed). The check itself that's done is
83 Workspace::allowClientActivation() (see below).
84 - a new window will be mapped - this is the most complicated case. If
85 the new window belongs to the currently active application, it may be safely
86 mapped on top and activated. The same if there's no active window,
87 or the active window is the desktop. These checks are done by
88 Workspace::allowClientActivation().
89 Following checks need to compare times. One time is the timestamp
90 of last user action in the currently active window, the other time is
91 the timestamp of the action that originally caused mapping of the new window
92 (e.g. when the application was started). If the first time is newer than
93 the second one, the window will not be activated, as that indicates
94 futher user actions took place after the action leading to this new
95 mapped window. This check is done by Workspace::allowClientActivation().
96 There are several ways how to get the timestamp of action that caused
97 the new mapped window (done in Client::readUserTimeMapTimestamp()) :
98 - the window may have the _NET_WM_USER_TIME property. This way
99 the application may either explicitly request that the window is not
100 activated (by using 0 timestamp), or the property contains the time
101 of last user action in the application.
102 - KWin itself tries to detect time of last user action in every window,
103 by watching KeyPress and ButtonPress events on windows. This way some
104 events may be missed (if they don't propagate to the toplevel window),
105 but it's good as a fallback for applications that don't provide
106 _NET_WM_USER_TIME, and missing some events may at most lead
107 to unwanted focus stealing.
108 - the timestamp may come from application startup notification.
109 Application startup notification, if it exists for the new mapped window,
110 should include time of the user action that caused it.
111 - if there's no timestamp available, it's checked whether the new window
112 belongs to some already running application - if yes, the timestamp
113 will be 0 (i.e. refuse activation)
114 - if the window is from session restored window, the timestamp will
115 be 0 too, unless this application was the active one at the time
116 when the session was saved, in which case the window will be
117 activated if there wasn't any user interaction since the time
118 KWin was started.
119 - as the last resort, the _KDE_NET_USER_CREATION_TIME timestamp
120 is used. For every toplevel window that is created (see CreateNotify
121 handling), this property is set to the at that time current time.
122 Since at this time it's known that the new window doesn't belong
123 to any existing application (better said, the application doesn't
124 have any other window mapped), it is either the very first window
125 of the application, or it is the only window of the application
126 that was hidden before. The latter case is handled by removing
127 the property from windows before withdrawing them, making
128 the timestamp empty for next mapping of the window. In the sooner
129 case, the timestamp will be used. This helps in case when
130 an application is launched without application startup notification,
131 it creates its mainwindow, and starts its initialization (that
132 may possibly take long time). The timestamp used will be older
133 than any user action done after launching this application.
134 - if no timestamp is found at all, the window is activated.
135 The check whether two windows belong to the same application (same
136 process) is done in Client::belongToSameApplication(). Not 100% reliable,
137 but hopefully 99,99% reliable.
138
139 As a somewhat special case, window activation is always enabled when
140 session saving is in progress. When session saving, the session
141 manager allows only one application to interact with the user.
142 Not allowing window activation in such case would result in e.g. dialogs
143 not becoming active, so focus stealing prevention would cause here
144 more harm than good.
145
146 Windows that attempted to become active but KWin prevented this will
147 be marked as demanding user attention. They'll get
148 the _NET_WM_STATE_DEMANDS_ATTENTION state, and the taskbar should mark
149 them specially (blink, etc.). The state will be reset when the window
150 eventually really becomes active.
151
152 There are one more ways how a window can become obstrusive, window stealing
153 focus: By showing above the active window, by either raising itself,
154 or by moving itself on the active desktop.
155 - KWin will refuse raising non-active window above the active one,
156 unless they belong to the same application. Applications shouldn't
157 raise their windows anyway (unless the app wants to raise one
158 of its windows above another of its windows).
159 - KWin activates windows moved to the current desktop (as that seems
160 logical from the user's point of view, after sending the window
161 there directly from KWin, or e.g. using pager). This means
162 applications shouldn't send their windows to another desktop
163 (SELI TODO - but what if they do?)
164
165 Special cases I can think of:
166 - konqueror reusing, i.e. kfmclient tells running Konqueror instance
167 to open new window
168 - without focus stealing prevention - no problem
169 - with ASN (application startup notification) - ASN is forwarded,
170 and because it's newer than the instance's user timestamp,
171 it takes precedence
172 - without ASN - user timestamp needs to be reset, otherwise it would
173 be used, and it's old; moreover this new window mustn't be detected
174 as window belonging to already running application, or it wouldn't
175 be activated - see Client::sameAppWindowRoleMatch() for the (rather ugly)
176 hack
177 - konqueror preloading, i.e. window is created in advance, and kfmclient
178 tells this Konqueror instance to show it later
179 - without focus stealing prevention - no problem
180 - with ASN - ASN is forwarded, and because it's newer than the instance's
181 user timestamp, it takes precedence
182 - without ASN - user timestamp needs to be reset, otherwise it would
183 be used, and it's old; also, creation timestamp is changed to
184 the time the instance starts (re-)initializing the window,
185 this ensures creation timestamp will still work somewhat even in this case
186 - KUniqueApplication - when the window is already visible, and the new instance
187 wants it to activate
188 - without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem
189 - with ASN - ASN is forwarded, and set on the already visible window, KWin
190 treats the window as new with that ASN
191 - without ASN - _NET_ACTIVE_WINDOW as application request is used,
192 and there's no really usable timestamp, only timestamp
193 from the time the (new) application instance was started,
194 so KWin will activate the window *sigh*
195 - the bad thing here is that there's absolutely no chance to recognize
196 the case of starting this KUniqueApp from Konsole (and thus wanting
197 the already visible window to become active) from the case
198 when something started this KUniqueApp without ASN (in which case
199 the already visible window shouldn't become active)
200 - the only solution is using ASN for starting applications, at least silent
201 (i.e. without feedback)
202 - when one application wants to activate another application's window (e.g. KMail
203 activating already running KAddressBook window ?)
204 - without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem
205 - with ASN - can't be here, it's the KUniqueApp case then
206 - without ASN - _NET_ACTIVE_WINDOW as application request should be used,
207 KWin will activate the new window depending on the timestamp and
208 whether it belongs to the currently active application
209
210 _NET_ACTIVE_WINDOW usage:
211 data.l[0]= 1 ->app request
212 = 2 ->pager request
213 = 0 - backwards compatibility
214 data.l[1]= timestamp
215*/
216
217
218//****************************************
219// Workspace
220//****************************************
221
222
223/*!
224 Informs the workspace about the active client, i.e. the client that
225 has the focus (or None if no client has the focus). This functions
226 is called by the client itself that gets focus. It has no other
227 effect than fixing the focus chain and the return value of
228 activeClient(). And of course, to propagate the active client to the
229 world.
230 */
231void Workspace::setActiveClient(Client* c)
232{
233 if (active_client == c)
234 return;
235
236 if (active_popup && active_popup_client != c && set_active_client_recursion == 0)
237 closeActivePopup();
238 if (m_userActionsMenu->hasClient() && !m_userActionsMenu->isMenuClient(c) && set_active_client_recursion == 0) {
239 m_userActionsMenu->close();
240 }
241 StackingUpdatesBlocker blocker(this);
242 ++set_active_client_recursion;
243 updateFocusMousePosition(cursorPos());
244 if (active_client != NULL) {
245 // note that this may call setActiveClient( NULL ), therefore the recursion counter
246 active_client->setActive(false);
247 }
248 active_client = c;
249 Q_ASSERT(c == NULL || c->isActive());
250
251 if (active_client) {
252 last_active_client = active_client;
253 FocusChain::self()->update(active_client, FocusChain::MakeFirst);
254 active_client->demandAttention(false);
255
256 // activating a client can cause a non active fullscreen window to loose the ActiveLayer status on > 1 screens
257 if (screens()->count() > 1) {
258 for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it) {
259 if (*it != active_client && (*it)->layer() == ActiveLayer && (*it)->screen() == active_client->screen()) {
260 updateClientLayer(*it);
261 }
262 }
263 }
264 }
265 pending_take_activity = NULL;
266
267 updateToolWindows(false);
268 if (c)
269 disableGlobalShortcutsForClient(c->rules()->checkDisableGlobalShortcuts(false));
270 else
271 disableGlobalShortcutsForClient(false);
272
273 updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active
274
275 rootInfo()->setActiveWindow(active_client ? active_client->window() : 0);
276
277 emit clientActivated(active_client);
278 --set_active_client_recursion;
279}
280
281/*!
282 Tries to activate the client \a c. This function performs what you
283 expect when clicking the respective entry in a taskbar: showing and
284 raising the client (this may imply switching to the another virtual
285 desktop) and putting the focus onto it. Once X really gave focus to
286 the client window as requested, the client itself will call
287 setActiveClient() and the operation is complete. This may not happen
288 with certain focus policies, though.
289
290 \sa stActiveClient(), requestFocus()
291 */
292void Workspace::activateClient(Client* c, bool force)
293{
294 if (c == NULL) {
295 focusToNull();
296 setActiveClient(NULL);
297 return;
298 }
299 raiseClient(c);
300 if (!c->isOnCurrentDesktop()) {
301 ++block_focus;
302 VirtualDesktopManager::self()->setCurrent(c->desktop());
303 --block_focus;
304 }
305#ifdef KWIN_BUILD_ACTIVITIES
306 if (!c->isOnCurrentActivity()) {
307 ++block_focus;
308 //DBUS!
309 Activities::self()->setCurrent(c->activities().first()); //first isn't necessarily best, but it's easiest
310 --block_focus;
311 }
312#endif
313 if (c->isMinimized())
314 c->unminimize();
315
316// TODO force should perhaps allow this only if the window already contains the mouse
317 if (options->focusPolicyIsReasonable() || force)
318 requestFocus(c, force);
319
320 // Don't update user time for clients that have focus stealing workaround.
321 // As they usually belong to the current active window but fail to provide
322 // this information, updating their user time would make the user time
323 // of the currently active window old, and reject further activation for it.
324 // E.g. typing URL in minicli which will show kio_uiserver dialog (with workaround),
325 // and then kdesktop shows dialog about SSL certificate.
326 // This needs also avoiding user creation time in Client::readUserTimeMapTimestamp().
327 c->updateUserTime();
328}
329
330/*!
331 Tries to activate the client by asking X for the input focus. This
332 function does not perform any show, raise or desktop switching. See
333 Workspace::activateClient() instead.
334
335 \sa Workspace::activateClient()
336 */
337void Workspace::requestFocus(Client* c, bool force)
338{
339 takeActivity(c, ActivityFocus | (force ? ActivityFocusForce : 0), false);
340}
341
342void Workspace::takeActivity(Client* c, int flags, bool handled)
343{
344 // the 'if ( c == active_client ) return;' optimization mustn't be done here
345 if (!focusChangeEnabled() && (c != active_client))
346 flags &= ~ActivityFocus;
347
348 if (!c) {
349 focusToNull();
350 return;
351 }
352
353 if (flags & ActivityFocus) {
354 Client* modal = c->findModal();
355 if (modal != NULL && modal != c) {
356 if (!modal->isOnDesktop(c->desktop())) {
357 modal->setDesktop(c->desktop());
358 if (modal->desktop() != c->desktop()) // forced desktop
359 activateClient(modal);
360 }
361 // if the click was inside the window (i.e. handled is set),
362 // but it has a modal, there's no need to use handled mode, because
363 // the modal doesn't get the click anyway
364 // raising of the original window needs to be still done
365 if (flags & ActivityRaise)
366 raiseClient(c);
367 c = modal;
368 handled = false;
369 }
370 cancelDelayFocus();
371 }
372 if (!(flags & ActivityFocusForce) && (c->isDock() || c->isSplash()))
373 flags &= ~ActivityFocus; // toplevel menus and dock windows don't take focus if not forced
374 if (c->isShade()) {
375 if (c->wantsInput() && (flags & ActivityFocus)) {
376 // client cannot accept focus, but at least the window should be active (window menu, et. al. )
377 c->setActive(true);
378 focusToNull();
379 }
380 flags &= ~ActivityFocus;
381 handled = false; // no point, can't get clicks
382 }
383 if (c->tabGroup() && c->tabGroup()->current() != c)
384 c->tabGroup()->setCurrent(c);
385 if (!c->isShown(true)) { // shouldn't happen, call activateClient() if needed
386 kWarning(1212) << "takeActivity: not shown" ;
387 return;
388 }
389 c->takeActivity(flags, handled);
390 if (!c->isOnActiveScreen())
391 screens()->setCurrent(c->screen());
392}
393
394void Workspace::handleTakeActivity(KWin::Client *c, xcb_timestamp_t /*timestamp*/, int flags)
395{
396 if (pending_take_activity != c) // pending_take_activity is reset when doing restack or activation
397 return;
398 if ((flags & ActivityRaise) != 0)
399 raiseClient(c);
400 if ((flags & ActivityFocus) != 0 && c->isShown(false))
401 c->takeFocus();
402 pending_take_activity = NULL;
403}
404
405/*!
406 Informs the workspace that the client \a c has been hidden. If it
407 was the active client (or to-become the active client),
408 the workspace activates another one.
409
410 \a c may already be destroyed
411 */
412void Workspace::clientHidden(Client* c)
413{
414 assert(!c->isShown(true) || !c->isOnCurrentDesktop() || !c->isOnCurrentActivity());
415 activateNextClient(c);
416}
417
418Client *Workspace::clientUnderMouse(int screen) const
419{
420 ToplevelList::const_iterator it = stackingOrder().constEnd();
421 while (it != stackingOrder().constBegin()) {
422 Client *client = qobject_cast<Client*>(*(--it));
423 if (!client) {
424 continue;
425 }
426
427 // rule out clients which are not really visible.
428 // the screen test is rather superfluous for xrandr & twinview since the geometry would differ -> TODO: might be dropped
429 if (!(client->isShown(false) && client->isOnCurrentDesktop() &&
430 client->isOnCurrentActivity() && client->isOnScreen(screen)))
431 continue;
432
433 if (client->geometry().contains(Cursor::pos())) {
434 return client;
435 }
436 }
437 return 0;
438}
439
440// deactivates 'c' and activates next client
441bool Workspace::activateNextClient(Client* c)
442{
443 // if 'c' is not the active or the to-become active one, do nothing
444 if (!(c == active_client || (should_get_focus.count() > 0 && c == should_get_focus.last())))
445 return false;
446
447 closeActivePopup();
448
449 if (c != NULL) {
450 if (c == active_client)
451 setActiveClient(NULL);
452 should_get_focus.removeAll(c);
453 }
454
455 // if blocking focus, move focus to the desktop later if needed
456 // in order to avoid flickering
457 if (!focusChangeEnabled()) {
458 focusToNull();
459 return true;
460 }
461
462 if (!options->focusPolicyIsReasonable())
463 return false;
464
465 Client* get_focus = NULL;
466
467 // precedence on keeping the current tabgroup active. to the user that's the same window
468 if (c && c->tabGroup() && c->isShown(false)) {
469 if (c == c->tabGroup()->current())
470 c->tabGroup()->activateNext();
471 get_focus = c->tabGroup()->current();
472 if (get_focus == c) // single tab case - should not happen
473 get_focus = NULL;
474 }
475
476 if (!get_focus && options->isNextFocusPrefersMouse()) {
477 get_focus = clientUnderMouse(c ? c->screen() : screens()->current());
478 if (get_focus && (get_focus == c || get_focus->isDesktop())) {
479 // should rather not happen, but it cannot get the focus. rest of usability is tested above
480 get_focus = NULL;
481 }
482 }
483
484 const int desktop = VirtualDesktopManager::self()->current();
485
486 if (!get_focus) { // no suitable window under the mouse -> find sth. else
487 // first try to pass the focus to the (former) active clients leader
488 if (c && (get_focus = c->transientFor()) && FocusChain::self()->isUsableFocusCandidate(get_focus, c)) {
489 raiseClient(get_focus); // also raise - we don't know where it came from
490 } else {
491 // nope, ask the focus chain for the next candidate
492 get_focus = FocusChain::self()->nextForDesktop(c, desktop);
493 }
494 }
495
496 if (get_focus == NULL) // last chance: focus the desktop
497 get_focus = findDesktop(true, desktop);
498
499 if (get_focus != NULL)
500 requestFocus(get_focus);
501 else
502 focusToNull();
503
504 return true;
505
506}
507
508void Workspace::setCurrentScreen(int new_screen)
509{
510 if (new_screen < 0 || new_screen >= screens()->count())
511 return;
512 if (!options->focusPolicyIsReasonable())
513 return;
514 closeActivePopup();
515 const int desktop = VirtualDesktopManager::self()->current();
516 Client *get_focus = FocusChain::self()->getForActivation(desktop, new_screen);
517 if (get_focus == NULL)
518 get_focus = findDesktop(true, desktop);
519 if (get_focus != NULL && get_focus != mostRecentlyActivatedClient())
520 requestFocus(get_focus);
521 screens()->setCurrent(new_screen);
522}
523
524void Workspace::gotFocusIn(const Client* c)
525{
526 if (should_get_focus.contains(const_cast< Client* >(c))) {
527 // remove also all sooner elements that should have got FocusIn,
528 // but didn't for some reason (and also won't anymore, because they were sooner)
529 while (should_get_focus.first() != c)
530 should_get_focus.pop_front();
531 should_get_focus.pop_front(); // remove 'c'
532 }
533}
534
535void Workspace::setShouldGetFocus(Client* c)
536{
537 should_get_focus.append(c);
538 updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active
539}
540
541// focus_in -> the window got FocusIn event
542// ignore_desktop - call comes from _NET_ACTIVE_WINDOW message, don't refuse just because of window
543// is on a different desktop
544bool Workspace::allowClientActivation(const KWin::Client *c, xcb_timestamp_t time, bool focus_in, bool ignore_desktop)
545{
546 // options->focusStealingPreventionLevel :
547 // 0 - none - old KWin behaviour, new windows always get focus
548 // 1 - low - focus stealing prevention is applied normally, when unsure, activation is allowed
549 // 2 - normal - focus stealing prevention is applied normally, when unsure, activation is not allowed,
550 // this is the default
551 // 3 - high - new window gets focus only if it belongs to the active application,
552 // or when no window is currently active
553 // 4 - extreme - no window gets focus without user intervention
554 if (time == -1U)
555 time = c->userTime();
556 int level = c->rules()->checkFSP(options->focusStealingPreventionLevel());
557 if (session_saving && level <= 2) { // <= normal
558 return true;
559 }
560 Client* ac = mostRecentlyActivatedClient();
561 if (focus_in) {
562 if (should_get_focus.contains(const_cast< Client* >(c)))
563 return true; // FocusIn was result of KWin's action
564 // Before getting FocusIn, the active Client already
565 // got FocusOut, and therefore got deactivated.
566 ac = last_active_client;
567 }
568 if (time == 0) // explicitly asked not to get focus
569 return false;
570 if (level == 0) // none
571 return true;
572 if (level == 4) // extreme
573 return false;
574 if (!ignore_desktop && !c->isOnCurrentDesktop())
575 return false; // allow only with level == 0
576 if (ac == NULL || ac->isDesktop()) {
577 kDebug(1212) << "Activation: No client active, allowing";
578 return true; // no active client -> always allow
579 }
580 // TODO window urgency -> return true?
581 if (Client::belongToSameApplication(c, ac, true)) {
582 kDebug(1212) << "Activation: Belongs to active application";
583 return true;
584 }
585 if (level == 3) // high
586 return false;
587 if (time == -1U) { // no time known
588 kDebug(1212) << "Activation: No timestamp at all";
589 if (level == 1) // low
590 return true;
591 // no timestamp at all, don't activate - because there's also creation timestamp
592 // done on CreateNotify, this case should happen only in case application
593 // maps again already used window, i.e. this won't happen after app startup
594 return false;
595 }
596 // level == 2 // normal
597 Time user_time = ac->userTime();
598 kDebug(1212) << "Activation, compared:" << c << ":" << time << ":" << user_time
599 << ":" << (timestampCompare(time, user_time) >= 0) << endl;
600 return timestampCompare(time, user_time) >= 0; // time >= user_time
601}
602
603// basically the same like allowClientActivation(), this time allowing
604// a window to be fully raised upon its own request (XRaiseWindow),
605// if refused, it will be raised only on top of windows belonging
606// to the same application
607bool Workspace::allowFullClientRaising(const KWin::Client *c, xcb_timestamp_t time)
608{
609 int level = c->rules()->checkFSP(options->focusStealingPreventionLevel());
610 if (session_saving && level <= 2) { // <= normal
611 return true;
612 }
613 Client* ac = mostRecentlyActivatedClient();
614 if (level == 0) // none
615 return true;
616 if (level == 4) // extreme
617 return false;
618 if (ac == NULL || ac->isDesktop()) {
619 kDebug(1212) << "Raising: No client active, allowing";
620 return true; // no active client -> always allow
621 }
622 // TODO window urgency -> return true?
623 if (Client::belongToSameApplication(c, ac, true)) {
624 kDebug(1212) << "Raising: Belongs to active application";
625 return true;
626 }
627 if (level == 3) // high
628 return false;
629 xcb_timestamp_t user_time = ac->userTime();
630 kDebug(1212) << "Raising, compared:" << time << ":" << user_time
631 << ":" << (timestampCompare(time, user_time) >= 0) << endl;
632 return timestampCompare(time, user_time) >= 0; // time >= user_time
633}
634
635// called from Client after FocusIn that wasn't initiated by KWin and the client
636// wasn't allowed to activate
637void Workspace::restoreFocus()
638{
639 // this updateXTime() is necessary - as FocusIn events don't have
640 // a timestamp *sigh*, kwin's timestamp would be older than the timestamp
641 // that was used by whoever caused the focus change, and therefore
642 // the attempt to restore the focus would fail due to old timestamp
643 updateXTime();
644 if (should_get_focus.count() > 0)
645 requestFocus(should_get_focus.last());
646 else if (last_active_client)
647 requestFocus(last_active_client);
648}
649
650void Workspace::clientAttentionChanged(Client* c, bool set)
651{
652 if (set) {
653 attention_chain.removeAll(c);
654 attention_chain.prepend(c);
655 } else
656 attention_chain.removeAll(c);
657 emit clientDemandsAttentionChanged(c, set);
658}
659
660//********************************************
661// Client
662//********************************************
663
664/*!
665 Updates the user time (time of last action in the active window).
666 This is called inside kwin for every action with the window
667 that qualifies for user interaction (clicking on it, activate it
668 externally, etc.).
669 */
670void Client::updateUserTime(xcb_timestamp_t time)
671{
672 // copied in Group::updateUserTime
673 if (time == XCB_TIME_CURRENT_TIME)
674 time = xTime();
675 if (time != -1U
676 && (m_userTime == XCB_TIME_CURRENT_TIME
677 || timestampCompare(time, m_userTime) > 0)) { // time > user_time
678 m_userTime = time;
679 shade_below = NULL; // do not hover re-shade a window after it got interaction
680 }
681 group()->updateUserTime(m_userTime);
682}
683
684xcb_timestamp_t Client::readUserCreationTime() const
685{
686 const xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, window(),
687 atoms->kde_net_wm_user_creation_time, XCB_ATOM_CARDINAL, 0, 10000);
688 ScopedCPointer<xcb_get_property_reply_t> property(xcb_get_property_reply(connection(), cookie, NULL));
689 if (property.isNull() || xcb_get_property_value_length(property.data()) == 0) {
690 return -1;
691 }
692 return *(reinterpret_cast<xcb_timestamp_t*>(xcb_get_property_value(property.data())));
693}
694
695void Client::demandAttention(bool set)
696{
697 if (isActive())
698 set = false;
699 if (demands_attention == set)
700 return;
701 demands_attention = set;
702 info->setState(set ? NET::DemandsAttention : 0, NET::DemandsAttention);
703 workspace()->clientAttentionChanged(this, set);
704 emit demandsAttentionChanged();
705}
706
707// TODO I probably shouldn't be lazy here and do it without the macro, so that people can read it
708KWIN_COMPARE_PREDICATE(SameApplicationActiveHackPredicate, Client, const Client*,
709 // ignore already existing splashes, toolbars, utilities and menus,
710 // as the app may show those before the main window
711 !cl->isSplash() && !cl->isToolbar() && !cl->isUtility() && !cl->isMenu()
712 && Client::belongToSameApplication(cl, value, true) && cl != value);
713
714xcb_timestamp_t Client::readUserTimeMapTimestamp(const KStartupInfoId *asn_id, const KStartupInfoData *asn_data,
715 bool session) const
716{
717 xcb_timestamp_t time = info->userTime();
718 //kDebug( 1212 ) << "User timestamp, initial:" << time;
719 //^^ this deadlocks kwin --replace sometimes.
720
721 // newer ASN timestamp always replaces user timestamp, unless user timestamp is 0
722 // helps e.g. with konqy reusing
723 if (asn_data != NULL && time != 0) {
724 if (asn_id->timestamp() != 0
725 && (time == -1U || timestampCompare(asn_id->timestamp(), time) > 0)) {
726 time = asn_id->timestamp();
727 }
728 }
729 kDebug(1212) << "User timestamp, ASN:" << time;
730 if (time == -1U) {
731 // The window doesn't have any timestamp.
732 // If it's the first window for its application
733 // (i.e. there's no other window from the same app),
734 // use the _KDE_NET_WM_USER_CREATION_TIME trick.
735 // Otherwise, refuse activation of a window
736 // from already running application if this application
737 // is not the active one (unless focus stealing prevention is turned off).
738 Client* act = workspace()->mostRecentlyActivatedClient();
739 if (act != NULL && !belongToSameApplication(act, this, true)) {
740 bool first_window = true;
741 if (isTransient()) {
742 if (act->hasTransient(this, true))
743 ; // is transient for currently active window, even though it's not
744 // the same app (e.g. kcookiejar dialog) -> allow activation
745 else if (groupTransient() &&
746 findClientInList(mainClients(), SameApplicationActiveHackPredicate(this)) == NULL)
747 ; // standalone transient
748 else
749 first_window = false;
750 } else {
751 if (workspace()->findClient(SameApplicationActiveHackPredicate(this)))
752 first_window = false;
753 }
754 // don't refuse if focus stealing prevention is turned off
755 if (!first_window && rules()->checkFSP(options->focusStealingPreventionLevel()) > 0) {
756 kDebug(1212) << "User timestamp, already exists:" << 0;
757 return 0; // refuse activation
758 }
759 }
760 // Creation time would just mess things up during session startup,
761 // as possibly many apps are started up at the same time.
762 // If there's no active window yet, no timestamp will be needed,
763 // as plain Workspace::allowClientActivation() will return true
764 // in such case. And if there's already active window,
765 // it's better not to activate the new one.
766 // Unless it was the active window at the time
767 // of session saving and there was no user interaction yet,
768 // this check will be done in manage().
769 if (session)
770 return -1U;
771 time = readUserCreationTime();
772 }
773 kDebug(1212) << "User timestamp, final:" << this << ":" << time;
774 return time;
775}
776
777xcb_timestamp_t Client::userTime() const
778{
779 xcb_timestamp_t time = m_userTime;
780 if (time == 0) // doesn't want focus after showing
781 return 0;
782 assert(group() != NULL);
783 if (time == -1U
784 || (group()->userTime() != -1U
785 && timestampCompare(group()->userTime(), time) > 0))
786 time = group()->userTime();
787 return time;
788}
789
790/*!
791 Sets the client's active state to \a act.
792
793 This function does only change the visual appearance of the client,
794 it does not change the focus setting. Use
795 Workspace::activateClient() or Workspace::requestFocus() instead.
796
797 If a client receives or looses the focus, it calls setActive() on
798 its own.
799
800 */
801void Client::setActive(bool act)
802{
803 if (active == act)
804 return;
805 active = act;
806 const int ruledOpacity = active
807 ? rules()->checkOpacityActive(qRound(opacity() * 100.0))
808 : rules()->checkOpacityInactive(qRound(opacity() * 100.0));
809 setOpacity(ruledOpacity / 100.0);
810 workspace()->setActiveClient(act ? this : NULL);
811
812 if (!active)
813 cancelAutoRaise();
814
815 if (!active && shade_mode == ShadeActivated)
816 setShade(ShadeNormal);
817
818 StackingUpdatesBlocker blocker(workspace());
819 workspace()->updateClientLayer(this); // active windows may get different layer
820 ClientList mainclients = mainClients();
821 for (ClientList::ConstIterator it = mainclients.constBegin();
822 it != mainclients.constEnd();
823 ++it)
824 if ((*it)->isFullScreen()) // fullscreens go high even if their transient is active
825 workspace()->updateClientLayer(*it);
826 emit activeChanged();
827 updateMouseGrab();
828 updateUrgency(); // demand attention again if it's still urgent
829}
830
831void Client::startupIdChanged()
832{
833 KStartupInfoId asn_id;
834 KStartupInfoData asn_data;
835 bool asn_valid = workspace()->checkStartupNotification(window(), asn_id, asn_data);
836 if (!asn_valid)
837 return;
838 // If the ASN contains desktop, move it to the desktop, otherwise move it to the current
839 // desktop (since the new ASN should make the window act like if it's a new application
840 // launched). However don't affect the window's desktop if it's set to be on all desktops.
841 int desktop = VirtualDesktopManager::self()->current();
842 if (asn_data.desktop() != 0)
843 desktop = asn_data.desktop();
844 if (!isOnAllDesktops())
845 workspace()->sendClientToDesktop(this, desktop, true);
846 if (asn_data.xinerama() != -1)
847 workspace()->sendClientToScreen(this, asn_data.xinerama());
848 Time timestamp = asn_id.timestamp();
849 if (timestamp != 0) {
850 bool activate = workspace()->allowClientActivation(this, timestamp);
851 if (asn_data.desktop() != 0 && !isOnCurrentDesktop())
852 activate = false; // it was started on different desktop than current one
853 if (activate)
854 workspace()->activateClient(this);
855 else
856 demandAttention();
857 }
858}
859
860void Client::updateUrgency()
861{
862 if (urgency)
863 demandAttention();
864}
865
866void Client::shortcutActivated()
867{
868 workspace()->activateClient(this, true); // force
869}
870
871//****************************************
872// Group
873//****************************************
874
875void Group::startupIdChanged()
876{
877 KStartupInfoId asn_id;
878 KStartupInfoData asn_data;
879 bool asn_valid = workspace()->checkStartupNotification(leader_wid, asn_id, asn_data);
880 if (!asn_valid)
881 return;
882 if (asn_id.timestamp() != -1U && user_time != -1U
883 && timestampCompare(asn_id.timestamp(), user_time) > 0) {
884 user_time = asn_id.timestamp();
885 }
886}
887
888void Group::updateUserTime(Time time)
889{
890 // copy of Client::updateUserTime
891 if (time == CurrentTime)
892 time = xTime();
893 if (time != -1U
894 && (user_time == CurrentTime
895 || timestampCompare(time, user_time) > 0)) // time > user_time
896 user_time = time;
897}
898
899} // namespace
900