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