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