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
00027 #include "notifications.h"
00028 #include "atoms.h"
00029 #include "group.h"
00030 #include "rules.h"
00031
00032 extern Time qt_x_time;
00033
00034 namespace KWinInternal
00035 {
00036
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
00214 void Workspace::setActiveClient( Client* c, allowed_t )
00215 {
00216 if ( active_client == c )
00217 return;
00218 if( active_popup && active_popup_client != c && set_active_client_recursion == 0 )
00219 closeActivePopup();
00220 StackingUpdatesBlocker blocker( this );
00221 ++set_active_client_recursion;
00222 if( active_client != NULL )
00223 {
00224 active_client->setActive( false, !c || !c->isModal() || c != active_client->transientFor() );
00225 }
00226 active_client = c;
00227 Q_ASSERT( c == NULL || c->isActive());
00228 if( active_client != NULL )
00229 last_active_client = active_client;
00230 if ( active_client )
00231 {
00232 focus_chain.remove( c );
00233 if ( c->wantsTabFocus() )
00234 focus_chain.append( c );
00235 active_client->demandAttention( false );
00236 }
00237 pending_take_activity = NULL;
00238
00239 updateCurrentTopMenu();
00240 updateToolWindows( false );
00241
00242 updateStackingOrder();
00243
00244 rootInfo->setActiveWindow( active_client? active_client->window() : 0 );
00245 updateColormap();
00246 --set_active_client_recursion;
00247 }
00248
00260 void Workspace::activateClient( Client* c, bool force )
00261 {
00262 if( c == NULL )
00263 {
00264 setActiveClient( NULL, Allowed );
00265 return;
00266 }
00267 raiseClient( c );
00268 if (!c->isOnDesktop(currentDesktop()) )
00269 {
00270 ++block_focus;
00271 setCurrentDesktop( c->desktop() );
00272 --block_focus;
00273
00274 }
00275 if( c->isMinimized())
00276 c->unminimize();
00277
00278
00279 if( options->focusPolicyIsReasonable() || force )
00280 requestFocus( c, force );
00281
00282
00283
00284
00285
00286
00287
00288
00289 if( !c->ignoreFocusStealing())
00290 c->updateUserTime();
00291 }
00292
00300 void Workspace::requestFocus( Client* c, bool force )
00301 {
00302 takeActivity( c, ActivityFocus | ( force ? ActivityFocusForce : 0 ), false);
00303 }
00304
00305 void Workspace::takeActivity( Client* c, int flags, bool handled )
00306 {
00307
00308 if (!focusChangeEnabled() && ( c != active_client) )
00309 flags &= ~ActivityFocus;
00310
00311 if ( !c )
00312 {
00313 focusToNull();
00314 return;
00315 }
00316
00317 if( flags & ActivityFocus )
00318 {
00319 Client* modal = c->findModal();
00320 if( modal != NULL && modal != c )
00321 {
00322 if( !modal->isOnDesktop( c->desktop()))
00323 {
00324 modal->setDesktop( c->desktop());
00325 if( modal->desktop() != c->desktop())
00326 activateClient( modal );
00327 }
00328
00329
00330
00331
00332 if( flags & ActivityRaise )
00333 raiseClient( c );
00334 c = modal;
00335 handled = false;
00336 }
00337 cancelDelayFocus();
00338 }
00339 if ( !( flags & ActivityFocusForce ) && ( c->isTopMenu() || c->isDock() || c->isSplash()) )
00340 flags &= ~ActivityFocus;
00341 if( c->isShade())
00342 {
00343 if( c->wantsInput() && ( flags & ActivityFocus ))
00344 {
00345
00346 c->setActive( true );
00347 focusToNull();
00348 }
00349 flags &= ~ActivityFocus;
00350 handled = false;
00351 }
00352 if( !c->isShown( true ))
00353 {
00354 kdWarning( 1212 ) << "takeActivity: not shown" << endl;
00355 return;
00356 }
00357 c->takeActivity( flags, handled, Allowed );
00358 }
00359
00360 void Workspace::handleTakeActivity( Client* c, Time , int flags )
00361 {
00362 if( pending_take_activity != c )
00363 return;
00364 if(( flags & ActivityRaise ) != 0 )
00365 raiseClient( c );
00366 if(( flags & ActivityFocus ) != 0 && c->isShown( false ))
00367 c->takeFocus( Allowed );
00368 pending_take_activity = NULL;
00369 }
00370
00378 void Workspace::clientHidden( Client* c )
00379 {
00380 assert( !c->isShown( true ) || !c->isOnCurrentDesktop());
00381 activateNextClient( c );
00382 }
00383
00384
00385 bool Workspace::activateNextClient( Client* c )
00386 {
00387
00388 if( !( c == active_client
00389 || ( should_get_focus.count() > 0 && c == should_get_focus.last())))
00390 return false;
00391 closeActivePopup();
00392 if( c != NULL )
00393 {
00394 if( c == active_client )
00395 setActiveClient( NULL, Allowed );
00396 should_get_focus.remove( c );
00397 }
00398 if( focusChangeEnabled())
00399 {
00400 if ( c != NULL && c->wantsTabFocus() && focus_chain.contains( c ) )
00401 {
00402 focus_chain.remove( c );
00403 focus_chain.prepend( c );
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.fromLast();
00411 it != focus_chain.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 kdDebug( 1212 ) << "Activation: No client active, allowing" << endl;
00500 return true;
00501 }
00502
00503 if( Client::belongToSameApplication( c, ac, true ))
00504 {
00505 kdDebug( 1212 ) << "Activation: Belongs to active application" << endl;
00506 return true;
00507 }
00508 if( level == 3 )
00509 return false;
00510 if( time == -1U )
00511 {
00512 kdDebug( 1212 ) << "Activation: No timestamp at all" << endl;
00513 if( level == 1 )
00514 return true;
00515
00516
00517
00518 return false;
00519 }
00520
00521 Time user_time = ac->userTime();
00522 kdDebug( 1212 ) << "Activation, compared:" << c << ":" << time << ":" << user_time
00523 << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
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 kdDebug( 1212 ) << "Raising: No client active, allowing" << endl;
00546 return true;
00547 }
00548 if( c->ignoreFocusStealing())
00549 return true;
00550
00551 if( Client::belongToSameApplication( c, ac, true ))
00552 {
00553 kdDebug( 1212 ) << "Raising: Belongs to active application" << endl;
00554 return true;
00555 }
00556 if( level == 3 )
00557 return false;
00558 Time user_time = ac->userTime();
00559 kdDebug( 1212 ) << "Raising, compared:" << time << ":" << user_time
00560 << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
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 }
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 info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
00663 workspace()->clientAttentionChanged( this, set );
00664 }
00665
00666
00667 KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, const Client*,
00668
00669
00670 !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu()
00671 && Client::belongToSameApplication( cl, value, true ) && cl != value);
00672
00673 Time Client::readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
00674 bool session ) const
00675 {
00676 Time time = info->userTime();
00677 kdDebug( 1212 ) << "User timestamp, initial:" << time << endl;
00678
00679
00680 if( asn_data != NULL && time != 0 )
00681 {
00682
00683 if( asn_id->timestamp() != 0
00684 && ( time == -1U || timestampCompare( asn_id->timestamp(), time ) > 0 ))
00685 {
00686 time = asn_id->timestamp();
00687 }
00688 else if( asn_data->timestamp() != -1U
00689 && ( time == -1U || timestampCompare( asn_data->timestamp(), time ) > 0 ))
00690 {
00691 time = asn_data->timestamp();
00692 }
00693 }
00694 kdDebug( 1212 ) << "User timestamp, ASN:" << time << endl;
00695 if( time == -1U )
00696 {
00697
00698
00699
00700
00701
00702
00703 Client* act = workspace()->mostRecentlyActivatedClient();
00704 if( act != NULL && !belongToSameApplication( act, this, true ))
00705 {
00706 bool first_window = true;
00707 if( isTransient())
00708 {
00709 if( act->hasTransient( this, true ))
00710 ;
00711
00712 else if( groupTransient() &&
00713 findClientInList( mainClients(), SameApplicationActiveHackPredicate( this )) == NULL )
00714 ;
00715 else
00716 first_window = false;
00717 }
00718 else
00719 {
00720 if( workspace()->findClient( SameApplicationActiveHackPredicate( this )))
00721 first_window = false;
00722 }
00723
00724 if( !first_window && rules()->checkFSP( options->focusStealingPreventionLevel ) > 0 )
00725 {
00726 kdDebug( 1212 ) << "User timestamp, already exists:" << 0 << endl;
00727 return 0;
00728 }
00729 }
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739 if( session )
00740 return -1U;
00741 if( ignoreFocusStealing() && act != NULL )
00742 time = act->userTime();
00743 else
00744 time = readUserCreationTime();
00745 }
00746 kdDebug( 1212 ) << "User timestamp, final:" << this << ":" << time << endl;
00747 return time;
00748 }
00749
00750 Time Client::userTime() const
00751 {
00752 Time time = user_time;
00753 if( time == 0 )
00754 return 0;
00755 assert( group() != NULL );
00756 if( time == -1U
00757 || ( group()->userTime() != -1U
00758 && timestampCompare( group()->userTime(), time ) > 0 ))
00759 time = group()->userTime();
00760 return time;
00761 }
00762
00774 void Client::setActive( bool act, bool updateOpacity_)
00775 {
00776 if ( active == act )
00777 return;
00778 active = act;
00779 workspace()->setActiveClient( act ? this : NULL, Allowed );
00780
00781 if (updateOpacity_) updateOpacity();
00782 if (isModal() && transientFor())
00783 {
00784 if (!act) transientFor()->updateOpacity();
00785 else if (!transientFor()->custom_opacity) transientFor()->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
00786 }
00787 updateShadowSize();
00788
00789 if ( active )
00790 Notify::raise( Notify::Activate );
00791
00792 if( !active )
00793 cancelAutoRaise();
00794
00795 if( !active && shade_mode == ShadeActivated )
00796 setShade( ShadeNormal );
00797
00798 StackingUpdatesBlocker blocker( workspace());
00799 workspace()->updateClientLayer( this );
00800
00801 ClientList mainclients = mainClients();
00802 for( ClientList::ConstIterator it = mainclients.begin();
00803 it != mainclients.end();
00804 ++it )
00805 if( (*it)->isFullScreen())
00806 workspace()->updateClientLayer( *it );
00807 if( decoration != NULL )
00808 decoration->activeChange();
00809 updateMouseGrab();
00810 updateUrgency();
00811 }
00812
00813 void Client::startupIdChanged()
00814 {
00815 KStartupInfoId asn_id;
00816 KStartupInfoData asn_data;
00817 bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data );
00818 if( !asn_valid )
00819 return;
00820 if( asn_data.desktop() != 0 )
00821 workspace()->sendClientToDesktop( this, asn_data.desktop(), true );
00822 Time timestamp = asn_id.timestamp();
00823 if( timestamp == 0 && asn_data.timestamp() != -1U )
00824 timestamp = asn_data.timestamp();
00825 if( timestamp != 0 )
00826 {
00827 bool activate = workspace()->allowClientActivation( this, timestamp );
00828 if( asn_data.desktop() != 0 && !isOnCurrentDesktop())
00829 activate = false;
00830 if( activate )
00831 workspace()->activateClient( this );
00832 else
00833 demandAttention();
00834 }
00835 }
00836
00837 void Client::updateUrgency()
00838 {
00839 if( urgency )
00840 demandAttention();
00841 }
00842
00843 void Client::shortcutActivated()
00844 {
00845 workspace()->activateClient( this, true );
00846 }
00847
00848
00849
00850
00851
00852 void Group::startupIdChanged()
00853 {
00854 KStartupInfoId asn_id;
00855 KStartupInfoData asn_data;
00856 bool asn_valid = workspace()->checkStartupNotification( leader_wid, asn_id, asn_data );
00857 if( !asn_valid )
00858 return;
00859 if( asn_id.timestamp() != 0 && user_time != -1U
00860 && timestampCompare( asn_id.timestamp(), user_time ) > 0 )
00861 {
00862 user_time = asn_id.timestamp();
00863 }
00864 else if( asn_data.timestamp() != -1U && user_time != -1U
00865 && timestampCompare( asn_data.timestamp(), user_time ) > 0 )
00866 {
00867 user_time = asn_data.timestamp();
00868 }
00869 }
00870
00871 void Group::updateUserTime( Time time )
00872 {
00873 if( time == CurrentTime )
00874 time = qt_x_time;
00875 if( time != -1U
00876 && ( user_time == CurrentTime
00877 || timestampCompare( time, user_time ) > 0 ))
00878 user_time = time;
00879 }
00880
00881 }