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