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