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