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