00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "client.h"
00020 #include "workspace.h"
00021
00022 #include <fixx11h.h>
00023 #include <qpopupmenu.h>
00024 #include <kxerrorhandler.h>
00025 #include <kstartupinfo.h>
00026
00027 #include "notifications.h"
00028 #include "atoms.h"
00029 #include "group.h"
00030 #include "rules.h"
00031
00032 extern Time qt_x_time;
00033
00034 namespace KWinInternal
00035 {
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00214 void Workspace::setActiveClient( Client* c, allowed_t )
00215 {
00216 if ( active_client == c )
00217 return;
00218 if( popup && popup_client != c && set_active_client_recursion == 0 )
00219 {
00220 popup->close();
00221 popup_client = 0;
00222 }
00223 StackingUpdatesBlocker blocker( this );
00224 ++set_active_client_recursion;
00225 if( active_client != NULL )
00226 {
00227 active_client->setActive( false );
00228 }
00229 active_client = c;
00230 Q_ASSERT( c == NULL || c->isActive());
00231 if( active_client != NULL )
00232 last_active_client = active_client;
00233 if ( active_client )
00234 {
00235 focus_chain.remove( c );
00236 if ( c->wantsTabFocus() )
00237 focus_chain.append( c );
00238 active_client->demandAttention( false );
00239 }
00240 pending_take_activity = NULL;
00241
00242 updateCurrentTopMenu();
00243 updateToolWindows( false );
00244
00245 updateStackingOrder();
00246
00247 rootInfo->setActiveWindow( active_client? active_client->window() : 0 );
00248 updateColormap();
00249 --set_active_client_recursion;
00250 }
00251
00263 void Workspace::activateClient( Client* c, bool force )
00264 {
00265 if( c == NULL )
00266 {
00267 setActiveClient( NULL, Allowed );
00268 return;
00269 }
00270 raiseClient( c );
00271 if (!c->isOnDesktop(currentDesktop()) )
00272 {
00273 ++block_focus;
00274 setCurrentDesktop( c->desktop() );
00275 --block_focus;
00276
00277 }
00278 if( c->isMinimized())
00279 c->unminimize();
00280
00281 if( options->focusPolicyIsReasonable())
00282 requestFocus( c, force );
00283
00284
00285
00286
00287
00288
00289
00290
00291 if( !c->ignoreFocusStealing())
00292 c->updateUserTime();
00293 }
00294
00302 void Workspace::requestFocus( Client* c, bool force )
00303 {
00304 takeActivity( c, ActivityFocus | ( force ? ActivityFocusForce : 0 ), false);
00305 }
00306
00307 void Workspace::takeActivity( Client* c, int flags, bool handled )
00308 {
00309
00310 if (!focusChangeEnabled() && ( c != active_client) )
00311 flags &= ~ActivityFocus;
00312
00313 if ( !c )
00314 {
00315 focusToNull();
00316 return;
00317 }
00318
00319 if( flags & ActivityFocus )
00320 {
00321 Client* modal = c->findModal();
00322 if( modal != NULL && modal != c )
00323 {
00324 if( !modal->isOnDesktop( c->desktop()))
00325 {
00326 modal->setDesktop( c->desktop());
00327 if( modal->desktop() != c->desktop())
00328 activateClient( modal );
00329 }
00330
00331
00332
00333
00334 if( flags & ActivityRaise )
00335 raiseClient( c );
00336 flags &= ~ActivityRaise;
00337 c = modal;
00338 handled = false;
00339 }
00340 cancelDelayFocus();
00341 }
00342 if ( !( flags & ActivityFocusForce ) && ( c->isTopMenu() || c->isDock() || c->isSplash()) )
00343 flags &= ~ActivityFocus;
00344 if( c->isShade())
00345 {
00346 if( c->wantsInput() && ( flags & ActivityFocus ))
00347 {
00348
00349 c->setActive( true );
00350 focusToNull();
00351 }
00352 flags &= ~ActivityFocus;
00353 handled = false;
00354 }
00355 if( !c->isShown( true ))
00356 {
00357 kdWarning( 1212 ) << "takeActivity: not shown" << endl;
00358 return;
00359 }
00360 c->takeActivity( flags, handled, Allowed );
00361 }
00362
00363 void Workspace::handleTakeActivity( Client* c, Time , int flags )
00364 {
00365 if( pending_take_activity != c )
00366 return;
00367 if(( flags & ActivityRaise ) != 0 )
00368 raiseClient( c );
00369 if(( flags & ActivityFocus ) != 0 && c->isShown( false ))
00370 c->takeFocus( Allowed );
00371 pending_take_activity = NULL;
00372 }
00373
00381 void Workspace::clientHidden( Client* c )
00382 {
00383 assert( !c->isShown( true ) || !c->isOnCurrentDesktop());
00384 activateNextClient( c );
00385 }
00386
00387
00388 void Workspace::activateNextClient( Client* c )
00389 {
00390
00391 if( !( c == active_client
00392 || ( should_get_focus.count() > 0 && c == should_get_focus.last())))
00393 return;
00394 if( popup )
00395 popup->close();
00396 if( c == active_client )
00397 setActiveClient( NULL, Allowed );
00398 should_get_focus.remove( c );
00399 if( focusChangeEnabled())
00400 {
00401 if ( c->wantsTabFocus() && focus_chain.contains( c ) )
00402 {
00403 focus_chain.remove( c );
00404 focus_chain.prepend( c );
00405 }
00406 if ( options->focusPolicyIsReasonable())
00407 {
00408
00409 Client* get_focus = NULL;
00410 const ClientList mainwindows = c->mainClients();
00411 for( ClientList::ConstIterator it = focus_chain.fromLast();
00412 it != focus_chain.end();
00413 --it )
00414 {
00415 if( !(*it)->isShown( false ) || !(*it)->isOnCurrentDesktop())
00416 continue;
00417 if( mainwindows.contains( *it ))
00418 {
00419 get_focus = *it;
00420 break;
00421 }
00422 if( get_focus == NULL )
00423 get_focus = *it;
00424 }
00425 if( get_focus == NULL )
00426 get_focus = findDesktop( true, currentDesktop());
00427 if( get_focus != NULL )
00428 requestFocus( get_focus );
00429 else
00430 focusToNull();
00431 }
00432 }
00433 else
00434
00435
00436 focusToNull();
00437 }
00438
00439
00440 void Workspace::gotFocusIn( const Client* c )
00441 {
00442 if( should_get_focus.contains( const_cast< Client* >( c )))
00443 {
00444
00445 while( should_get_focus.first() != c )
00446 should_get_focus.pop_front();
00447 should_get_focus.pop_front();
00448 }
00449 }
00450
00451 void Workspace::setShouldGetFocus( Client* c )
00452 {
00453 should_get_focus.append( c );
00454 updateStackingOrder();
00455 }
00456
00457
00458
00459 bool Workspace::allowClientActivation( const Client* c, Time time, bool focus_in )
00460 {
00461
00462
00463
00464
00465
00466
00467
00468
00469 if( time == -1U )
00470 time = c->userTime();
00471 int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
00472 if( session_saving && level <= 2 )
00473 {
00474 return true;
00475 }
00476 Client* ac = mostRecentlyActivatedClient();
00477 if( focus_in )
00478 {
00479 if( should_get_focus.contains( const_cast< Client* >( c )))
00480 return true;
00481
00482
00483 ac = last_active_client;
00484 }
00485 if( time == 0 )
00486 return false;
00487 if( level == 0 )
00488 return true;
00489 if( level == 4 )
00490 return false;
00491 if( !c->isOnCurrentDesktop())
00492 return false;
00493 if( c->ignoreFocusStealing())
00494 return true;
00495 if( ac == NULL || ac->isDesktop())
00496 {
00497 kdDebug( 1212 ) << "Activation: No client active, allowing" << endl;
00498 return true;
00499 }
00500
00501 if( Client::belongToSameApplication( c, ac, true ))
00502 {
00503 kdDebug( 1212 ) << "Activation: Belongs to active application" << endl;
00504 return true;
00505 }
00506 if( level == 3 )
00507 return false;
00508 if( time == -1U )
00509 {
00510 kdDebug( 1212 ) << "Activation: No timestamp at all" << endl;
00511 if( level == 1 )
00512 return true;
00513
00514
00515
00516 return false;
00517 }
00518
00519 Time user_time = ac->userTime();
00520 kdDebug( 1212 ) << "Activation, compared:" << c << ":" << time << ":" << user_time
00521 << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
00522 return timestampCompare( time, user_time ) >= 0;
00523 }
00524
00525
00526
00527
00528
00529 bool Workspace::allowFullClientRaising( const Client* c, Time time )
00530 {
00531 int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
00532 if( session_saving && level <= 2 )
00533 {
00534 return true;
00535 }
00536 Client* ac = mostRecentlyActivatedClient();
00537 if( level == 0 )
00538 return true;
00539 if( level == 4 )
00540 return false;
00541 if( ac == NULL || ac->isDesktop())
00542 {
00543 kdDebug( 1212 ) << "Raising: No client active, allowing" << endl;
00544 return true;
00545 }
00546 if( c->ignoreFocusStealing())
00547 return true;
00548
00549 if( Client::belongToSameApplication( c, ac, true ))
00550 {
00551 kdDebug( 1212 ) << "Raising: Belongs to active application" << endl;
00552 return true;
00553 }
00554 if( level == 3 )
00555 return false;
00556 Time user_time = ac->userTime();
00557 kdDebug( 1212 ) << "Raising, compared:" << time << ":" << user_time
00558 << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
00559 return timestampCompare( time, user_time ) >= 0;
00560 }
00561
00562
00563
00564 void Workspace::restoreFocus()
00565 {
00566
00567
00568
00569
00570 updateXTime();
00571 if( should_get_focus.count() > 0 )
00572 requestFocus( should_get_focus.last());
00573 else if( last_active_client )
00574 requestFocus( last_active_client );
00575 }
00576
00577 void Workspace::clientAttentionChanged( Client* c, bool set )
00578 {
00579 if( set )
00580 {
00581 attention_chain.remove( c );
00582 attention_chain.prepend( c );
00583 }
00584 else
00585 attention_chain.remove( c );
00586 }
00587
00588
00589
00590
00591 bool Workspace::fakeRequestedActivity( Client* c )
00592 {
00593 if( should_get_focus.count() > 0 && should_get_focus.last() == c )
00594 {
00595 if( c->isActive())
00596 return false;
00597 c->setActive( true );
00598 return true;
00599 }
00600 return false;
00601 }
00602
00603 void Workspace::unfakeActivity( Client* c )
00604 {
00605 if( should_get_focus.count() > 0 && should_get_focus.last() == c )
00606 {
00607 if( last_active_client != NULL )
00608 last_active_client->setActive( true );
00609 else
00610 c->setActive( false );
00611 }
00612 }
00613
00614
00615
00616
00617
00618
00625 void Client::updateUserTime( Time time )
00626 {
00627 if( time == CurrentTime )
00628 time = qt_x_time;
00629 if( time != -1U
00630 && ( user_time == CurrentTime
00631 || timestampCompare( time, user_time ) > 0 ))
00632 user_time = time;
00633 }
00634
00635 Time Client::readUserCreationTime() const
00636 {
00637 long result = -1;
00638 Atom type;
00639 int format, status;
00640 unsigned long nitems = 0;
00641 unsigned long extra = 0;
00642 unsigned char *data = 0;
00643 KXErrorHandler handler;
00644 status = XGetWindowProperty( qt_xdisplay(), window(),
00645 atoms->kde_net_wm_user_creation_time, 0, 10000, FALSE, XA_CARDINAL,
00646 &type, &format, &nitems, &extra, &data );
00647 if (status == Success )
00648 {
00649 if (data && nitems > 0)
00650 result = *((long*) data);
00651 XFree(data);
00652 }
00653 return result;
00654 }
00655
00656 void Client::demandAttention( bool set )
00657 {
00658 if( isActive())
00659 set = false;
00660 info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
00661 workspace()->clientAttentionChanged( this, set );
00662 }
00663
00664
00665 KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, const Client*,
00666
00667
00668 !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu()
00669 && Client::belongToSameApplication( cl, value, true ) && cl != value);
00670
00671 Time Client::readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
00672 bool session ) const
00673 {
00674 Time time = info->userTime();
00675 kdDebug( 1212 ) << "User timestamp, initial:" << time << endl;
00676
00677
00678 if( asn_data != NULL && time != 0 )
00679 {
00680
00681 if( asn_id->timestamp() != 0
00682 && ( time == -1U || timestampCompare( asn_id->timestamp(), time ) > 0 ))
00683 {
00684 time = asn_id->timestamp();
00685 }
00686 else if( asn_data->timestamp() != -1U
00687 && ( time == -1U || timestampCompare( asn_data->timestamp(), time ) > 0 ))
00688 {
00689 time = asn_data->timestamp();
00690 }
00691 }
00692 kdDebug( 1212 ) << "User timestamp, ASN:" << time << endl;
00693 if( time == -1U )
00694 {
00695
00696
00697
00698
00699
00700
00701 Client* act = workspace()->mostRecentlyActivatedClient();
00702 if( act != NULL && !belongToSameApplication( act, this, true ))
00703 {
00704 bool first_window = true;
00705 if( isTransient())
00706 {
00707 if( act->hasTransient( this, true ))
00708 ;
00709
00710 else if( groupTransient() &&
00711 findClientInList( mainClients(), SameApplicationActiveHackPredicate( this )) == NULL )
00712 ;
00713 else
00714 first_window = false;
00715 }
00716 else
00717 {
00718 if( workspace()->findClient( SameApplicationActiveHackPredicate( this )))
00719 first_window = false;
00720 }
00721
00722 if( !first_window && rules()->checkFSP( options->focusStealingPreventionLevel ) > 0 )
00723 {
00724 kdDebug( 1212 ) << "User timestamp, already exists:" << 0 << endl;
00725 return 0;
00726 }
00727 }
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737 if( session )
00738 return -1U;
00739 if( ignoreFocusStealing() && act != NULL )
00740 time = act->userTime();
00741 else
00742 time = readUserCreationTime();
00743 }
00744 kdDebug( 1212 ) << "User timestamp, final:" << this << ":" << time << endl;
00745 return time;
00746 }
00747
00748 Time Client::userTime() const
00749 {
00750 Time time = user_time;
00751 if( time == 0 )
00752 return 0;
00753 assert( group() != NULL );
00754 if( time == -1U
00755 || ( group()->userTime() != -1U
00756 && timestampCompare( group()->userTime(), time ) > 0 ))
00757 time = group()->userTime();
00758 return time;
00759 }
00760
00772 void Client::setActive( bool act)
00773 {
00774 if ( active == act )
00775 return;
00776 active = act;
00777 workspace()->setActiveClient( act ? this : NULL, Allowed );
00778
00779 if ( active )
00780 Notify::raise( Notify::Activate );
00781
00782 if( !active )
00783 cancelAutoRaise();
00784
00785 if( !active && shade_mode == ShadeActivated )
00786 setShade( ShadeNormal );
00787
00788 StackingUpdatesBlocker blocker( workspace());
00789 workspace()->updateClientLayer( this );
00790
00791 ClientList mainclients = mainClients();
00792 for( ClientList::ConstIterator it = mainclients.begin();
00793 it != mainclients.end();
00794 ++it )
00795 if( (*it)->isFullScreen())
00796 workspace()->updateClientLayer( *it );
00797 if( decoration != NULL )
00798 decoration->activeChange();
00799 updateMouseGrab();
00800 updateUrgency();
00801 }
00802
00803 void Client::startupIdChanged()
00804 {
00805 KStartupInfoId asn_id;
00806 KStartupInfoData asn_data;
00807 bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data );
00808 if( !asn_valid )
00809 return;
00810 if( asn_data.desktop() != 0 )
00811 workspace()->sendClientToDesktop( this, asn_data.desktop(), true );
00812 Time timestamp = asn_id.timestamp();
00813 if( timestamp == 0 && asn_data.timestamp() != -1U )
00814 timestamp = asn_data.timestamp();
00815 if( timestamp != 0 )
00816 {
00817 bool activate = workspace()->allowClientActivation( this, timestamp );
00818 if( asn_data.desktop() != 0 && !isOnCurrentDesktop())
00819 activate = false;
00820 if( activate )
00821 workspace()->activateClient( this );
00822 else
00823 demandAttention();
00824 }
00825 }
00826
00827 void Client::updateUrgency()
00828 {
00829 if( urgency )
00830 demandAttention();
00831 }
00832
00833
00834
00835
00836
00837 void Group::startupIdChanged()
00838 {
00839 KStartupInfoId asn_id;
00840 KStartupInfoData asn_data;
00841 bool asn_valid = workspace()->checkStartupNotification( leader_wid, asn_id, asn_data );
00842 if( !asn_valid )
00843 return;
00844 if( asn_id.timestamp() != 0 && user_time != -1U
00845 && timestampCompare( asn_id.timestamp(), user_time ) > 0 )
00846 {
00847 user_time = asn_id.timestamp();
00848 }
00849 else if( asn_data.timestamp() != -1U && user_time != -1U
00850 && timestampCompare( asn_data.timestamp(), user_time ) > 0 )
00851 {
00852 user_time = asn_data.timestamp();
00853 }
00854 }
00855
00856 void Group::updateUserTime( Time time )
00857 {
00858 if( time == CurrentTime )
00859 time = qt_x_time;
00860 if( time != -1U
00861 && ( user_time == CurrentTime
00862 || timestampCompare( time, user_time ) > 0 ))
00863 user_time = time;
00864 }
00865
00866 }