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 <qpopupmenu.h>
00023 #include <kxerrorhandler.h>
00024 #include <kstartupinfo.h>
00025
00026 #include "notifications.h"
00027 #include "atoms.h"
00028 #include "group.h"
00029
00030 extern Time qt_x_time;
00031
00032 namespace KWinInternal
00033 {
00034
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
00212 void Workspace::setActiveClient( Client* c, allowed_t )
00213 {
00214 if ( active_client == c )
00215 return;
00216 if( popup && popup_client != c && set_active_client_recursion == 0 )
00217 {
00218 popup->close();
00219 popup_client = 0;
00220 }
00221 StackingUpdatesBlocker blocker( this );
00222 ++set_active_client_recursion;
00223 if( active_client != NULL )
00224 {
00225 active_client->setActive( false );
00226 }
00227 active_client = c;
00228 Q_ASSERT( c == NULL || c->isActive());
00229 if( active_client != NULL )
00230 last_active_client = active_client;
00231 if ( active_client )
00232 {
00233 focus_chain.remove( c );
00234 if ( c->wantsTabFocus() )
00235 focus_chain.append( c );
00236 active_client->demandAttention( false );
00237 }
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 if( options->focusPolicyIsReasonable())
00279 requestFocus( c, force );
00280
00281 c->updateUserTime();
00282 }
00283
00291 void Workspace::requestFocus( Client* c, bool force )
00292 {
00293 if (!focusChangeEnabled() && ( c != active_client) )
00294 return;
00295
00296
00297 if ( !c )
00298 {
00299 focusToNull();
00300 return;
00301 }
00302
00303 if( !c->isOnCurrentDesktop())
00304 {
00305 kdWarning( 1212 ) << "requestFocus: not on current desktop" << endl;
00306 return;
00307 }
00308
00309 Client* modal = c->findModal();
00310 if( modal != NULL && modal != c )
00311 {
00312 if( !modal->isOnDesktop( c->desktop()))
00313 modal->setDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop());
00314 requestFocus( modal, force );
00315 return;
00316 }
00317 if ( c->isShown( false ) )
00318 {
00319 c->takeFocus( force, Allowed );
00320 should_get_focus.append( c );
00321 focus_chain.remove( c );
00322 if ( c->wantsTabFocus() )
00323 focus_chain.append( c );
00324 }
00325 else if ( c->isShade() && c->wantsInput())
00326 {
00327
00328 c->setActive( true );
00329 focusToNull();
00330 }
00331 }
00332
00340 void Workspace::clientHidden( Client* c )
00341 {
00342 assert( !c->isShown( true ) || !c->isOnCurrentDesktop());
00343 activateNextClient( c );
00344 }
00345
00346
00347 void Workspace::activateNextClient( Client* c )
00348 {
00349
00350 if( !( c == active_client
00351 || ( should_get_focus.count() > 0 && c == should_get_focus.last())))
00352 return;
00353 if( popup )
00354 popup->close();
00355 if( c == active_client )
00356 setActiveClient( NULL, Allowed );
00357 should_get_focus.remove( c );
00358 if( focusChangeEnabled())
00359 {
00360 if ( c->wantsTabFocus() && focus_chain.contains( c ) )
00361 {
00362 focus_chain.remove( c );
00363 focus_chain.prepend( c );
00364 }
00365 if ( options->focusPolicyIsReasonable())
00366 {
00367
00368 Client* get_focus = NULL;
00369 const ClientList mainwindows = c->mainClients();
00370 for( ClientList::ConstIterator it = focus_chain.fromLast();
00371 it != focus_chain.end();
00372 --it )
00373 {
00374 if( !(*it)->isShown( false ) || !(*it)->isOnCurrentDesktop())
00375 continue;
00376 if( mainwindows.contains( *it ))
00377 {
00378 get_focus = *it;
00379 break;
00380 }
00381 if( get_focus == NULL )
00382 get_focus = *it;
00383 }
00384 if( get_focus == NULL )
00385 get_focus = findDesktop( true, currentDesktop());
00386 if( get_focus != NULL )
00387 requestFocus( get_focus );
00388 else
00389 focusToNull();
00390 }
00391 }
00392 else
00393
00394
00395 focusToNull();
00396 }
00397
00398
00399 void Workspace::gotFocusIn( const Client* c )
00400 {
00401 if( should_get_focus.contains( const_cast< Client* >( c )))
00402 {
00403
00404 while( should_get_focus.first() != c )
00405 should_get_focus.pop_front();
00406 }
00407 }
00408
00409
00410
00411
00412 bool Workspace::allowClientActivation( const Client* c, Time time, bool focus_in, bool session_active )
00413 {
00414
00415
00416
00417
00418
00419
00420
00421
00422 if( session_saving
00423 && options->focusStealingPreventionLevel <= 2 )
00424 {
00425 return true;
00426 }
00427 Client* ac = mostRecentlyActivatedClient();
00428 if( focus_in )
00429 {
00430 if( should_get_focus.contains( const_cast< Client* >( c )))
00431 return true;
00432
00433
00434 ac = last_active_client;
00435 }
00436 if( options->focusStealingPreventionLevel == 0 )
00437 return true;
00438 if( options->focusStealingPreventionLevel == 4 )
00439 return false;
00440 if( ac == NULL || ac->isDesktop())
00441 {
00442 kdDebug( 1212 ) << "Activation: No client active, allowing" << endl;
00443 return true;
00444 }
00445 if( options->ignoreFocusStealingClasses.contains(QString::fromLatin1(c->resourceClass())))
00446 return true;
00447 if( time == 0 )
00448 return false;
00449
00450 if( Client::belongToSameApplication( c, ac, true ))
00451 {
00452 kdDebug( 1212 ) << "Activation: Belongs to active application" << endl;
00453 return true;
00454 }
00455 if( options->focusStealingPreventionLevel == 3 )
00456 return false;
00457 if( time == -1U )
00458 if( session_active )
00459 return !was_user_interaction;
00460 else
00461 {
00462 kdDebug() << "Activation: No timestamp at all" << endl;
00463 if( options->focusStealingPreventionLevel == 1 )
00464 return true;
00465
00466
00467
00468 return false;
00469 }
00470
00471 Time user_time = ac->userTime();
00472 kdDebug( 1212 ) << "Activation, compared:" << time << ":" << user_time
00473 << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
00474 return timestampCompare( time, user_time ) >= 0;
00475 }
00476
00477
00478
00479
00480
00481 bool Workspace::allowFullClientRaising( const Client* c )
00482 {
00483 if( session_saving
00484 && options->focusStealingPreventionLevel <= 2 )
00485 {
00486 return true;
00487 }
00488 Client* ac = mostRecentlyActivatedClient();
00489 if( options->focusStealingPreventionLevel == 0 )
00490 return true;
00491 if( options->focusStealingPreventionLevel == 4 )
00492 return false;
00493 if( ac == NULL || ac->isDesktop())
00494 {
00495 kdDebug( 1212 ) << "Raising: No client active, allowing" << endl;
00496 return true;
00497 }
00498 if( options->ignoreFocusStealingClasses.contains(QString::fromLatin1(c->resourceClass())))
00499 return true;
00500
00501 if( Client::belongToSameApplication( c, ac, true ))
00502 {
00503 kdDebug( 1212 ) << "Raising: Belongs to active application" << endl;
00504 return true;
00505 }
00506 if( options->focusStealingPreventionLevel == 3 )
00507 return false;
00508 if( !c->hasUserTimeSupport())
00509 {
00510 kdDebug() << "Raising: No support" << endl;
00511 if( options->focusStealingPreventionLevel == 1 )
00512 return true;
00513 }
00514
00515 kdDebug() << "Raising: Refusing" << endl;
00516 return false;
00517 }
00518
00519
00520
00521 void Workspace::restoreFocus()
00522 {
00523
00524
00525
00526
00527 updateXTime();
00528 if( should_get_focus.count() > 0 )
00529 requestFocus( should_get_focus.last());
00530 else if( last_active_client )
00531 requestFocus( last_active_client );
00532 }
00533
00534 void Workspace::clientAttentionChanged( Client* c, bool set )
00535 {
00536 if( set )
00537 {
00538 attention_chain.remove( c );
00539 attention_chain.prepend( c );
00540 }
00541 else
00542 attention_chain.remove( c );
00543 }
00544
00545
00546
00547
00548 bool Workspace::fakeRequestedActivity( Client* c )
00549 {
00550 if( should_get_focus.count() > 0 && should_get_focus.last() == c )
00551 {
00552 if( c->isActive())
00553 return false;
00554 c->setActive( true );
00555 return true;
00556 }
00557 return false;
00558 }
00559
00560 void Workspace::unfakeActivity( Client* c )
00561 {
00562 if( should_get_focus.count() > 0 && should_get_focus.last() == c )
00563 {
00564 if( last_active_client != NULL )
00565 last_active_client->setActive( true );
00566 else
00567 c->setActive( false );
00568 }
00569 }
00570
00571
00572
00573
00574
00575
00582 void Client::updateUserTime( Time time )
00583 {
00584 if( time == CurrentTime )
00585 time = qt_x_time;
00586 if( time != -1U
00587 && ( user_time == CurrentTime
00588 || timestampCompare( time, user_time ) > 0 ))
00589 user_time = time;
00590 }
00591
00592 Time Client::readUserCreationTime() const
00593 {
00594 long result = -1;
00595 Atom type;
00596 int format, status;
00597 unsigned long nitems = 0;
00598 unsigned long extra = 0;
00599 unsigned char *data = 0;
00600 KXErrorHandler handler;
00601 status = XGetWindowProperty( qt_xdisplay(), window(),
00602 atoms->kde_net_wm_user_creation_time, 0, 10000, FALSE, XA_CARDINAL,
00603 &type, &format, &nitems, &extra, &data );
00604 if (status == Success )
00605 {
00606 if (data && nitems > 0)
00607 result = *((long*) data);
00608 XFree(data);
00609 }
00610 return result;
00611 }
00612
00613 void Client::demandAttention( bool set )
00614 {
00615 if( isActive())
00616 set = false;
00617 info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
00618 workspace()->clientAttentionChanged( this, set );
00619 }
00620
00621
00622 KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, const Client*,
00623
00624
00625 !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu()
00626 && Client::belongToSameApplication( cl, value, true ) && cl != value);
00627
00628 Time Client::readUserTimeMapTimestamp( const KStartupInfoData* asn_data,
00629 const SessionInfo* session ) const
00630 {
00631 Time time = info->userTime();
00632 kdDebug( 1212 ) << "User timestamp, initial:" << time << endl;
00633
00634
00635 if( asn_data != NULL && time != 0
00636 && ( time == -1U
00637 || ( asn_data->timestamp() != -1U
00638 && timestampCompare( asn_data->timestamp(), time ) > 0 )))
00639 time = asn_data->timestamp();
00640 kdDebug( 1212 ) << "User timestamp, ASN:" << time << endl;
00641 if( time == -1U )
00642 {
00643
00644
00645
00646
00647
00648
00649 Client* act = workspace()->mostRecentlyActivatedClient();
00650 if( act != NULL && !belongToSameApplication( act, this, true ))
00651 {
00652 bool first_window = true;
00653 if( isTransient())
00654 {
00655 if( act->hasTransient( this, true ))
00656 ;
00657
00658 else if( groupTransient() &&
00659 findClientInList( mainClients(), SameApplicationActiveHackPredicate( this )) == NULL )
00660 ;
00661 else
00662 first_window = false;
00663 }
00664 else
00665 {
00666 if( workspace()->findClient( SameApplicationActiveHackPredicate( this )))
00667 first_window = false;
00668 }
00669 if( !first_window )
00670 {
00671 kdDebug( 1212 ) << "User timestamp, already exists:" << 0 << endl;
00672 return 0;
00673 }
00674 }
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684 if( session && !session->fake )
00685 return -1U;
00686 time = readUserCreationTime();
00687 }
00688 kdDebug( 1212 ) << "User timestamp, final:" << time << endl;
00689 return time;
00690 }
00691
00692 Time Client::userTime() const
00693 {
00694 Time time = user_time;
00695 assert( group() != NULL );
00696 if( time == -1U
00697 || ( group()->userTime() != -1U
00698 && timestampCompare( group()->userTime(), time ) > 0 ))
00699 time = group()->userTime();
00700 return time;
00701 }
00702
00714 void Client::setActive( bool act)
00715 {
00716 if ( active == act )
00717 return;
00718 active = act;
00719 workspace()->setActiveClient( act ? this : NULL, Allowed );
00720
00721 if ( active )
00722 Notify::raise( Notify::Activate );
00723
00724 if( !active )
00725 cancelAutoRaise();
00726
00727 if( !active && shade_mode == ShadeActivated )
00728 setShade( ShadeNormal );
00729
00730 StackingUpdatesBlocker blocker( workspace());
00731 workspace()->updateClientLayer( this );
00732
00733 ClientList mainclients = mainClients();
00734 for( ClientList::ConstIterator it = mainclients.begin();
00735 it != mainclients.end();
00736 ++it )
00737 if( (*it)->isFullScreen())
00738 workspace()->updateClientLayer( *it );
00739 if( decoration != NULL )
00740 decoration->activeChange();
00741 updateMouseGrab();
00742 updateUrgency();
00743 }
00744
00745 void Client::startupIdChanged()
00746 {
00747 KStartupInfoData asn_data;
00748 bool asn_valid = workspace()->checkStartupNotification( window(), asn_data );
00749 if( !asn_valid )
00750 return;
00751 if( asn_data.desktop() != 0 )
00752 workspace()->sendClientToDesktop( this, asn_data.desktop(), true );
00753 if( asn_data.timestamp() != -1U )
00754 {
00755 bool activate = workspace()->allowClientActivation( this, asn_data.timestamp());
00756 if( asn_data.desktop() != 0 && !isOnCurrentDesktop())
00757 activate = false;
00758 if( activate )
00759 workspace()->activateClient( this );
00760 else
00761 demandAttention();
00762 }
00763 }
00764
00765 void Client::updateUrgency()
00766 {
00767 if( urgency )
00768 demandAttention();
00769 }
00770
00771
00772
00773
00774
00775 void Group::startupIdChanged()
00776 {
00777 KStartupInfoData asn_data;
00778 bool asn_valid = workspace()->checkStartupNotification( leader_wid, asn_data );
00779 if( !asn_valid )
00780 return;
00781 if( asn_data.timestamp() != -1U && user_time != -1U
00782 &×tampCompare( asn_data.timestamp(), user_time ) > 0 )
00783 user_time = asn_data.timestamp();
00784 }
00785
00786 void Group::updateUserTime( Time time )
00787 {
00788 if( time == CurrentTime )
00789 time = qt_x_time;
00790 if( time != -1U
00791 && ( user_time == CurrentTime
00792 || timestampCompare( time, user_time ) > 0 ))
00793 user_time = time;
00794 }
00795
00796 }