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