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( popup && popup_client != c && set_active_client_recursion == 0 )
00219 {
00220 popup->close();
00221 popup_client = 0;
00222 }
00223 StackingUpdatesBlocker blocker(
this );
00224 ++set_active_client_recursion;
00225
if( active_client != NULL )
00226 {
00227 active_client->setActive(
false );
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 focus_chain.remove( c );
00236
if ( c->wantsTabFocus() )
00237 focus_chain.append( c );
00238 active_client->demandAttention(
false );
00239 }
00240 pending_take_activity = NULL;
00241
00242 updateCurrentTopMenu();
00243 updateToolWindows(
false );
00244
00245 updateStackingOrder();
00246
00247 rootInfo->setActiveWindow( active_client? active_client->window() : 0 );
00248 updateColormap();
00249 --set_active_client_recursion;
00250 }
00251
00263
void Workspace::activateClient( Client* c,
bool force )
00264 {
00265
if( c == NULL )
00266 {
00267 setActiveClient( NULL, Allowed );
00268
return;
00269 }
00270 raiseClient( c );
00271
if (!c->isOnDesktop(currentDesktop()) )
00272 {
00273 ++block_focus;
00274 setCurrentDesktop( c->desktop() );
00275 --block_focus;
00276
00277 }
00278
if( c->isMinimized())
00279 c->unminimize();
00280
00281
if( options->focusPolicyIsReasonable())
00282 requestFocus( c, force );
00283
00284
00285
00286
00287
00288
00289
00290
00291
if( !c->ignoreFocusStealing())
00292 c->updateUserTime();
00293 }
00294
00302
void Workspace::requestFocus( Client* c,
bool force )
00303 {
00304 takeActivity( c, ActivityFocus | ( force ? ActivityFocusForce : 0 ),
false);
00305 }
00306
00307
void Workspace::takeActivity( Client* c,
int flags,
bool handled )
00308 {
00309
00310
if (!focusChangeEnabled() && ( c != active_client) )
00311 flags &= ~ActivityFocus;
00312
00313
if ( !c )
00314 {
00315 focusToNull();
00316
return;
00317 }
00318
00319
if( flags & ActivityFocus )
00320 {
00321 Client* modal = c->findModal();
00322
if( modal != NULL && modal != c )
00323 {
00324
if( !modal->isOnDesktop( c->desktop()))
00325 {
00326 modal->setDesktop( c->desktop());
00327
if( modal->desktop() != c->desktop())
00328 activateClient( modal );
00329 }
00330
00331
00332
00333
00334
if( flags & ActivityRaise )
00335 raiseClient( c );
00336 flags &= ~ActivityRaise;
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 }
00362
00363
void Workspace::handleTakeActivity( Client* c, Time ,
int flags )
00364 {
00365
if( pending_take_activity != c )
00366
return;
00367
if(( flags & ActivityRaise ) != 0 )
00368 raiseClient( c );
00369
if(( flags & ActivityFocus ) != 0 && c->isShown(
false ))
00370 c->takeFocus( Allowed );
00371 pending_take_activity = NULL;
00372 }
00373
00381
void Workspace::clientHidden( Client* c )
00382 {
00383 assert( !c->isShown(
true ) || !c->isOnCurrentDesktop());
00384 activateNextClient( c );
00385 }
00386
00387
00388
void Workspace::activateNextClient( Client* c )
00389 {
00390
00391
if( !( c == active_client
00392 || ( should_get_focus.count() > 0 && c == should_get_focus.last())))
00393
return;
00394
if( popup )
00395 popup->close();
00396
if( c == active_client )
00397 setActiveClient( NULL, Allowed );
00398 should_get_focus.remove( c );
00399
if( focusChangeEnabled())
00400 {
00401
if ( c->wantsTabFocus() && focus_chain.contains( c ) )
00402 {
00403 focus_chain.remove( c );
00404 focus_chain.prepend( c );
00405 }
00406
if ( options->focusPolicyIsReasonable())
00407 {
00408
00409 Client* get_focus = NULL;
00410
const ClientList mainwindows = c->mainClients();
00411
for( ClientList::ConstIterator it = focus_chain.fromLast();
00412 it != focus_chain.end();
00413 --it )
00414 {
00415
if( !(*it)->isShown(
false ) || !(*it)->isOnCurrentDesktop())
00416
continue;
00417
if( mainwindows.contains( *it ))
00418 {
00419 get_focus = *it;
00420
break;
00421 }
00422
if( get_focus == NULL )
00423 get_focus = *it;
00424 }
00425
if( get_focus == NULL )
00426 get_focus = findDesktop(
true, currentDesktop());
00427
if( get_focus != NULL )
00428 requestFocus( get_focus );
00429
else
00430 focusToNull();
00431 }
00432 }
00433
else
00434
00435
00436 focusToNull();
00437 }
00438
00439
00440
void Workspace::gotFocusIn(
const Client* c )
00441 {
00442
if( should_get_focus.contains( const_cast< Client* >( c )))
00443 {
00444
00445
while( should_get_focus.first() != c )
00446 should_get_focus.pop_front();
00447 should_get_focus.pop_front();
00448 }
00449 }
00450
00451
void Workspace::setShouldGetFocus( Client* c )
00452 {
00453 should_get_focus.append( c );
00454 }
00455
00456
00457
00458
bool Workspace::allowClientActivation(
const Client* c, Time time,
bool focus_in )
00459 {
00460
00461
00462
00463
00464
00465
00466
00467
00468
if( time == -1U )
00469 time = c->userTime();
00470
int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
00471
if( session_saving && level <= 2 )
00472 {
00473
return true;
00474 }
00475 Client* ac = mostRecentlyActivatedClient();
00476
if( focus_in )
00477 {
00478
if( should_get_focus.contains( const_cast< Client* >( c )))
00479
return true;
00480
00481
00482 ac = last_active_client;
00483 }
00484
if( time == 0 )
00485
return false;
00486
if( level == 0 )
00487
return true;
00488
if( level == 4 )
00489
return false;
00490
if( !c->isOnCurrentDesktop())
00491
return false;
00492
if( c->ignoreFocusStealing())
00493
return true;
00494
if( ac == NULL || ac->isDesktop())
00495 {
00496 kdDebug( 1212 ) <<
"Activation: No client active, allowing" << endl;
00497
return true;
00498 }
00499
00500
if( Client::belongToSameApplication( c, ac,
true ))
00501 {
00502 kdDebug( 1212 ) <<
"Activation: Belongs to active application" << endl;
00503
return true;
00504 }
00505
if( level == 3 )
00506
return false;
00507
if( time == -1U )
00508 {
00509 kdDebug( 1212 ) <<
"Activation: No timestamp at all" << endl;
00510
if( level == 1 )
00511
return true;
00512
00513
00514
00515
return false;
00516 }
00517
00518 Time user_time = ac->userTime();
00519 kdDebug( 1212 ) <<
"Activation, compared:" << c <<
":" << time <<
":" << user_time
00520 <<
":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
00521
return timestampCompare( time, user_time ) >= 0;
00522 }
00523
00524
00525
00526
00527
00528
bool Workspace::allowFullClientRaising(
const Client* c, Time time )
00529 {
00530
int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
00531
if( session_saving && level <= 2 )
00532 {
00533
return true;
00534 }
00535 Client* ac = mostRecentlyActivatedClient();
00536
if( level == 0 )
00537
return true;
00538
if( level == 4 )
00539
return false;
00540
if( ac == NULL || ac->isDesktop())
00541 {
00542 kdDebug( 1212 ) <<
"Raising: No client active, allowing" << endl;
00543
return true;
00544 }
00545
if( c->ignoreFocusStealing())
00546
return true;
00547
00548
if( Client::belongToSameApplication( c, ac,
true ))
00549 {
00550 kdDebug( 1212 ) <<
"Raising: Belongs to active application" << endl;
00551
return true;
00552 }
00553
if( level == 3 )
00554
return false;
00555 Time user_time = ac->userTime();
00556 kdDebug( 1212 ) <<
"Raising, compared:" << time <<
":" << user_time
00557 <<
":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
00558
return timestampCompare( time, user_time ) >= 0;
00559 }
00560
00561
00562
00563
void Workspace::restoreFocus()
00564 {
00565
00566
00567
00568
00569 updateXTime();
00570
if( should_get_focus.count() > 0 )
00571 requestFocus( should_get_focus.last());
00572
else if( last_active_client )
00573 requestFocus( last_active_client );
00574 }
00575
00576
void Workspace::clientAttentionChanged( Client* c,
bool set )
00577 {
00578
if( set )
00579 {
00580 attention_chain.remove( c );
00581 attention_chain.prepend( c );
00582 }
00583
else
00584 attention_chain.remove( c );
00585 }
00586
00587
00588
00589
00590
bool Workspace::fakeRequestedActivity( Client* c )
00591 {
00592
if( should_get_focus.count() > 0 && should_get_focus.last() == c )
00593 {
00594
if( c->isActive())
00595
return false;
00596 c->setActive(
true );
00597
return true;
00598 }
00599
return false;
00600 }
00601
00602
void Workspace::unfakeActivity( Client* c )
00603 {
00604
if( should_get_focus.count() > 0 && should_get_focus.last() == c )
00605 {
00606
if( last_active_client != NULL )
00607 last_active_client->setActive(
true );
00608
else
00609 c->setActive(
false );
00610 }
00611 }
00612
00613
00614
00615
00616
00617
00624 void Client::updateUserTime( Time time )
00625 {
00626
if( time == CurrentTime )
00627 time = qt_x_time;
00628
if( time != -1U
00629 && ( user_time == CurrentTime
00630 || timestampCompare( time, user_time ) > 0 ))
00631 user_time = time;
00632 }
00633
00634 Time Client::readUserCreationTime()
const
00635
{
00636
long result = -1;
00637 Atom type;
00638
int format, status;
00639
unsigned long nitems = 0;
00640
unsigned long extra = 0;
00641
unsigned char *data = 0;
00642 KXErrorHandler handler;
00643 status = XGetWindowProperty( qt_xdisplay(), window(),
00644 atoms->kde_net_wm_user_creation_time, 0, 10000, FALSE, XA_CARDINAL,
00645 &type, &format, &nitems, &extra, &data );
00646
if (status == Success )
00647 {
00648
if (data && nitems > 0)
00649 result = *((
long*) data);
00650 XFree(data);
00651 }
00652
return result;
00653 }
00654
00655
void Client::demandAttention(
bool set )
00656 {
00657
if( isActive())
00658 set =
false;
00659 info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
00660 workspace()->clientAttentionChanged(
this, set );
00661 }
00662
00663
00664 KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate,
const Client*,
00665
00666
00667 !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu()
00668 && Client::belongToSameApplication( cl, value,
true ) && cl != value);
00669
00670 Time Client::readUserTimeMapTimestamp(
const KStartupInfoId* asn_id,
const KStartupInfoData* asn_data,
00671
bool session )
const
00672
{
00673 Time time = info->userTime();
00674 kdDebug( 1212 ) <<
"User timestamp, initial:" << time << endl;
00675
00676
00677
if( asn_data != NULL && time != 0 )
00678 {
00679
00680
if( asn_id->timestamp() != 0
00681 && ( time == -1U || timestampCompare( asn_id->timestamp(), time ) > 0 ))
00682 {
00683 time = asn_id->timestamp();
00684 }
00685
else if( asn_data->timestamp() != -1U
00686 && ( time == -1U || timestampCompare( asn_data->timestamp(), time ) > 0 ))
00687 {
00688 time = asn_data->timestamp();
00689 }
00690 }
00691 kdDebug( 1212 ) <<
"User timestamp, ASN:" << time << endl;
00692
if( time == -1U )
00693 {
00694
00695
00696
00697
00698
00699
00700
Client* act = workspace()->mostRecentlyActivatedClient();
00701
if( act != NULL && !belongToSameApplication( act,
this,
true ))
00702 {
00703
bool first_window =
true;
00704
if( isTransient())
00705 {
00706
if( act->hasTransient(
this,
true ))
00707 ;
00708
00709
else if( groupTransient() &&
00710 findClientInList( mainClients(), SameApplicationActiveHackPredicate(
this )) == NULL )
00711 ;
00712
else
00713 first_window =
false;
00714 }
00715
else
00716 {
00717
if( workspace()->findClient( SameApplicationActiveHackPredicate(
this )))
00718 first_window =
false;
00719 }
00720
if( !first_window )
00721 {
00722 kdDebug( 1212 ) <<
"User timestamp, already exists:" << 0 << endl;
00723
return 0;
00724 }
00725 }
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
if( session )
00736
return -1U;
00737
if( ignoreFocusStealing() && act != NULL )
00738 time = act->userTime();
00739
else
00740 time = readUserCreationTime();
00741 }
00742 kdDebug( 1212 ) <<
"User timestamp, final:" <<
this <<
":" << time << endl;
00743
return time;
00744 }
00745
00746 Time Client::userTime()
const
00747
{
00748 Time time = user_time;
00749
if( time == 0 )
00750
return 0;
00751 assert( group() != NULL );
00752
if( time == -1U
00753 || ( group()->userTime() != -1U
00754 && timestampCompare( group()->userTime(), time ) > 0 ))
00755 time = group()->userTime();
00756
return time;
00757 }
00758
00770 void Client::setActive(
bool act)
00771 {
00772
if ( active == act )
00773
return;
00774 active = act;
00775 workspace()->setActiveClient( act ?
this : NULL, Allowed );
00776
00777
if ( active )
00778 Notify::raise( Notify::Activate );
00779
00780
if( !active )
00781 cancelAutoRaise();
00782
00783
if( !active && shade_mode == ShadeActivated )
00784 setShade( ShadeNormal );
00785
00786 StackingUpdatesBlocker blocker( workspace());
00787 workspace()->updateClientLayer(
this );
00788
00789 ClientList mainclients = mainClients();
00790
for( ClientList::ConstIterator it = mainclients.begin();
00791 it != mainclients.end();
00792 ++it )
00793
if( (*it)->isFullScreen())
00794 workspace()->updateClientLayer( *it );
00795
if( decoration != NULL )
00796 decoration->
activeChange();
00797 updateMouseGrab();
00798 updateUrgency();
00799 }
00800
00801
void Client::startupIdChanged()
00802 {
00803 KStartupInfoId asn_id;
00804 KStartupInfoData asn_data;
00805
bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data );
00806
if( !asn_valid )
00807
return;
00808
if( asn_data.desktop() != 0 )
00809 workspace()->sendClientToDesktop(
this, asn_data.desktop(),
true );
00810 Time timestamp = asn_id.timestamp();
00811
if( timestamp == 0 && asn_data.timestamp() != -1U )
00812 timestamp = asn_data.timestamp();
00813
if( timestamp != 0 )
00814 {
00815
bool activate = workspace()->allowClientActivation(
this, asn_data.timestamp());
00816
if( asn_data.desktop() != 0 && !isOnCurrentDesktop())
00817 activate =
false;
00818
if( activate )
00819 workspace()->activateClient(
this );
00820
else
00821 demandAttention();
00822 }
00823 }
00824
00825
void Client::updateUrgency()
00826 {
00827
if( urgency )
00828 demandAttention();
00829 }
00830
00831
00832
00833
00834
00835
void Group::startupIdChanged()
00836 {
00837 KStartupInfoId asn_id;
00838 KStartupInfoData asn_data;
00839
bool asn_valid = workspace()->checkStartupNotification( leader_wid, asn_id, asn_data );
00840
if( !asn_valid )
00841
return;
00842
if( asn_id.timestamp() != 0 && user_time != -1U
00843 && timestampCompare( asn_id.timestamp(), user_time ) > 0 )
00844 {
00845 user_time = asn_id.timestamp();
00846 }
00847
else if( asn_data.timestamp() != -1U && user_time != -1U
00848 && timestampCompare( asn_data.timestamp(), user_time ) > 0 )
00849 {
00850 user_time = asn_data.timestamp();
00851 }
00852 }
00853
00854
void Group::updateUserTime( Time time )
00855 {
00856
if( time == CurrentTime )
00857 time = qt_x_time;
00858
if( time != -1U
00859 && ( user_time == CurrentTime
00860 || timestampCompare( time, user_time ) > 0 ))
00861 user_time = time;
00862 }
00863
00864 }