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 }
00455
00456
00457
00458 bool Workspace::allowClientActivation( const Client* c, Time time, bool focus_in )
00459 {
00460
00461
00462
00463
00464
00465
00466
00467
00468 if( time == -1U )
00469 time = c->userTime();
00470 int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
00471 if( session_saving && level <= 2 )
00472 {
00473 return true;
00474 }
00475 Client* ac = mostRecentlyActivatedClient();
00476 if( focus_in )
00477 {
00478 if( should_get_focus.contains( const_cast< Client* >( c )))
00479 return true;
00480
00481
00482 ac = last_active_client;
00483 }
00484 if( time == 0 )
00485 return false;
00486 if( level == 0 )
00487 return true;
00488 if( level == 4 )
00489 return false;
00490 if( !c->isOnCurrentDesktop())
00491 return false;
00492 if( c->ignoreFocusStealing())
00493 return true;
00494 if( ac == NULL || ac->isDesktop())
00495 {
00496 kdDebug( 1212 ) << "Activation: No client active, allowing" << endl;
00497 return true;
00498 }
00499
00500 if( Client::belongToSameApplication( c, ac, true ))
00501 {
00502 kdDebug( 1212 ) << "Activation: Belongs to active application" << endl;
00503 return true;
00504 }
00505 if( level == 3 )
00506 return false;
00507 if( time == -1U )
00508 {
00509 kdDebug( 1212 ) << "Activation: No timestamp at all" << endl;
00510 if( level == 1 )
00511 return true;
00512
00513
00514
00515 return false;
00516 }
00517
00518 Time user_time = ac->userTime();
00519 kdDebug( 1212 ) << "Activation, compared:" << c << ":" << time << ":" << user_time
00520 << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
00521 return timestampCompare( time, user_time ) >= 0;
00522 }
00523
00524
00525
00526
00527
00528 bool Workspace::allowFullClientRaising( const Client* c, Time time )
00529 {
00530 int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
00531 if( session_saving && level <= 2 )
00532 {
00533 return true;
00534 }
00535 Client* ac = mostRecentlyActivatedClient();
00536 if( level == 0 )
00537 return true;
00538 if( level == 4 )
00539 return false;
00540 if( ac == NULL || ac->isDesktop())
00541 {
00542 kdDebug( 1212 ) << "Raising: No client active, allowing" << endl;
00543 return true;
00544 }
00545 if( c->ignoreFocusStealing())
00546 return true;
00547
00548 if( Client::belongToSameApplication( c, ac, true ))
00549 {
00550 kdDebug( 1212 ) << "Raising: Belongs to active application" << endl;
00551 return true;
00552 }
00553 if( level == 3 )
00554 return false;
00555 Time user_time = ac->userTime();
00556 kdDebug( 1212 ) << "Raising, compared:" << time << ":" << user_time
00557 << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
00558 return timestampCompare( time, user_time ) >= 0;
00559 }
00560
00561
00562
00563 void Workspace::restoreFocus()
00564 {
00565
00566
00567
00568
00569 updateXTime();
00570 if( should_get_focus.count() > 0 )
00571 requestFocus( should_get_focus.last());
00572 else if( last_active_client )
00573 requestFocus( last_active_client );
00574 }
00575
00576 void Workspace::clientAttentionChanged( Client* c, bool set )
00577 {
00578 if( set )
00579 {
00580 attention_chain.remove( c );
00581 attention_chain.prepend( c );
00582 }
00583 else
00584 attention_chain.remove( c );
00585 }
00586
00587
00588
00589
00590 bool Workspace::fakeRequestedActivity( Client* c )
00591 {
00592 if( should_get_focus.count() > 0 && should_get_focus.last() == c )
00593 {
00594 if( c->isActive())
00595 return false;
00596 c->setActive( true );
00597 return true;
00598 }
00599 return false;
00600 }
00601
00602 void Workspace::unfakeActivity( Client* c )
00603 {
00604 if( should_get_focus.count() > 0 && should_get_focus.last() == c )
00605 {
00606 if( last_active_client != NULL )
00607 last_active_client->setActive( true );
00608 else
00609 c->setActive( false );
00610 }
00611 }
00612
00613
00614
00615
00616
00617
00624 void Client::updateUserTime( Time time )
00625 {
00626 if( time == CurrentTime )
00627 time = qt_x_time;
00628 if( time != -1U
00629 && ( user_time == CurrentTime
00630 || timestampCompare( time, user_time ) > 0 ))
00631 user_time = time;
00632 }
00633
00634 Time Client::readUserCreationTime() const
00635 {
00636 long result = -1;
00637 Atom type;
00638 int format, status;
00639 unsigned long nitems = 0;
00640 unsigned long extra = 0;
00641 unsigned char *data = 0;
00642 KXErrorHandler handler;
00643 status = XGetWindowProperty( qt_xdisplay(), window(),
00644 atoms->kde_net_wm_user_creation_time, 0, 10000, FALSE, XA_CARDINAL,
00645 &type, &format, &nitems, &extra, &data );
00646 if (status == Success )
00647 {
00648 if (data && nitems > 0)
00649 result = *((long*) data);
00650 XFree(data);
00651 }
00652 return result;
00653 }
00654
00655 void Client::demandAttention( bool set )
00656 {
00657 if( isActive())
00658 set = false;
00659 info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
00660 workspace()->clientAttentionChanged( this, set );
00661 }
00662
00663
00664 KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, const Client*,
00665
00666
00667 !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu()
00668 && Client::belongToSameApplication( cl, value, true ) && cl != value);
00669
00670 Time Client::readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
00671 bool session ) const
00672 {
00673 Time time = info->userTime();
00674 kdDebug( 1212 ) << "User timestamp, initial:" << time << endl;
00675
00676
00677 if( asn_data != NULL && time != 0 )
00678 {
00679
00680 if( asn_id->timestamp() != 0
00681 && ( time == -1U || timestampCompare( asn_id->timestamp(), time ) > 0 ))
00682 {
00683 time = asn_id->timestamp();
00684 }
00685 else if( asn_data->timestamp() != -1U
00686 && ( time == -1U || timestampCompare( asn_data->timestamp(), time ) > 0 ))
00687 {
00688 time = asn_data->timestamp();
00689 }
00690 }
00691 kdDebug( 1212 ) << "User timestamp, ASN:" << time << endl;
00692 if( time == -1U )
00693 {
00694
00695
00696
00697
00698
00699
00700 Client* act = workspace()->mostRecentlyActivatedClient();
00701 if( act != NULL && !belongToSameApplication( act, this, true ))
00702 {
00703 bool first_window = true;
00704 if( isTransient())
00705 {
00706 if( act->hasTransient( this, true ))
00707 ;
00708
00709 else if( groupTransient() &&
00710 findClientInList( mainClients(), SameApplicationActiveHackPredicate( this )) == NULL )
00711 ;
00712 else
00713 first_window = false;
00714 }
00715 else
00716 {
00717 if( workspace()->findClient( SameApplicationActiveHackPredicate( this )))
00718 first_window = false;
00719 }
00720
00721 if( !first_window && rules()->checkFSP( options->focusStealingPreventionLevel ) > 0 )
00722 {
00723 kdDebug( 1212 ) << "User timestamp, already exists:" << 0 << endl;
00724 return 0;
00725 }
00726 }
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736 if( session )
00737 return -1U;
00738 if( ignoreFocusStealing() && act != NULL )
00739 time = act->userTime();
00740 else
00741 time = readUserCreationTime();
00742 }
00743 kdDebug( 1212 ) << "User timestamp, final:" << this << ":" << time << endl;
00744 return time;
00745 }
00746
00747 Time Client::userTime() const
00748 {
00749 Time time = user_time;
00750 if( time == 0 )
00751 return 0;
00752 assert( group() != NULL );
00753 if( time == -1U
00754 || ( group()->userTime() != -1U
00755 && timestampCompare( group()->userTime(), time ) > 0 ))
00756 time = group()->userTime();
00757 return time;
00758 }
00759
00771 void Client::setActive( bool act)
00772 {
00773 if ( active == act )
00774 return;
00775 active = act;
00776 workspace()->setActiveClient( act ? this : NULL, Allowed );
00777
00778 if ( active )
00779 Notify::raise( Notify::Activate );
00780
00781 if( !active )
00782 cancelAutoRaise();
00783
00784 if( !active && shade_mode == ShadeActivated )
00785 setShade( ShadeNormal );
00786
00787 StackingUpdatesBlocker blocker( workspace());
00788 workspace()->updateClientLayer( this );
00789
00790 ClientList mainclients = mainClients();
00791 for( ClientList::ConstIterator it = mainclients.begin();
00792 it != mainclients.end();
00793 ++it )
00794 if( (*it)->isFullScreen())
00795 workspace()->updateClientLayer( *it );
00796 if( decoration != NULL )
00797 decoration->activeChange();
00798 updateMouseGrab();
00799 updateUrgency();
00800 }
00801
00802 void Client::startupIdChanged()
00803 {
00804 KStartupInfoId asn_id;
00805 KStartupInfoData asn_data;
00806 bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data );
00807 if( !asn_valid )
00808 return;
00809 if( asn_data.desktop() != 0 )
00810 workspace()->sendClientToDesktop( this, asn_data.desktop(), true );
00811 Time timestamp = asn_id.timestamp();
00812 if( timestamp == 0 && asn_data.timestamp() != -1U )
00813 timestamp = asn_data.timestamp();
00814 if( timestamp != 0 )
00815 {
00816 bool activate = workspace()->allowClientActivation( this, asn_data.timestamp());
00817 if( asn_data.desktop() != 0 && !isOnCurrentDesktop())
00818 activate = false;
00819 if( activate )
00820 workspace()->activateClient( this );
00821 else
00822 demandAttention();
00823 }
00824 }
00825
00826 void Client::updateUrgency()
00827 {
00828 if( urgency )
00829 demandAttention();
00830 }
00831
00832
00833
00834
00835
00836 void Group::startupIdChanged()
00837 {
00838 KStartupInfoId asn_id;
00839 KStartupInfoData asn_data;
00840 bool asn_valid = workspace()->checkStartupNotification( leader_wid, asn_id, asn_data );
00841 if( !asn_valid )
00842 return;
00843 if( asn_id.timestamp() != 0 && user_time != -1U
00844 && timestampCompare( asn_id.timestamp(), user_time ) > 0 )
00845 {
00846 user_time = asn_id.timestamp();
00847 }
00848 else if( asn_data.timestamp() != -1U && user_time != -1U
00849 && timestampCompare( asn_data.timestamp(), user_time ) > 0 )
00850 {
00851 user_time = asn_data.timestamp();
00852 }
00853 }
00854
00855 void Group::updateUserTime( Time time )
00856 {
00857 if( time == CurrentTime )
00858 time = qt_x_time;
00859 if( time != -1U
00860 && ( user_time == CurrentTime
00861 || timestampCompare( time, user_time ) > 0 ))
00862 user_time = time;
00863 }
00864
00865 }