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