not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kwin / activation.cpp
bloba92cd36db3c14c3272f62c719d7afdc4bd79ed1d
1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *********************************************************************/
24 This file contains things relevant to window activation and focus
25 stealing prevention.
29 #include "client.h"
30 #include "workspace.h"
32 #include <fixx11h.h>
33 #include <kxerrorhandler.h>
34 #include <kstartupinfo.h>
35 #include <kstringhandler.h>
36 #include <klocale.h>
38 #include "notifications.h"
39 #include "atoms.h"
40 #include "group.h"
41 #include "rules.h"
42 #include "effects.h"
43 #include <QX11Info>
45 namespace KWin
49 Prevention of focus stealing:
51 KWin tries to prevent unwanted changes of focus, that would result
52 from mapping a new window. Also, some nasty applications may try
53 to force focus change even in cases when ICCCM 4.2.7 doesn't allow it
54 (e.g. they may try to activate their main window because the user
55 definitely "needs" to see something happened - misusing
56 of QWidget::setActiveWindow() may be such case).
58 There are 4 ways how a window may become active:
59 - the user changes the active window (e.g. focus follows mouse, clicking
60 on some window's titlebar) - the change of focus will
61 be done by KWin, so there's nothing to solve in this case
62 - the change of active window will be requested using the _NET_ACTIVE_WINDOW
63 message (handled in RootInfo::changeActiveWindow()) - such requests
64 will be obeyed, because this request is meant mainly for e.g. taskbar
65 asking the WM to change the active window as a result of some user action.
66 Normal applications should use this request only rarely in special cases.
67 See also below the discussion of _NET_ACTIVE_WINDOW_TRANSFER.
68 - the change of active window will be done by performing XSetInputFocus()
69 on a window that's not currently active. ICCCM 4.2.7 describes when
70 the application may perform change of input focus. In order to handle
71 misbehaving applications, KWin will try to detect focus changes to
72 windows that don't belong to currently active application, and restore
73 focus back to the currently active window, instead of activating the window
74 that got focus (unfortunately there's no way to FocusChangeRedirect similar
75 to e.g. SubstructureRedirect, so there will be short time when the focus
76 will be changed). The check itself that's done is
77 Workspace::allowClientActivation() (see below).
78 - a new window will be mapped - this is the most complicated case. If
79 the new window belongs to the currently active application, it may be safely
80 mapped on top and activated. The same if there's no active window,
81 or the active window is the desktop. These checks are done by
82 Workspace::allowClientActivation().
83 Following checks need to compare times. One time is the timestamp
84 of last user action in the currently active window, the other time is
85 the timestamp of the action that originally caused mapping of the new window
86 (e.g. when the application was started). If the first time is newer than
87 the second one, the window will not be activated, as that indicates
88 futher user actions took place after the action leading to this new
89 mapped window. This check is done by Workspace::allowClientActivation().
90 There are several ways how to get the timestamp of action that caused
91 the new mapped window (done in Client::readUserTimeMapTimestamp()) :
92 - the window may have the _NET_WM_USER_TIME property. This way
93 the application may either explicitly request that the window is not
94 activated (by using 0 timestamp), or the property contains the time
95 of last user action in the application.
96 - KWin itself tries to detect time of last user action in every window,
97 by watching KeyPress and ButtonPress events on windows. This way some
98 events may be missed (if they don't propagate to the toplevel window),
99 but it's good as a fallback for applications that don't provide
100 _NET_WM_USER_TIME, and missing some events may at most lead
101 to unwanted focus stealing.
102 - the timestamp may come from application startup notification.
103 Application startup notification, if it exists for the new mapped window,
104 should include time of the user action that caused it.
105 - if there's no timestamp available, it's checked whether the new window
106 belongs to some already running application - if yes, the timestamp
107 will be 0 (i.e. refuse activation)
108 - if the window is from session restored window, the timestamp will
109 be 0 too, unless this application was the active one at the time
110 when the session was saved, in which case the window will be
111 activated if there wasn't any user interaction since the time
112 KWin was started.
113 - as the last resort, the _KDE_NET_USER_CREATION_TIME timestamp
114 is used. For every toplevel window that is created (see CreateNotify
115 handling), this property is set to the at that time current time.
116 Since at this time it's known that the new window doesn't belong
117 to any existing application (better said, the application doesn't
118 have any other window mapped), it is either the very first window
119 of the application, or its the only window of the application
120 that was hidden before. The latter case is handled by removing
121 the property from windows before withdrawing them, making
122 the timestamp empty for next mapping of the window. In the sooner
123 case, the timestamp will be used. This helps in case when
124 an application is launched without application startup notification,
125 it creates its mainwindow, and starts its initialization (that
126 may possibly take long time). The timestamp used will be older
127 than any user action done after launching this application.
128 - if no timestamp is found at all, the window is activated.
129 The check whether two windows belong to the same application (same
130 process) is done in Client::belongToSameApplication(). Not 100% reliable,
131 but hopefully 99,99% reliable.
133 As a somewhat special case, window activation is always enabled when
134 session saving is in progress. When session saving, the session
135 manager allows only one application to interact with the user.
136 Not allowing window activation in such case would result in e.g. dialogs
137 not becoming active, so focus stealing prevention would cause here
138 more harm than good.
140 Windows that attempted to become active but KWin prevented this will
141 be marked as demanding user attention. They'll get
142 the _NET_WM_STATE_DEMANDS_ATTENTION state, and the taskbar should mark
143 them specially (blink, etc.). The state will be reset when the window
144 eventually really becomes active.
146 There are one more ways how a window can become obstrusive, window stealing
147 focus: By showing above the active window, by either raising itself,
148 or by moving itself on the active desktop.
149 - KWin will refuse raising non-active window above the active one,
150 unless they belong to the same application. Applications shouldn't
151 raise their windows anyway (unless the app wants to raise one
152 of its windows above another of its windows).
153 - KWin activates windows moved to the current desktop (as that seems
154 logical from the user's point of view, after sending the window
155 there directly from KWin, or e.g. using pager). This means
156 applications shouldn't send their windows to another desktop
157 (SELI TODO - but what if they do?)
159 Special cases I can think of:
160 - konqueror reusing, i.e. kfmclient tells running Konqueror instance
161 to open new window
162 - without focus stealing prevention - no problem
163 - with ASN (application startup notification) - ASN is forwarded,
164 and because it's newer than the instance's user timestamp,
165 it takes precedence
166 - without ASN - user timestamp needs to be reset, otherwise it would
167 be used, and it's old; moreover this new window mustn't be detected
168 as window belonging to already running application, or it wouldn't
169 be activated - see Client::sameAppWindowRoleMatch() for the (rather ugly)
170 hack
171 - konqueror preloading, i.e. window is created in advance, and kfmclient
172 tells this Konqueror instance to show it later
173 - without focus stealing prevention - no problem
174 - with ASN - ASN is forwarded, and because it's newer than the instance's
175 user timestamp, it takes precedence
176 - without ASN - user timestamp needs to be reset, otherwise it would
177 be used, and it's old; also, creation timestamp is changed to
178 the time the instance starts (re-)initializing the window,
179 this ensures creation timestamp will still work somewhat even in this case
180 - KUniqueApplication - when the window is already visible, and the new instance
181 wants it to activate
182 - without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem
183 - with ASN - ASN is forwarded, and set on the already visible window, KWin
184 treats the window as new with that ASN
185 - without ASN - _NET_ACTIVE_WINDOW as application request is used,
186 and there's no really usable timestamp, only timestamp
187 from the time the (new) application instance was started,
188 so KWin will activate the window *sigh*
189 - the bad thing here is that there's absolutely no chance to recognize
190 the case of starting this KUniqueApp from Konsole (and thus wanting
191 the already visible window to become active) from the case
192 when something started this KUniqueApp without ASN (in which case
193 the already visible window shouldn't become active)
194 - the only solution is using ASN for starting applications, at least silent
195 (i.e. without feedback)
196 - when one application wants to activate another application's window (e.g. KMail
197 activating already running KAddressBook window ?)
198 - without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem
199 - with ASN - can't be here, it's the KUniqueApp case then
200 - without ASN - _NET_ACTIVE_WINDOW as application request should be used,
201 KWin will activate the new window depending on the timestamp and
202 whether it belongs to the currently active application
204 _NET_ACTIVE_WINDOW usage:
205 data.l[0]= 1 ->app request
206 = 2 ->pager request
207 = 0 - backwards compatibility
208 data.l[1]= timestamp
212 //****************************************
213 // Workspace
214 //****************************************
218 Informs the workspace about the active client, i.e. the client that
219 has the focus (or None if no client has the focus). This functions
220 is called by the client itself that gets focus. It has no other
221 effect than fixing the focus chain and the return value of
222 activeClient(). And of course, to propagate the active client to the
223 world.
225 void Workspace::setActiveClient( Client* c, allowed_t )
227 if ( active_client == c )
228 return;
229 if( active_popup && active_popup_client != c && set_active_client_recursion == 0 )
230 closeActivePopup();
231 StackingUpdatesBlocker blocker( this );
232 ++set_active_client_recursion;
233 updateFocusMousePosition( cursorPos());
234 if( active_client != NULL )
235 { // note that this may call setActiveClient( NULL ), therefore the recursion counter
236 active_client->setActive( false );
238 active_client = c;
239 Q_ASSERT( c == NULL || c->isActive());
240 if( active_client != NULL )
241 last_active_client = active_client;
242 if ( active_client )
244 updateFocusChains( active_client, FocusChainMakeFirst );
245 active_client->demandAttention( false );
247 pending_take_activity = NULL;
249 updateCurrentTopMenu();
250 updateToolWindows( false );
251 if( c )
252 disableGlobalShortcutsForClient( c->rules()->checkDisableGlobalShortcuts( false ));
253 else
254 disableGlobalShortcutsForClient( false );
256 updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active
258 rootInfo->setActiveWindow( active_client? active_client->window() : 0 );
259 updateColormap();
260 if( effects )
261 static_cast<EffectsHandlerImpl*>(effects)->windowActivated( active_client ? active_client->effectWindow() : NULL );
262 --set_active_client_recursion;
266 Tries to activate the client \a c. This function performs what you
267 expect when clicking the respective entry in a taskbar: showing and
268 raising the client (this may imply switching to the another virtual
269 desktop) and putting the focus onto it. Once X really gave focus to
270 the client window as requested, the client itself will call
271 setActiveClient() and the operation is complete. This may not happen
272 with certain focus policies, though.
274 \sa stActiveClient(), requestFocus()
276 void Workspace::activateClient( Client* c, bool force )
278 if( c == NULL )
280 focusToNull();
281 setActiveClient( NULL, Allowed );
282 return;
284 raiseClient( c );
285 if (!c->isOnDesktop(currentDesktop()) )
287 ++block_focus;
288 setCurrentDesktop( c->desktop() );
289 --block_focus;
291 if( c->isMinimized())
292 c->unminimize();
294 // TODO force should perhaps allow this only if the window already contains the mouse
295 if( options->focusPolicyIsReasonable() || force )
296 requestFocus( c, force );
298 // Don't update user time for clients that have focus stealing workaround.
299 // As they usually belong to the current active window but fail to provide
300 // this information, updating their user time would make the user time
301 // of the currently active window old, and reject further activation for it.
302 // E.g. typing URL in minicli which will show kio_uiserver dialog (with workaround),
303 // and then kdesktop shows dialog about SSL certificate.
304 // This needs also avoiding user creation time in Client::readUserTimeMapTimestamp().
305 if( !c->ignoreFocusStealing())
306 c->updateUserTime();
310 Tries to activate the client by asking X for the input focus. This
311 function does not perform any show, raise or desktop switching. See
312 Workspace::activateClient() instead.
314 \sa Workspace::activateClient()
316 void Workspace::requestFocus( Client* c, bool force )
318 takeActivity( c, ActivityFocus | ( force ? ActivityFocusForce : 0 ), false);
321 void Workspace::takeActivity( Client* c, int flags, bool handled )
323 // the 'if( c == active_client ) return;' optimization mustn't be done here
324 if (!focusChangeEnabled() && ( c != active_client) )
325 flags &= ~ActivityFocus;
327 if ( !c )
329 focusToNull();
330 return;
333 if( flags & ActivityFocus )
335 Client* modal = c->findModal();
336 if( modal != NULL && modal != c )
338 if( !modal->isOnDesktop( c->desktop()))
340 modal->setDesktop( c->desktop());
341 if( modal->desktop() != c->desktop()) // forced desktop
342 activateClient( modal );
344 // if the click was inside the window (i.e. handled is set),
345 // but it has a modal, there's no need to use handled mode, because
346 // the modal doesn't get the click anyway
347 // raising of the original window needs to be still done
348 if( flags & ActivityRaise )
349 raiseClient( c );
350 c = modal;
351 handled = false;
353 cancelDelayFocus();
355 if ( !( flags & ActivityFocusForce ) && ( c->isTopMenu() || c->isDock() || c->isSplash()) )
356 flags &= ~ActivityFocus; // toplevel menus and dock windows don't take focus if not forced
357 if( c->isShade())
359 if( c->wantsInput() && ( flags & ActivityFocus ))
361 // client cannot accept focus, but at least the window should be active (window menu, et. al. )
362 c->setActive( true );
363 focusToNull();
365 flags &= ~ActivityFocus;
366 handled = false; // no point, can't get clicks
368 if( !c->isShown( true )) // shouldn't happen, call activateClient() if needed
370 kWarning( 1212 ) << "takeActivity: not shown" ;
371 return;
373 c->takeActivity( flags, handled, Allowed );
374 if( !c->isOnScreen( active_screen ))
375 active_screen = c->screen();
378 void Workspace::handleTakeActivity( Client* c, Time /*timestamp*/, int flags )
380 if( pending_take_activity != c ) // pending_take_activity is reset when doing restack or activation
381 return;
382 if(( flags & ActivityRaise ) != 0 )
383 raiseClient( c );
384 if(( flags & ActivityFocus ) != 0 && c->isShown( false ))
385 c->takeFocus( Allowed );
386 pending_take_activity = NULL;
390 Informs the workspace that the client \a c has been hidden. If it
391 was the active client (or to-become the active client),
392 the workspace activates another one.
394 \a c may already be destroyed
396 void Workspace::clientHidden( Client* c )
398 assert( !c->isShown( true ) || !c->isOnCurrentDesktop());
399 activateNextClient( c );
402 // deactivates 'c' and activates next client
403 bool Workspace::activateNextClient( Client* c )
405 // if 'c' is not the active or the to-become active one, do nothing
406 if( !( c == active_client
407 || ( should_get_focus.count() > 0 && c == should_get_focus.last())))
408 return false;
409 closeActivePopup();
410 if( c != NULL )
412 if( c == active_client )
413 setActiveClient( NULL, Allowed );
414 should_get_focus.removeAll( c );
416 if( focusChangeEnabled())
418 if ( options->focusPolicyIsReasonable())
419 { // search the focus_chain for a client to transfer focus to,
420 // first try to transfer focus to the first suitable window in the group
421 Client* get_focus = NULL;
422 const ClientList windows = ( c != NULL ? c->group()->members() : ClientList());
423 for ( int i = focus_chain[ currentDesktop() ].size() - 1;
424 i >= 0;
425 --i )
427 Client* ci = focus_chain[ currentDesktop() ].at( i );
428 if( c == ci || !ci->isShown( false )
429 || !ci->isOnCurrentDesktop())
430 continue;
431 if( options->separateScreenFocus )
433 if( c != NULL && !ci->isOnScreen( c->screen()))
434 continue;
435 if( c == NULL && !ci->isOnScreen( activeScreen()))
436 continue;
438 if( windows.contains( ci ))
440 get_focus = ci;
441 break;
443 if( get_focus == NULL )
444 get_focus = ci;
446 if( get_focus == NULL )
447 get_focus = findDesktop( true, currentDesktop());
448 if( get_focus != NULL )
449 requestFocus( get_focus );
450 else
451 focusToNull();
453 else
454 return false;
456 else
457 // if blocking focus, move focus to the desktop later if needed
458 // in order to avoid flickering
459 focusToNull();
460 return true;
463 void Workspace::setCurrentScreen( int new_screen )
465 if (new_screen < 0 || new_screen > numScreens())
466 return;
467 if ( !options->focusPolicyIsReasonable())
468 return;
469 closeActivePopup();
470 Client* get_focus = NULL;
471 for( int i = focus_chain[ currentDesktop() ].count() - 1;
472 i >= 0;
473 --i )
475 Client* ci = focus_chain[ currentDesktop() ].at( i );
476 if( !ci->isShown( false ) || !ci->isOnCurrentDesktop())
477 continue;
478 if( !ci->screen() == new_screen )
479 continue;
480 get_focus = ci;
481 break;
483 if( get_focus == NULL )
484 get_focus = findDesktop( true, currentDesktop());
485 if( get_focus != NULL && get_focus != mostRecentlyActivatedClient())
486 requestFocus( get_focus );
487 active_screen = new_screen;
490 void Workspace::gotFocusIn( const Client* c )
492 if( should_get_focus.contains( const_cast< Client* >( c )))
493 { // remove also all sooner elements that should have got FocusIn,
494 // but didn't for some reason (and also won't anymore, because they were sooner)
495 while( should_get_focus.first() != c )
496 should_get_focus.pop_front();
497 should_get_focus.pop_front(); // remove 'c'
501 void Workspace::setShouldGetFocus( Client* c )
503 should_get_focus.append( c );
504 updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active
507 // focus_in -> the window got FocusIn event
508 // ignore_desktop - call comes from _NET_ACTIVE_WINDOW message, don't refuse just because of window
509 // is on a different desktop
510 bool Workspace::allowClientActivation( const Client* c, Time time, bool focus_in, bool ignore_desktop )
512 // options->focusStealingPreventionLevel :
513 // 0 - none - old KWin behaviour, new windows always get focus
514 // 1 - low - focus stealing prevention is applied normally, when unsure, activation is allowed
515 // 2 - normal - focus stealing prevention is applied normally, when unsure, activation is not allowed,
516 // this is the default
517 // 3 - high - new window gets focus only if it belongs to the active application,
518 // or when no window is currently active
519 // 4 - extreme - no window gets focus without user intervention
520 if( time == -1U )
521 time = c->userTime();
522 int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
523 if( session_saving && level <= 2 ) // <= normal
525 return true;
527 Client* ac = mostRecentlyActivatedClient();
528 if( focus_in )
530 if( should_get_focus.contains( const_cast< Client* >( c )))
531 return true; // FocusIn was result of KWin's action
532 // Before getting FocusIn, the active Client already
533 // got FocusOut, and therefore got deactivated.
534 ac = last_active_client;
536 if( time == 0 ) // explicitly asked not to get focus
537 return false;
538 if( level == 0 ) // none
539 return true;
540 if( level == 4 ) // extreme
541 return false;
542 if( !ignore_desktop && !c->isOnCurrentDesktop())
543 return false; // allow only with level == 0
544 if( c->ignoreFocusStealing())
545 return true;
546 if( ac == NULL || ac->isDesktop())
548 kDebug( 1212 ) << "Activation: No client active, allowing";
549 return true; // no active client -> always allow
551 // TODO window urgency -> return true?
552 if( Client::belongToSameApplication( c, ac, true ))
554 kDebug( 1212 ) << "Activation: Belongs to active application";
555 return true;
557 if( level == 3 ) // high
558 return false;
559 if( time == -1U ) // no time known
561 kDebug( 1212 ) << "Activation: No timestamp at all";
562 if( level == 1 ) // low
563 return true;
564 // no timestamp at all, don't activate - because there's also creation timestamp
565 // done on CreateNotify, this case should happen only in case application
566 // maps again already used window, i.e. this won't happen after app startup
567 return false;
569 // level == 2 // normal
570 Time user_time = ac->userTime();
571 kDebug( 1212 ) << "Activation, compared:" << c << ":" << time << ":" << user_time
572 << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
573 return timestampCompare( time, user_time ) >= 0; // time >= user_time
576 // basically the same like allowClientActivation(), this time allowing
577 // a window to be fully raised upon its own request (XRaiseWindow),
578 // if refused, it will be raised only on top of windows belonging
579 // to the same application
580 bool Workspace::allowFullClientRaising( const Client* c, Time time )
582 int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
583 if( session_saving && level <= 2 ) // <= normal
585 return true;
587 Client* ac = mostRecentlyActivatedClient();
588 if( level == 0 ) // none
589 return true;
590 if( level == 4 ) // extreme
591 return false;
592 if( ac == NULL || ac->isDesktop())
594 kDebug( 1212 ) << "Raising: No client active, allowing";
595 return true; // no active client -> always allow
597 if( c->ignoreFocusStealing())
598 return true;
599 // TODO window urgency -> return true?
600 if( Client::belongToSameApplication( c, ac, true ))
602 kDebug( 1212 ) << "Raising: Belongs to active application";
603 return true;
605 if( level == 3 ) // high
606 return false;
607 Time user_time = ac->userTime();
608 kDebug( 1212 ) << "Raising, compared:" << time << ":" << user_time
609 << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
610 return timestampCompare( time, user_time ) >= 0; // time >= user_time
613 // called from Client after FocusIn that wasn't initiated by KWin and the client
614 // wasn't allowed to activate
615 void Workspace::restoreFocus()
617 // this updateXTime() is necessary - as FocusIn events don't have
618 // a timestamp *sigh*, kwin's timestamp would be older than the timestamp
619 // that was used by whoever caused the focus change, and therefore
620 // the attempt to restore the focus would fail due to old timestamp
621 updateXTime();
622 if( should_get_focus.count() > 0 )
623 requestFocus( should_get_focus.last());
624 else if( last_active_client )
625 requestFocus( last_active_client );
628 void Workspace::clientAttentionChanged( Client* c, bool set )
630 if( set )
632 attention_chain.removeAll( c );
633 attention_chain.prepend( c );
635 else
636 attention_chain.removeAll( c );
639 // This is used when a client should be shown active immediately after requestFocus(),
640 // without waiting for the matching FocusIn that will really make the window the active one.
641 // Used only in special cases, e.g. for MouseActivateRaiseandMove with transparent windows,
642 bool Workspace::fakeRequestedActivity( Client* c )
644 if( should_get_focus.count() > 0 && should_get_focus.last() == c )
646 if( c->isActive())
647 return false;
648 c->setActive( true );
649 return true;
651 return false;
654 void Workspace::unfakeActivity( Client* c )
656 if( should_get_focus.count() > 0 && should_get_focus.last() == c )
657 { // TODO this will cause flicker, and probably is not needed
658 if( last_active_client != NULL )
659 last_active_client->setActive( true );
660 else
661 c->setActive( false );
666 //********************************************
667 // Client
668 //********************************************
671 Updates the user time (time of last action in the active window).
672 This is called inside kwin for every action with the window
673 that qualifies for user interaction (clicking on it, activate it
674 externally, etc.).
676 void Client::updateUserTime( Time time )
677 { // copied in Group::updateUserTime
678 if( time == CurrentTime )
679 time = xTime();
680 if( time != -1U
681 && ( user_time == CurrentTime
682 || timestampCompare( time, user_time ) > 0 )) // time > user_time
683 user_time = time;
684 group()->updateUserTime( user_time );
687 Time Client::readUserCreationTime() const
689 long result = -1; // Time == -1 means none
690 Atom type;
691 int format, status;
692 unsigned long nitems = 0;
693 unsigned long extra = 0;
694 unsigned char *data = 0;
695 KXErrorHandler handler; // ignore errors?
696 status = XGetWindowProperty( display(), window(),
697 atoms->kde_net_wm_user_creation_time, 0, 10000, false, XA_CARDINAL,
698 &type, &format, &nitems, &extra, &data );
699 if (status == Success )
701 if (data && nitems > 0)
702 result = *((long*) data);
703 XFree(data);
705 return result;
708 void Client::demandAttention( bool set )
710 if( isActive())
711 set = false;
712 if( demands_attention == set )
713 return;
714 demands_attention = set;
715 if( demands_attention )
717 // Demand attention flag is often set right from manage(), when focus stealing prevention
718 // steps in. At that time the window has no taskbar entry yet, so KNotify cannot place
719 // e.g. the passive popup next to it. So wait up to 1 second for the icon geometry
720 // to be set.
721 // Delayed call to KNotify also solves the problem of having X server grab in manage(),
722 // which may deadlock when KNotify (or KLauncher when launching KNotify) need to access X.
724 // Setting the demands attention state needs to be done directly in KWin, because
725 // KNotify would try to set it, resulting in a call to KNotify again, etc.
727 info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
729 if( demandAttentionKNotifyTimer == NULL )
731 demandAttentionKNotifyTimer = new QTimer( this );
732 demandAttentionKNotifyTimer->setSingleShot( true );
733 connect( demandAttentionKNotifyTimer, SIGNAL( timeout()), SLOT( demandAttentionKNotify()));
735 demandAttentionKNotifyTimer->start( 1000 );
737 else
738 info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
739 workspace()->clientAttentionChanged( this, set );
742 void Client::demandAttentionKNotify()
744 Notify::Event e = isOnCurrentDesktop() ? Notify::DemandAttentionCurrent : Notify::DemandAttentionOther;
745 Notify::raise( e, i18n( "Window '%1' demands attention.", KStringHandler::csqueeze(caption())), this );
746 demandAttentionKNotifyTimer->stop();
747 demandAttentionKNotifyTimer->deleteLater();
748 demandAttentionKNotifyTimer = NULL;
751 // TODO I probably shouldn't be lazy here and do it without the macro, so that people can read it
752 KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, Client, const Client*,
753 // ignore already existing splashes, toolbars, utilities, menus and topmenus,
754 // as the app may show those before the main window
755 !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu()
756 && Client::belongToSameApplication( cl, value, true ) && cl != value);
758 Time Client::readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
759 bool session ) const
761 Time time = info->userTime();
762 kDebug( 1212 ) << "User timestamp, initial:" << time;
763 // newer ASN timestamp always replaces user timestamp, unless user timestamp is 0
764 // helps e.g. with konqy reusing
765 if( asn_data != NULL && time != 0 )
767 // prefer timestamp from ASN id (timestamp from data is obsolete way)
768 if( asn_id->timestamp() != 0
769 && ( time == -1U || timestampCompare( asn_id->timestamp(), time ) > 0 ))
771 time = asn_id->timestamp();
773 else if( asn_data->timestamp() != -1U
774 && ( time == -1U || timestampCompare( asn_data->timestamp(), time ) > 0 ))
776 time = asn_data->timestamp();
779 kDebug( 1212 ) << "User timestamp, ASN:" << time;
780 if( time == -1U )
781 { // The window doesn't have any timestamp.
782 // If it's the first window for its application
783 // (i.e. there's no other window from the same app),
784 // use the _KDE_NET_WM_USER_CREATION_TIME trick.
785 // Otherwise, refuse activation of a window
786 // from already running application if this application
787 // is not the active one (unless focus stealing prevention is turned off).
788 Client* act = workspace()->mostRecentlyActivatedClient();
789 if( act != NULL && !belongToSameApplication( act, this, true ))
791 bool first_window = true;
792 if( isTransient())
794 if( act->hasTransient( this, true ))
795 ; // is transient for currently active window, even though it's not
796 // the same app (e.g. kcookiejar dialog) -> allow activation
797 else if( groupTransient() &&
798 findClientInList( mainClients(), SameApplicationActiveHackPredicate( this )) == NULL )
799 ; // standalone transient
800 else
801 first_window = false;
803 else
805 if( workspace()->findClient( SameApplicationActiveHackPredicate( this )))
806 first_window = false;
808 // don't refuse if focus stealing prevention is turned off
809 if( !first_window && rules()->checkFSP( options->focusStealingPreventionLevel ) > 0 )
811 kDebug( 1212 ) << "User timestamp, already exists:" << 0;
812 return 0; // refuse activation
815 // Creation time would just mess things up during session startup,
816 // as possibly many apps are started up at the same time.
817 // If there's no active window yet, no timestamp will be needed,
818 // as plain Workspace::allowClientActivation() will return true
819 // in such case. And if there's already active window,
820 // it's better not to activate the new one.
821 // Unless it was the active window at the time
822 // of session saving and there was no user interaction yet,
823 // this check will be done in manage().
824 if( session )
825 return -1U;
826 if( ignoreFocusStealing() && act != NULL )
827 time = act->userTime();
828 else
829 time = readUserCreationTime();
831 kDebug( 1212 ) << "User timestamp, final:" << this << ":" << time;
832 return time;
835 Time Client::userTime() const
837 Time time = user_time;
838 if( time == 0 ) // doesn't want focus after showing
839 return 0;
840 assert( group() != NULL );
841 if( time == -1U
842 || ( group()->userTime() != -1U
843 && timestampCompare( group()->userTime(), time ) > 0 ))
844 time = group()->userTime();
845 return time;
849 Sets the client's active state to \a act.
851 This function does only change the visual appearance of the client,
852 it does not change the focus setting. Use
853 Workspace::activateClient() or Workspace::requestFocus() instead.
855 If a client receives or looses the focus, it calls setActive() on
856 its own.
859 void Client::setActive( bool act )
861 if ( active == act )
862 return;
863 active = act;
864 workspace()->setActiveClient( act ? this : NULL, Allowed );
866 if ( active )
867 Notify::raise( Notify::Activate );
869 if( !active )
870 cancelAutoRaise();
872 if( !active && shade_mode == ShadeActivated )
873 setShade( ShadeNormal );
875 StackingUpdatesBlocker blocker( workspace());
876 workspace()->updateClientLayer( this ); // active windows may get different layer
877 ClientList mainclients = mainClients();
878 for( ClientList::ConstIterator it = mainclients.constBegin();
879 it != mainclients.constEnd();
880 ++it )
881 if( (*it)->isFullScreen()) // fullscreens go high even if their transient is active
882 workspace()->updateClientLayer( *it );
883 if( decoration != NULL )
884 decoration->activeChange();
885 updateMouseGrab();
886 updateUrgency(); // demand attention again if it's still urgent
887 workspace()->checkUnredirect();
890 void Client::startupIdChanged()
892 KStartupInfoId asn_id;
893 KStartupInfoData asn_data;
894 bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data );
895 if( !asn_valid )
896 return;
897 // If the ASN contains desktop, move it to the desktop, otherwise move it to the current
898 // desktop (since the new ASN should make the window act like if it's a new application
899 // launched). However don't affect the window's desktop if it's set to be on all desktops.
900 int desktop = workspace()->currentDesktop();
901 if( asn_data.desktop() != 0 )
902 desktop = asn_data.desktop();
903 if( !isOnAllDesktops())
904 workspace()->sendClientToDesktop( this, desktop, true );
905 if( asn_data.xinerama() != -1 )
906 workspace()->sendClientToScreen( this, asn_data.xinerama());
907 Time timestamp = asn_id.timestamp();
908 if( timestamp == 0 && asn_data.timestamp() != -1U )
909 timestamp = asn_data.timestamp();
910 if( timestamp != 0 )
912 bool activate = workspace()->allowClientActivation( this, timestamp );
913 if( asn_data.desktop() != 0 && !isOnCurrentDesktop())
914 activate = false; // it was started on different desktop than current one
915 if( activate )
916 workspace()->activateClient( this );
917 else
918 demandAttention();
922 void Client::updateUrgency()
924 if( urgency )
925 demandAttention();
928 void Client::shortcutActivated()
930 workspace()->activateClient( this, true ); // force
933 //****************************************
934 // Group
935 //****************************************
937 void Group::startupIdChanged()
939 KStartupInfoId asn_id;
940 KStartupInfoData asn_data;
941 bool asn_valid = workspace()->checkStartupNotification( leader_wid, asn_id, asn_data );
942 if( !asn_valid )
943 return;
944 if( asn_id.timestamp() != 0 && user_time != -1U
945 && timestampCompare( asn_id.timestamp(), user_time ) > 0 )
947 user_time = asn_id.timestamp();
949 else if( asn_data.timestamp() != -1U && user_time != -1U
950 && timestampCompare( asn_data.timestamp(), user_time ) > 0 )
952 user_time = asn_data.timestamp();
956 void Group::updateUserTime( Time time )
957 { // copy of Client::updateUserTime
958 if( time == CurrentTime )
959 time = xTime();
960 if( time != -1U
961 && ( user_time == CurrentTime
962 || timestampCompare( time, user_time ) > 0 )) // time > user_time
963 user_time = time;
966 } // namespace