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