00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "client.h"
00030 #include "workspace.h"
00031
00032 #include <fixx11h.h>
00033 #include <kxerrorhandler.h>
00034 #include <kstartupinfo.h>
00035 #include <kstringhandler.h>
00036 #include <klocale.h>
00037
00038 #include "notifications.h"
00039 #include "atoms.h"
00040 #include "group.h"
00041 #include "rules.h"
00042 #include "effects.h"
00043 #include <QX11Info>
00044
00045 namespace KWin
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
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00225 void Workspace::setActiveClient( Client* c, allowed_t )
00226 {
00227 if ( active_client == c )
00228 return;
00229 if( active_popup && active_popup_client != c && set_active_client_recursion == 0 )
00230 closeActivePopup();
00231 StackingUpdatesBlocker blocker( this );
00232 ++set_active_client_recursion;
00233 updateFocusMousePosition( cursorPos());
00234 if( active_client != NULL )
00235 {
00236 active_client->setActive( false );
00237 }
00238 active_client = c;
00239 Q_ASSERT( c == NULL || c->isActive());
00240 if( active_client != NULL )
00241 last_active_client = active_client;
00242 if ( active_client )
00243 {
00244 updateFocusChains( active_client, FocusChainMakeFirst );
00245 active_client->demandAttention( false );
00246 }
00247 pending_take_activity = NULL;
00248
00249 updateCurrentTopMenu();
00250 updateToolWindows( false );
00251 if( c )
00252 disableGlobalShortcutsForClient( c->rules()->checkDisableGlobalShortcuts( false ));
00253 else
00254 disableGlobalShortcutsForClient( false );
00255
00256 updateStackingOrder();
00257
00258 rootInfo->setActiveWindow( active_client? active_client->window() : 0 );
00259 updateColormap();
00260 if( effects )
00261 static_cast<EffectsHandlerImpl*>(effects)->windowActivated( active_client ? active_client->effectWindow() : NULL );
00262 --set_active_client_recursion;
00263 }
00264
00276 void Workspace::activateClient( Client* c, bool force )
00277 {
00278 if( c == NULL )
00279 {
00280 focusToNull();
00281 setActiveClient( NULL, Allowed );
00282 return;
00283 }
00284 raiseClient( c );
00285 if (!c->isOnDesktop(currentDesktop()) )
00286 {
00287 ++block_focus;
00288 setCurrentDesktop( c->desktop() );
00289 --block_focus;
00290 }
00291 if( c->isMinimized())
00292 c->unminimize();
00293
00294
00295 if( options->focusPolicyIsReasonable() || force )
00296 requestFocus( c, force );
00297
00298
00299
00300
00301
00302
00303
00304
00305 if( !c->ignoreFocusStealing())
00306 c->updateUserTime();
00307 }
00308
00316 void Workspace::requestFocus( Client* c, bool force )
00317 {
00318 takeActivity( c, ActivityFocus | ( force ? ActivityFocusForce : 0 ), false);
00319 }
00320
00321 void Workspace::takeActivity( Client* c, int flags, bool handled )
00322 {
00323
00324 if (!focusChangeEnabled() && ( c != active_client) )
00325 flags &= ~ActivityFocus;
00326
00327 if ( !c )
00328 {
00329 focusToNull();
00330 return;
00331 }
00332
00333 if( flags & ActivityFocus )
00334 {
00335 Client* modal = c->findModal();
00336 if( modal != NULL && modal != c )
00337 {
00338 if( !modal->isOnDesktop( c->desktop()))
00339 {
00340 modal->setDesktop( c->desktop());
00341 if( modal->desktop() != c->desktop())
00342 activateClient( modal );
00343 }
00344
00345
00346
00347
00348 if( flags & ActivityRaise )
00349 raiseClient( c );
00350 c = modal;
00351 handled = false;
00352 }
00353 cancelDelayFocus();
00354 }
00355 if ( !( flags & ActivityFocusForce ) && ( c->isTopMenu() || c->isDock() || c->isSplash()) )
00356 flags &= ~ActivityFocus;
00357 if( c->isShade())
00358 {
00359 if( c->wantsInput() && ( flags & ActivityFocus ))
00360 {
00361
00362 c->setActive( true );
00363 focusToNull();
00364 }
00365 flags &= ~ActivityFocus;
00366 handled = false;
00367 }
00368 if( !c->isShown( true ))
00369 {
00370 kWarning( 1212 ) << "takeActivity: not shown" ;
00371 return;
00372 }
00373 c->takeActivity( flags, handled, Allowed );
00374 if( !c->isOnScreen( active_screen ))
00375 active_screen = c->screen();
00376 }
00377
00378 void Workspace::handleTakeActivity( Client* c, Time , int flags )
00379 {
00380 if( pending_take_activity != c )
00381 return;
00382 if(( flags & ActivityRaise ) != 0 )
00383 raiseClient( c );
00384 if(( flags & ActivityFocus ) != 0 && c->isShown( false ))
00385 c->takeFocus( Allowed );
00386 pending_take_activity = NULL;
00387 }
00388
00396 void Workspace::clientHidden( Client* c )
00397 {
00398 assert( !c->isShown( true ) || !c->isOnCurrentDesktop());
00399 activateNextClient( c );
00400 }
00401
00402
00403 bool Workspace::activateNextClient( Client* c )
00404 {
00405
00406 if( !( c == active_client
00407 || ( should_get_focus.count() > 0 && c == should_get_focus.last())))
00408 return false;
00409 closeActivePopup();
00410 if( c != NULL )
00411 {
00412 if( c == active_client )
00413 setActiveClient( NULL, Allowed );
00414 should_get_focus.removeAll( c );
00415 }
00416 if( focusChangeEnabled())
00417 {
00418 if ( options->focusPolicyIsReasonable())
00419 {
00420
00421 Client* get_focus = NULL;
00422 const ClientList windows = ( c != NULL ? c->group()->members() : ClientList());
00423 for ( int i = focus_chain[ currentDesktop() ].size() - 1;
00424 i >= 0;
00425 --i )
00426 {
00427 Client* ci = focus_chain[ currentDesktop() ].at( i );
00428 if( c == ci || !ci->isShown( false )
00429 || !ci->isOnCurrentDesktop())
00430 continue;
00431 if( options->separateScreenFocus )
00432 {
00433 if( c != NULL && !ci->isOnScreen( c->screen()))
00434 continue;
00435 if( c == NULL && !ci->isOnScreen( activeScreen()))
00436 continue;
00437 }
00438 if( windows.contains( ci ))
00439 {
00440 get_focus = ci;
00441 break;
00442 }
00443 if( get_focus == NULL )
00444 get_focus = ci;
00445 }
00446 if( get_focus == NULL )
00447 get_focus = findDesktop( true, currentDesktop());
00448 if( get_focus != NULL )
00449 requestFocus( get_focus );
00450 else
00451 focusToNull();
00452 }
00453 else
00454 return false;
00455 }
00456 else
00457
00458
00459 focusToNull();
00460 return true;
00461 }
00462
00463 void Workspace::setCurrentScreen( int new_screen )
00464 {
00465 if (new_screen < 0 || new_screen > numScreens())
00466 return;
00467 if ( !options->focusPolicyIsReasonable())
00468 return;
00469 closeActivePopup();
00470 Client* get_focus = NULL;
00471 for( int i = focus_chain[ currentDesktop() ].count() - 1;
00472 i >= 0;
00473 --i )
00474 {
00475 Client* ci = focus_chain[ currentDesktop() ].at( i );
00476 if( !ci->isShown( false ) || !ci->isOnCurrentDesktop())
00477 continue;
00478 if( !ci->screen() == new_screen )
00479 continue;
00480 get_focus = ci;
00481 break;
00482 }
00483 if( get_focus == NULL )
00484 get_focus = findDesktop( true, currentDesktop());
00485 if( get_focus != NULL && get_focus != mostRecentlyActivatedClient())
00486 requestFocus( get_focus );
00487 active_screen = new_screen;
00488 }
00489
00490 void Workspace::gotFocusIn( const Client* c )
00491 {
00492 if( should_get_focus.contains( const_cast< Client* >( c )))
00493 {
00494
00495 while( should_get_focus.first() != c )
00496 should_get_focus.pop_front();
00497 should_get_focus.pop_front();
00498 }
00499 }
00500
00501 void Workspace::setShouldGetFocus( Client* c )
00502 {
00503 should_get_focus.append( c );
00504 updateStackingOrder();
00505 }
00506
00507
00508
00509
00510 bool Workspace::allowClientActivation( const Client* c, Time time, bool focus_in, bool ignore_desktop )
00511 {
00512
00513
00514
00515
00516
00517
00518
00519
00520 if( time == -1U )
00521 time = c->userTime();
00522 int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
00523 if( session_saving && level <= 2 )
00524 {
00525 return true;
00526 }
00527 Client* ac = mostRecentlyActivatedClient();
00528 if( focus_in )
00529 {
00530 if( should_get_focus.contains( const_cast< Client* >( c )))
00531 return true;
00532
00533
00534 ac = last_active_client;
00535 }
00536 if( time == 0 )
00537 return false;
00538 if( level == 0 )
00539 return true;
00540 if( level == 4 )
00541 return false;
00542 if( !ignore_desktop && !c->isOnCurrentDesktop())
00543 return false;
00544 if( c->ignoreFocusStealing())
00545 return true;
00546 if( ac == NULL || ac->isDesktop())
00547 {
00548 kDebug( 1212 ) << "Activation: No client active, allowing";
00549 return true;
00550 }
00551
00552 if( Client::belongToSameApplication( c, ac, true ))
00553 {
00554 kDebug( 1212 ) << "Activation: Belongs to active application";
00555 return true;
00556 }
00557 if( level == 3 )
00558 return false;
00559 if( time == -1U )
00560 {
00561 kDebug( 1212 ) << "Activation: No timestamp at all";
00562 if( level == 1 )
00563 return true;
00564
00565
00566
00567 return false;
00568 }
00569
00570 Time user_time = ac->userTime();
00571 kDebug( 1212 ) << "Activation, compared:" << c << ":" << time << ":" << user_time
00572 << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
00573 return timestampCompare( time, user_time ) >= 0;
00574 }
00575
00576
00577
00578
00579
00580 bool Workspace::allowFullClientRaising( const Client* c, Time time )
00581 {
00582 int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
00583 if( session_saving && level <= 2 )
00584 {
00585 return true;
00586 }
00587 Client* ac = mostRecentlyActivatedClient();
00588 if( level == 0 )
00589 return true;
00590 if( level == 4 )
00591 return false;
00592 if( ac == NULL || ac->isDesktop())
00593 {
00594 kDebug( 1212 ) << "Raising: No client active, allowing";
00595 return true;
00596 }
00597 if( c->ignoreFocusStealing())
00598 return true;
00599
00600 if( Client::belongToSameApplication( c, ac, true ))
00601 {
00602 kDebug( 1212 ) << "Raising: Belongs to active application";
00603 return true;
00604 }
00605 if( level == 3 )
00606 return false;
00607 Time user_time = ac->userTime();
00608 kDebug( 1212 ) << "Raising, compared:" << time << ":" << user_time
00609 << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
00610 return timestampCompare( time, user_time ) >= 0;
00611 }
00612
00613
00614
00615 void Workspace::restoreFocus()
00616 {
00617
00618
00619
00620
00621 updateXTime();
00622 if( should_get_focus.count() > 0 )
00623 requestFocus( should_get_focus.last());
00624 else if( last_active_client )
00625 requestFocus( last_active_client );
00626 }
00627
00628 void Workspace::clientAttentionChanged( Client* c, bool set )
00629 {
00630 if( set )
00631 {
00632 attention_chain.removeAll( c );
00633 attention_chain.prepend( c );
00634 }
00635 else
00636 attention_chain.removeAll( c );
00637 }
00638
00639
00640
00641
00642 bool Workspace::fakeRequestedActivity( Client* c )
00643 {
00644 if( should_get_focus.count() > 0 && should_get_focus.last() == c )
00645 {
00646 if( c->isActive())
00647 return false;
00648 c->setActive( true );
00649 return true;
00650 }
00651 return false;
00652 }
00653
00654 void Workspace::unfakeActivity( Client* c )
00655 {
00656 if( should_get_focus.count() > 0 && should_get_focus.last() == c )
00657 {
00658 if( last_active_client != NULL )
00659 last_active_client->setActive( true );
00660 else
00661 c->setActive( false );
00662 }
00663 }
00664
00665
00666
00667
00668
00669
00676 void Client::updateUserTime( Time time )
00677 {
00678 if( time == CurrentTime )
00679 time = xTime();
00680 if( time != -1U
00681 && ( user_time == CurrentTime
00682 || timestampCompare( time, user_time ) > 0 ))
00683 user_time = time;
00684 group()->updateUserTime( user_time );
00685 }
00686
00687 Time Client::readUserCreationTime() const
00688 {
00689 long result = -1;
00690 Atom type;
00691 int format, status;
00692 unsigned long nitems = 0;
00693 unsigned long extra = 0;
00694 unsigned char *data = 0;
00695 KXErrorHandler handler;
00696 status = XGetWindowProperty( display(), window(),
00697 atoms->kde_net_wm_user_creation_time, 0, 10000, false, XA_CARDINAL,
00698 &type, &format, &nitems, &extra, &data );
00699 if (status == Success )
00700 {
00701 if (data && nitems > 0)
00702 result = *((long*) data);
00703 XFree(data);
00704 }
00705 return result;
00706 }
00707
00708 void Client::demandAttention( bool set )
00709 {
00710 if( isActive())
00711 set = false;
00712 if( demands_attention == set )
00713 return;
00714 demands_attention = set;
00715 if( demands_attention )
00716 {
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
00728
00729 if( demandAttentionKNotifyTimer == NULL )
00730 {
00731 demandAttentionKNotifyTimer = new QTimer( this );
00732 demandAttentionKNotifyTimer->setSingleShot( true );
00733 connect( demandAttentionKNotifyTimer, SIGNAL( timeout()), SLOT( demandAttentionKNotify()));
00734 }
00735 demandAttentionKNotifyTimer->start( 1000 );
00736 }
00737 else
00738 info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
00739 workspace()->clientAttentionChanged( this, set );
00740 }
00741
00742 void Client::demandAttentionKNotify()
00743 {
00744 Notify::Event e = isOnCurrentDesktop() ? Notify::DemandAttentionCurrent : Notify::DemandAttentionOther;
00745 Notify::raise( e, i18n( "Window '%1' demands attention.", KStringHandler::csqueeze(caption())), this );
00746 demandAttentionKNotifyTimer->stop();
00747 demandAttentionKNotifyTimer->deleteLater();
00748 demandAttentionKNotifyTimer = NULL;
00749 }
00750
00751
00752 KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, Client, const Client*,
00753
00754
00755 !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu()
00756 && Client::belongToSameApplication( cl, value, true ) && cl != value);
00757
00758 Time Client::readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
00759 bool session ) const
00760 {
00761 Time time = info->userTime();
00762 kDebug( 1212 ) << "User timestamp, initial:" << time;
00763
00764
00765 if( asn_data != NULL && time != 0 )
00766 {
00767
00768 if( asn_id->timestamp() != 0
00769 && ( time == -1U || timestampCompare( asn_id->timestamp(), time ) > 0 ))
00770 {
00771 time = asn_id->timestamp();
00772 }
00773 else if( asn_data->timestamp() != -1U
00774 && ( time == -1U || timestampCompare( asn_data->timestamp(), time ) > 0 ))
00775 {
00776 time = asn_data->timestamp();
00777 }
00778 }
00779 kDebug( 1212 ) << "User timestamp, ASN:" << time;
00780 if( time == -1U )
00781 {
00782
00783
00784
00785
00786
00787
00788 Client* act = workspace()->mostRecentlyActivatedClient();
00789 if( act != NULL && !belongToSameApplication( act, this, true ))
00790 {
00791 bool first_window = true;
00792 if( isTransient())
00793 {
00794 if( act->hasTransient( this, true ))
00795 ;
00796
00797 else if( groupTransient() &&
00798 findClientInList( mainClients(), SameApplicationActiveHackPredicate( this )) == NULL )
00799 ;
00800 else
00801 first_window = false;
00802 }
00803 else
00804 {
00805 if( workspace()->findClient( SameApplicationActiveHackPredicate( this )))
00806 first_window = false;
00807 }
00808
00809 if( !first_window && rules()->checkFSP( options->focusStealingPreventionLevel ) > 0 )
00810 {
00811 kDebug( 1212 ) << "User timestamp, already exists:" << 0;
00812 return 0;
00813 }
00814 }
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824 if( session )
00825 return -1U;
00826 if( ignoreFocusStealing() && act != NULL )
00827 time = act->userTime();
00828 else
00829 time = readUserCreationTime();
00830 }
00831 kDebug( 1212 ) << "User timestamp, final:" << this << ":" << time;
00832 return time;
00833 }
00834
00835 Time Client::userTime() const
00836 {
00837 Time time = user_time;
00838 if( time == 0 )
00839 return 0;
00840 assert( group() != NULL );
00841 if( time == -1U
00842 || ( group()->userTime() != -1U
00843 && timestampCompare( group()->userTime(), time ) > 0 ))
00844 time = group()->userTime();
00845 return time;
00846 }
00847
00859 void Client::setActive( bool act )
00860 {
00861 if ( active == act )
00862 return;
00863 active = act;
00864 workspace()->setActiveClient( act ? this : NULL, Allowed );
00865
00866 if ( active )
00867 Notify::raise( Notify::Activate );
00868
00869 if( !active )
00870 cancelAutoRaise();
00871
00872 if( !active && shade_mode == ShadeActivated )
00873 setShade( ShadeNormal );
00874
00875 StackingUpdatesBlocker blocker( workspace());
00876 workspace()->updateClientLayer( this );
00877 ClientList mainclients = mainClients();
00878 for( ClientList::ConstIterator it = mainclients.begin();
00879 it != mainclients.end();
00880 ++it )
00881 if( (*it)->isFullScreen())
00882 workspace()->updateClientLayer( *it );
00883 if( decoration != NULL )
00884 decoration->activeChange();
00885 updateMouseGrab();
00886 updateUrgency();
00887 }
00888
00889 void Client::startupIdChanged()
00890 {
00891 KStartupInfoId asn_id;
00892 KStartupInfoData asn_data;
00893 bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data );
00894 if( !asn_valid )
00895 return;
00896
00897
00898
00899 int desktop = workspace()->currentDesktop();
00900 if( asn_data.desktop() != 0 )
00901 desktop = asn_data.desktop();
00902 if( !isOnAllDesktops())
00903 workspace()->sendClientToDesktop( this, desktop, true );
00904 if( asn_data.xinerama() != -1 )
00905 workspace()->sendClientToScreen( this, asn_data.xinerama());
00906 Time timestamp = asn_id.timestamp();
00907 if( timestamp == 0 && asn_data.timestamp() != -1U )
00908 timestamp = asn_data.timestamp();
00909 if( timestamp != 0 )
00910 {
00911 bool activate = workspace()->allowClientActivation( this, timestamp );
00912 if( asn_data.desktop() != 0 && !isOnCurrentDesktop())
00913 activate = false;
00914 if( activate )
00915 workspace()->activateClient( this );
00916 else
00917 demandAttention();
00918 }
00919 }
00920
00921 void Client::updateUrgency()
00922 {
00923 if( urgency )
00924 demandAttention();
00925 }
00926
00927 void Client::shortcutActivated()
00928 {
00929 workspace()->activateClient( this, true );
00930 }
00931
00932
00933
00934
00935
00936 void Group::startupIdChanged()
00937 {
00938 KStartupInfoId asn_id;
00939 KStartupInfoData asn_data;
00940 bool asn_valid = workspace()->checkStartupNotification( leader_wid, asn_id, asn_data );
00941 if( !asn_valid )
00942 return;
00943 if( asn_id.timestamp() != 0 && user_time != -1U
00944 && timestampCompare( asn_id.timestamp(), user_time ) > 0 )
00945 {
00946 user_time = asn_id.timestamp();
00947 }
00948 else if( asn_data.timestamp() != -1U && user_time != -1U
00949 && timestampCompare( asn_data.timestamp(), user_time ) > 0 )
00950 {
00951 user_time = asn_data.timestamp();
00952 }
00953 }
00954
00955 void Group::updateUserTime( Time time )
00956 {
00957 if( time == CurrentTime )
00958 time = xTime();
00959 if( time != -1U
00960 && ( user_time == CurrentTime
00961 || timestampCompare( time, user_time ) > 0 ))
00962 user_time = time;
00963 }
00964
00965 }