diff --git a/kwin/activation.cpp b/kwin/activation.cpp index 7cd31b22cc..15bfc8ada9 100644 --- a/kwin/activation.cpp +++ b/kwin/activation.cpp @@ -1,688 +1,708 @@ /***************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 1999, 2000 Matthias Ettrich Copyright (C) 2003 Lubos Lunak You can Freely distribute this program under the GNU General Public License. See the file "COPYING" for the exact licensing terms. ******************************************************************/ /* This file contains things relevant to window activation and focus stealing prevention. */ #include "client.h" #include "workspace.h" #include #include #include #include "notifications.h" #include "atoms.h" extern Time qt_x_time; namespace KWinInternal { /* Prevention of focus stealing: KWin tries to prevent unwanted changes of focus, that would result from mapping a new window. Also, some nasty applications may try to force focus change even in cases when ICCCM 4.2.7 doesn't allow it (e.g. they may try to activate their main window because the user definitely "needs" to see something happened - misusing of QWidget::setActiveWindow() may be such case). There are 4 ways how a window may become active: - the user changes the active window (e.g. focus follows mouse, clicking on some window's titlebar) - the change of focus will be done by KWin, so there's nothing to solve in this case - the change of active window will be requested using the _NET_ACTIVE_WINDOW message (handled in RootInfo::changeActiveWindow()) - such requests will be obeyed, because this request is meant mainly for e.g. taskbar asking the WM to change the active window as a result of some user action. Normal applications should use this request only rarely in special cases. See also below the discussion of _NET_ACTIVE_WINDOW_TRANSFER. - the change of active window will be done by performing XSetInputFocus() on a window that's not currently active. ICCCM 4.2.7 describes when the application may perform change of input focus. In order to handle misbehaving applications, KWin will try to detect focus changes to windows that don't belong to currently active application, and restore focus back to the currently active window, instead of activating the window that got focus (unfortunately there's no way to FocusChangeRedirect similar to e.g. SubstructureRedirect, so there will be short time when the focus will be changed). The check itself that's done is Workspace::allowClientActivation() (see below). - a new window will be mapped - this is the most complicated case. If the new window belongs to the currently active application, it may be safely mapped on top and activated. The same if there's no active window, or the active window is the desktop. These checks are done by Workspace::allowClientActivation(). Following checks need to compare times. One time is the timestamp of last user action in the currently active window, the other time is the timestamp of the action that originally caused mapping of the new window (e.g. when the application was started). If the first time is newer than the second one, the window will not be activated, as that indicates futher user actions took place after the action leading to this new mapped window. This check is done by Workspace::allowClientActivation(). There are several ways how to get the timestamp of action that caused the new mapped window (done in Client::readUserTimeMapTimestamp()) : - the window may have the _NET_WM_USER_TIME property. This way the application may either explicitly request that the window is not activated (by using 0 timestamp), or the property contains the time of last user action in the application. - KWin itself tries to detect time of last user action in every window, by watching KeyPress and ButtonPress events on windows. This way some events may be missed (if they don't propagate to the toplevel window), but it's good as a fallback for applications that don't provide _NET_WM_USER_TIME, and missing some events may at most lead to unwanted focus stealing. - the timestamp may come from application startup notification. Application startup notification, if it exists for the new mapped window, should include time of the user action that caused it. - if there's no timestamp available, it's checked whether the new window belongs to some already running application - if yes, the timestamp will be 0 (i.e. refuse activation) - if the window is from session restored window, the timestamp will be 0 too, unless this application was the active one at the time when the session was saved, in which case the window will be activated if there wasn't any user interaction since the time KWin was started. - as the last resort, the _KDE_NET_USER_CREATION_TIME timestamp is used. For every toplevel window that is created (see CreateNotify handling), this property is set to the at that time current time. Since at this time it's known that the new window doesn't belong to any existing application (better said, the application doesn't have any other window mapped), it is either the very first window of the application, or its the only window of the application that was hidden before. The latter case is handled by removing the property from windows before withdrawing them, making the timestamp empty for next mapping of the window. In the sooner case, the timestamp will be used. This helps in case when an application is launched without application startup notification, it creates its mainwindow, and starts its initialization (that may possibly take long time). The timestamp used will be older than any user action done after launching this application. - if no timestamp is found at all, the window is activated. The check whether two windows belong to the same application (same process) is done in Client::belongToSameApplication(). Not 100% reliable, but hopefully 99,99% reliable. As a somewhat special case, window activation is always enabled when session saving is in progress. When session saving, the session manager allows only one application to interact with the user. Not allowing window activation in such case would result in e.g. dialogs not becoming active, so focus stealing prevention would cause here more harm than good. Windows that attempted to become active but KWin prevented this will be marked as demanding user attention. They'll get the _NET_WM_STATE_DEMANDS_ATTENTION state, and the taskbar should mark them specially (blink, etc.). The state will be reset when the window eventually really becomes active. There are one more ways how a window can become obstrusive, window stealing focus: By showing above the active window, by either raising itself, or by moving itself on the active desktop. - KWin will refuse raising non-active window above the active one, unless they belong to the same application. Applications shouldn't raise their windows anyway (unless the app wants to raise one of its windows above another of its windows). - KWin activates windows moved to the current desktop (as that seems logical from the user's point of view, after sending the window there directly from KWin, or e.g. using pager). This means applications shouldn't send their windows to another desktop (SELI TODO - but what if they do?) Special cases I can think of: - konqueror reusing, i.e. kfmclient tells running Konqueror instance to open new window - without focus stealing prevention - no problem - with ASN (application startup notification) - ASN is forwarded, and because it's newer than the instance's user timestamp, it takes precedence - without ASN - user timestamp needs to be reset, otherwise it would be used, and it's old; moreover this new window mustn't be detected as window belonging to already running application, or it wouldn't be activated - see Client::sameAppWindowRoleMatch() for the (rather ugly) hack - konqueror preloading, i.e. window is created in advance, and kfmclient tells this Konqueror instance to show it later - without focus stealing prevention - no problem - with ASN - ASN is forwarded, and because it's newer than the instance's user timestamp, it takes precedence - without ASN - user timestamp needs to be reset, otherwise it would be used, and it's old; also, creation timestamp is changed to the time the instance starts (re-)initializing the window, this ensures creation timestamp will still work somewhat even in this case - KUniqueApplication - when the window is already visible, and the new instance wants it to activate - without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem - with ASN - ASN is forwarded, and set on the already visible window, KWin treats the window as new with that ASN - without ASN - _NET_ACTIVE_WINDOW as application request is used, and there's no really usable timestamp, only timestamp from the time the (new) application instance was started, so KWin will activate the window *sigh* - the bad thing here is that there's absolutely no chance to recognize the case of starting this KUniqueApp from Konsole (and thus wanting the already visible window to become active) from the case when something started this KUniqueApp without ASN (in which case the already visible window shouldn't become active) - the only solution is using ASN for starting applications, at least silent (i.e. without feedback) - when one application wants to activate another application's window (e.g. KMail activating already running KAddressBook window ?) - without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem - with ASN - can't be here, it's the KUniqueApp case then - without ASN - _NET_ACTIVE_WINDOW as application request should be used, KWin will activate the new window depending on the timestamp and whether it belongs to the currently active application _NET_ACTIVE_WINDOW usage: data.l[0]= 1 ->app request = 2 ->pager request = 0 - backwards compatibility data.l[1]= timestamp */ //**************************************** // Workspace //**************************************** /*! Informs the workspace about the active client, i.e. the client that has the focus (or None if no client has the focus). This functions is called by the client itself that gets focus. It has no other effect than fixing the focus chain and the return value of activeClient(). And of course, to propagate the active client to the world. */ void Workspace::setActiveClient( Client* c, allowed_t ) { if ( active_client == c ) return; if( popup && popup_client != c && set_active_client_recursion == 0 ) { popup->close(); popup_client = 0; } StackingUpdatesBlocker blocker( this ); ++set_active_client_recursion; if( active_client != NULL ) { // note that this may call setActiveClient( NULL ), therefore the recursion counter active_client->setActive( false ); } active_client = c; Q_ASSERT( c == NULL || c->isActive()); if( active_client != NULL ) last_active_client = active_client; if ( active_client ) { focus_chain.remove( c ); if ( c->wantsTabFocus() ) focus_chain.append( c ); active_client->demandAttention( false ); } updateCurrentTopMenu(); updateToolWindows( false ); updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active rootInfo->setActiveWindow( active_client? active_client->window() : 0 ); updateColormap(); --set_active_client_recursion; } /*! Tries to activate the client \a c. This function performs what you expect when clicking the respective entry in a taskbar: showing and raising the client (this may imply switching to the another virtual desktop) and putting the focus onto it. Once X really gave focus to the client window as requested, the client itself will call setActiveClient() and the operation is complete. This may not happen with certain focus policies, though. \sa stActiveClient(), requestFocus() */ void Workspace::activateClient( Client* c, bool force ) { if( c == NULL ) { setActiveClient( NULL, Allowed ); return; } raiseClient( c ); if (!c->isOnDesktop(currentDesktop()) ) { setCurrentDesktop( c->desktop() ); // popupinfo->showInfo( desktopName(currentDesktop()) ); // AK - not sure } if( c->isMinimized()) c->unminimize(); if( options->focusPolicyIsReasonable()) requestFocus( c, force ); else { if( activeClient() != c ) c->demandAttention(); } c->updateUserTime(); } /*! Tries to activate the client by asking X for the input focus. This function does not perform any show, raise or desktop switching. See Workspace::activateClient() instead. \sa Workspace::activateClient() */ void Workspace::requestFocus( Client* c, bool force ) { // the 'if( c == active_client ) return;' optimization mustn't be done here if (!focusChangeEnabled() && ( c != active_client) ) return; //TODO will be different for non-root clients. (subclassing?) if ( !c ) { focusToNull(); return; } if( !c->isOnCurrentDesktop()) // shouldn't happen, call activateClient() if needed { kdWarning( 1212 ) << "requestFocus: not on current desktop" << endl; return; } Client* modal = c->findModal(); if( modal != NULL && modal != c ) { if( !modal->isOnDesktop( c->desktop())) modal->setDesktop( c->desktop()); requestFocus( modal, force ); return; } if ( c->isShown() ) { c->takeFocus( force, Allowed ); should_get_focus.append( c ); focus_chain.remove( c ); if ( c->wantsTabFocus() ) focus_chain.append( c ); } else if ( c->isShade() && c->wantsInput()) { // client cannot accept focus, but at least the window should be active (window menu, et. al. ) c->setActive( true ); focusToNull(); } } /*! Informs the workspace that the client \a c has been hidden. If it was the active client (or to-become the active client), the workspace activates another one. \a c may already be destroyed */ extern bool block_focus; // SELI void Workspace::clientHidden( Client* c ) { if( !( c == active_client || ( should_get_focus.count() > 0 && c == should_get_focus.last()))) return; if( popup ) popup->close(); if( c == active_client ) setActiveClient( NULL, Allowed ); should_get_focus.remove( c ); if( !block_focus ) { if ( c->wantsTabFocus() && focus_chain.contains( c ) ) { focus_chain.remove( c ); focus_chain.prepend( c ); } if ( options->focusPolicyIsReasonable()) { // search the focus_chain for a client to transfer focus to // if 'c' is transient, transfer focus to the first suitable mainwindow Client* get_focus = NULL; const ClientList mainwindows = c->mainClients(); for( ClientList::ConstIterator it = focus_chain.fromLast(); it != focus_chain.end(); --it ) { if( !(*it)->isShown() || !(*it)->isOnCurrentDesktop()) continue; if( mainwindows.contains( *it )) { get_focus = *it; break; } if( get_focus == NULL ) get_focus = *it; } if( get_focus != NULL ) { requestFocus( get_focus ); return; } if ( !desktops.isEmpty() ) requestFocus( findDesktop( true, currentDesktop())); else focusToNull(); } } else // if blocking focus, move focus to the desktop later if needed // in order to avoid flickering focusToNull(); } void Workspace::gotFocusIn( const Client* c ) { if( should_get_focus.contains( const_cast< Client* >( c ))) { // remove also all sooner elements that should have got FocusIn, // but didn't for some reason (and also won't anymore, because they were sooner) while( should_get_focus.first() != c ) should_get_focus.pop_front(); } } // focus_in -> the window got FocusIn event // session_active -> the window was active when saving session bool Workspace::allowClientActivation( const Client* c, Time time, bool focus_in, bool session_active ) { - if( session_saving ) + // options->focusStealingPreventionLevel : + // 0 - none - old KWin behaviour, new windows always get focus + // 1 - low - focus stealing prevention is applied normally, when unsure, activation is allowed + // 2 - normal - focus stealing prevention is applied normally, when unsure, activation is not allowed, + // this is the default + // 3 - high - new window gets focus only if it belongs to the active application, + // or when no window is currently active + // 4 - extreme - no window gets focus without user intervention + if( session_saving + && options->focusStealingPreventionLevel <= 3 ) // <= normal + { return true; + } Client* ac = activeClient(); if( focus_in ) { if( should_get_focus.contains( const_cast< Client* >( c ))) return true; // FocusIn was result of KWin's action // Before getting FocusIn, the active Client already // got FocusOut, and therefore got deactivated. ac = last_active_client; } + if( options->focusStealingPreventionLevel == 0 ) // none + return true; + if( options->focusStealingPreventionLevel == 5 ) // extreme + return false; if( ac == NULL || ac->isDesktop()) { kdDebug( 1212 ) << "Activation: No client active, allowing" << endl; return true; // no active client -> always allow } if( time == 0 ) // explicitly asked not to get focus return false; // TODO window urgency -> return true? if( Client::belongToSameApplication( c, ac, true )) { kdDebug( 1212 ) << "Activation: Belongs to active application" << endl; return true; } + if( options->focusStealingPreventionLevel == 4 ) // high + return false; if( time == -1U ) // no time known if( session_active ) return !was_user_interaction; // see Client::readUserTimeMapTimestamp() else { kdDebug() << "Activation: No timestamp at all" << endl; - // no timestamp at all, don't activate - because there's also creation timestamp - // done on CreateNotify, this case should happen only in case application - // maps again already used window, i.e. this won't happen after app startup + if( options->focusStealingPreventionLevel == 1 ) // low + return true; + // no timestamp at all, don't activate - because there's also creation timestamp + // done on CreateNotify, this case should happen only in case application + // maps again already used window, i.e. this won't happen after app startup return false; } + // options->focusStealingPreventionLevel == 2 // normal Time user_time = ac->userTime(); kdDebug( 1212 ) << "Activation, compared:" << time << ":" << user_time << ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl; return timestampCompare( time, user_time ) >= 0; // time >= user_time } // called from Client after FocusIn that wasn't initiated by KWin and the client // wasn't allowed to activate void Workspace::restoreFocus() { if( should_get_focus.count() > 0 ) requestFocus( should_get_focus.last()); else if( last_active_client ) requestFocus( last_active_client ); } void Workspace::clientAttentionChanged( Client* c, bool set ) { if( set ) { attention_chain.remove( c ); attention_chain.prepend( c ); } else attention_chain.remove( c ); } // This is used when a client should be shown active immediately after requestFocus(), // without waiting for the matching FocusIn that will really make the window the active one. // Used only in special cases, e.g. for MouseActivateRaiseandMove with transparent windows, bool Workspace::fakeRequestedActivity( Client* c ) { if( should_get_focus.count() > 0 && should_get_focus.last() == c ) { if( c->isActive()) return false; c->setActive( true ); return true; } return false; } void Workspace::unfakeActivity( Client* c ) { if( should_get_focus.count() > 0 && should_get_focus.last() == c ) { // TODO this will cause flicker, and probably is not needed if( last_active_client != NULL ) last_active_client->setActive( true ); else c->setActive( false ); } } //******************************************** // Client //******************************************** /*! Updates the user time (time of last action in the active window). This is called inside kwin for every action with the window that qualifies for user interaction (clicking on it, activate it externally, etc.). */ void Client::updateUserTime( Time time ) { if( time == CurrentTime ) time = qt_x_time; if( time != -1U && ( user_time == CurrentTime || timestampCompare( time, user_time ) > 0 )) // time > user_time user_time = time; } Time Client::readUserCreationTime() const { long result = -1; // Time == -1 means none Atom type; int format, status; unsigned long nitems = 0; unsigned long extra = 0; unsigned char *data = 0; KXErrorHandler handler; // ignore errors? status = XGetWindowProperty( qt_xdisplay(), window(), atoms->kde_net_wm_user_creation_time, 0, 10000, FALSE, XA_CARDINAL, &type, &format, &nitems, &extra, &data ); if (status == Success ) { if (data && nitems > 0) result = *((long*) data); XFree(data); } return result; } void Client::demandAttention( bool set ) { if( isActive()) set = false; info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention ); workspace()->clientAttentionChanged( this, set ); } // TODO I probably shouldn't be lazy here and do it without the macro, so that people can read it KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, const Client*, // ignore already existing splashes, toolbars, utilities, menus and topmenus, // as the app may show those before the main window !cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu() && Client::belongToSameApplication( cl, value, true )); Time Client::readUserTimeMapTimestamp( const KStartupInfoData* asn_data, const SessionInfo* session ) const { Time time = info->userTime(); kdDebug( 1212 ) << "User timestamp, initial:" << time << endl; // newer ASN timestamp always replaces user timestamp, unless user timestamp is 0 // helps e.g. with konqy reusing if( asn_data != NULL && time != 0 && ( time == -1U || ( asn_data->timestamp() != -1U && timestampCompare( asn_data->timestamp(), time ) > 0 ))) time = asn_data->timestamp(); kdDebug( 1212 ) << "User timestamp, ASN:" << time << endl; if( time == -1U ) { // The window doesn't have any timestamp. // If it's the first window for its application // (i.e. there's no other window from the same app), // use the _KDE_NET_WM_USER_CREATION_TIME trick. // Otherwise, refuse activation of a window // from already running application if this application // is not the active one. if( workspace()->activeClient() != NULL && !belongToSameApplication( workspace()->activeClient(), this, true )) { bool first_window = true; if( isTransient()) { if( workspace()->activeClient()->hasTransient( this, true )) ; // is transient for currently active window, even though it's not // the same app (e.g. kcookiejar dialog) -> allow activation else if( groupTransient() && mainClients().isEmpty()) ; // standalone transient else first_window = false; } else { if( workspace()->findClient( SameApplicationActiveHackPredicate( this ))) first_window = false; } if( !first_window ) { kdDebug( 1212 ) << "User timestamp, already exists:" << 0 << endl; return 0; // refuse activation } } // Creation time would just mess things up during session startup, // as possibly many apps are started up at the same time. // If there's no active window yet, no timestamp will be needed, // as plain Workspace::allowClientActivation() will return true // in such case. And if there's already active window, // it's better not to activate the new one. // Unless it was the active window at the time // of session saving and there was no user interaction yet, // this check will be done in Workspace::allowClientActiovationTimestamp(). if( session ) return -1U; time = readUserCreationTime(); } kdDebug( 1212 ) << "User timestamp, final:" << time << endl; return time; } /*! Sets the client's active state to \a act. This function does only change the visual appearance of the client, it does not change the focus setting. Use Workspace::activateClient() or Workspace::requestFocus() instead. If a client receives or looses the focus, it calls setActive() on its own. */ void Client::setActive( bool act) { if ( active == act ) return; active = act; workspace()->setActiveClient( act ? this : NULL, Allowed ); if ( active ) Notify::raise( Notify::Activate ); if ( !active && autoRaiseTimer ) { delete autoRaiseTimer; autoRaiseTimer = 0; } if( shade_mode == ShadeActivated ) setShade( ShadeNormal ); StackingUpdatesBlocker blocker( workspace()); workspace()->updateClientLayer( this ); // active windows may get different layer // TODO optimize? mainClients() may be a bit expensive ClientList mainclients = mainClients(); for( ClientList::ConstIterator it = mainclients.begin(); it != mainclients.end(); ++it ) if( (*it)->isFullScreen()) // fullscreens go high even if their transient is active workspace()->updateClientLayer( *it ); if( decoration != NULL ) decoration->activeChange(); updateMouseGrab(); } void Client::startupIdChanged() { KStartupInfoData asn_data; bool asn_valid = workspace()->checkStartupNotification( this, asn_data ); if( !asn_valid ) return; if( asn_data.desktop() != 0 ) workspace()->sendClientToDesktop( this, asn_data.desktop(), true ); if( asn_data.timestamp() != -1U ) { bool activate = workspace()->allowClientActivation( this, asn_data.timestamp()); if( asn_data.desktop() != 0 && !isOnCurrentDesktop()) activate = false; // it was started on different desktop than current one if( activate ) workspace()->activateClient( this ); else demandAttention(); } } } // namespace diff --git a/kwin/kcmkwin/kwinoptions/windows.cpp b/kwin/kcmkwin/kwinoptions/windows.cpp index efeae09727..89f04b514f 100644 --- a/kwin/kcmkwin/kwinoptions/windows.cpp +++ b/kwin/kcmkwin/kwinoptions/windows.cpp @@ -1,1046 +1,1091 @@ /* * windows.cpp * * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca * Copyright (c) 2001 Waldo Bastian bastian@kde.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id$ * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include "windows.h" // kwin config keywords #define KWIN_FOCUS "FocusPolicy" #define KWIN_PLACEMENT "Placement" #define KWIN_MOVE "MoveMode" #define KWIN_MINIMIZE_ANIM "AnimateMinimize" #define KWIN_MINIMIZE_ANIM_SPEED "AnimateMinimizeSpeed" #define KWIN_RESIZE_OPAQUE "ResizeMode" #define KWIN_GEOMETRY "GeometryTip" #define KWIN_AUTORAISE_INTERVAL "AutoRaiseInterval" #define KWIN_AUTORAISE "AutoRaise" #define KWIN_CLICKRAISE "ClickRaise" #define KWIN_ANIMSHADE "AnimateShade" #define KWIN_MOVE_RESIZE_MAXIMIZED "MoveResizeMaximizedWindows" #define KWIN_ALTTABMODE "AltTabStyle" #define KWIN_TRAVERSE_ALL "TraverseAll" #define KWIN_SHOW_POPUP "ShowPopup" #define KWIN_ROLL_OVER_DESKTOPS "RollOverDesktops" #define KWIN_SHADEHOVER "ShadeHover" #define KWIN_SHADEHOVER_INTERVAL "ShadeHoverInterval" +#define KWIN_FOCUS_STEALING "FocusStealingPreventionLevel" // kwm config keywords #define KWM_ELECTRIC_BORDER "ElectricBorders" #define KWM_ELECTRIC_BORDER_DELAY "ElectricBorderDelay" //CT 15mar 98 - magics #define KWM_BRDR_SNAP_ZONE "BorderSnapZone" #define KWM_BRDR_SNAP_ZONE_DEFAULT 10 #define KWM_WNDW_SNAP_ZONE "WindowSnapZone" #define KWM_WNDW_SNAP_ZONE_DEFAULT 10 #define MAX_BRDR_SNAP 100 #define MAX_WNDW_SNAP 100 #define MAX_EDGE_RES 1000 KFocusConfig::~KFocusConfig () { if (standAlone) delete config; } // removed the LCD display over the slider - this is not good GUI design :) RNolden 051701 KFocusConfig::KFocusConfig (bool _standAlone, KConfig *_config, QWidget * parent, const char *) : KCModule(parent, "kcmkwm"), config(_config), standAlone(_standAlone) { QString wtstr; QBoxLayout *lay = new QVBoxLayout (this, 0, KDialog::spacingHint()); //iTLabel = new QLabel(i18n(" Allowed overlap:\n" // "(% of desktop space)"), // plcBox); //iTLabel->setAlignment(AlignTop|AlignHCenter); //pLay->addWidget(iTLabel,1,1); //interactiveTrigger = new QSpinBox(0, 500, 1, plcBox); //pLay->addWidget(interactiveTrigger,1,2); //pLay->addRowSpacing(2,KDialog::spacingHint()); //lay->addWidget(plcBox); // focus policy fcsBox = new QButtonGroup(i18n("Focus"),this); fcsBox->setColumnLayout( 0, Qt::Horizontal ); QBoxLayout *fLay = new QVBoxLayout(fcsBox->layout(), KDialog::spacingHint()); QBoxLayout *cLay = new QHBoxLayout(fLay); QLabel *fLabel = new QLabel(i18n("&Policy:"), fcsBox); cLay->addWidget(fLabel, 0); focusCombo = new QComboBox(false, fcsBox); focusCombo->insertItem(i18n("Click to Focus"), CLICK_TO_FOCUS); focusCombo->insertItem(i18n("Focus Follows Mouse"), FOCUS_FOLLOWS_MOUSE); focusCombo->insertItem(i18n("Focus Under Mouse"), FOCUS_UNDER_MOUSE); focusCombo->insertItem(i18n("Focus Strictly Under Mouse"), FOCUS_STRICTLY_UNDER_MOUSE); cLay->addWidget(focusCombo,1 ,Qt::AlignLeft); fLabel->setBuddy(focusCombo); // FIXME, when more policies have been added to KWin wtstr = i18n("The focus policy is used to determine the active window, i.e." " the window you can work in.
    " "
  • Click to focus: A window becomes active when you click into it. This is the behavior" " you might know from other operating systems.
  • " "
  • Focus follows mouse: Moving the mouse pointer actively on to a" " normal window activates it. Very practical if you are using the mouse a lot.
  • " "
  • Focus under mouse: The window that happens to be under the" " mouse pointer becomes active. If the mouse points nowhere, the last window" " that was under the mouse has focus.
  • " "
  • Focus strictly under mouse: This is even worse than" " 'Focus under mouse'. Only the window under the mouse pointer is" " active. If the mouse points nowhere, nothing has focus." "
" " Note that 'Focus under mouse' and 'Focus strictly under mouse' are not" " particularly useful. They are only provided for old-fashioned" " die-hard UNIX people ;-)" ); QWhatsThis::add( focusCombo, wtstr); QWhatsThis::add(fLabel, wtstr); connect(focusCombo, SIGNAL(activated(int)), this, SLOT(setAutoRaiseEnabled()) ); // autoraise delay autoRaiseOn = new QCheckBox(i18n("Auto &raise"), fcsBox); fLay->addWidget(autoRaiseOn); connect(autoRaiseOn,SIGNAL(toggled(bool)), this, SLOT(autoRaiseOnTog(bool))); autoRaise = new KIntNumInput(500, fcsBox); autoRaise->setLabel(i18n("Dela&y:"), Qt::AlignVCenter|Qt::AlignLeft); autoRaise->setRange(0, 3000, 100, true); autoRaise->setSteps(100,100); autoRaise->setSuffix(i18n(" msec")); fLay->addWidget(autoRaise); clickRaiseOn = new QCheckBox(i18n("C&lick raise active window"), fcsBox); connect(clickRaiseOn,SIGNAL(toggled(bool)), this, SLOT(clickRaiseOnTog(bool))); fLay->addWidget(clickRaiseOn); // fLay->addColSpacing(0,QMAX(autoRaiseOn->sizeHint().width(), // clickRaiseOn->sizeHint().width()) + 15); QWhatsThis::add( autoRaiseOn, i18n("When this option is enabled, a window in the background will automatically" " come to the front when the mouse pointer has been over it for some time.") ); wtstr = i18n("This is the delay after which the window that the mouse pointer is over will automatically" " come to the front."); QWhatsThis::add( autoRaise, wtstr ); QWhatsThis::add( clickRaiseOn, i18n("When this option is enabled, the active window will be brought to the" " front when you click somewhere into the window contents. To change" " it for inactive windows, you need to change the settings" " in the Actions tab.") ); lay->addWidget(fcsBox); kbdBox = new QButtonGroup(i18n("Navigation"), this); kbdBox->setColumnLayout( 0, Qt::Horizontal ); QGridLayout *kLay = new QGridLayout(kbdBox->layout(), 4, 4, KDialog::spacingHint()); QLabel *altTabLabel = new QLabel( i18n("Walk through windows mode:"), kbdBox); kLay->addWidget(altTabLabel, 1, 0); kdeMode = new QRadioButton(i18n("&KDE"), kbdBox); kLay->addWidget(kdeMode, 1, 1); cdeMode = new QRadioButton(i18n("CD&E"), kbdBox); kLay->addWidget(cdeMode, 1, 2); wtstr = i18n("Hold down the Alt key and press the Tab key repeatedly to walk" " through the windows on the current desktop (the Alt+Tab" " combination can be reconfigured). The two different modes mean:
    " "
  • KDE: a nice widget is shown, displaying the icons of all windows to" " walk through and the title of the currently selected one;" "
  • CDE: the focus is passed to a new window each time Tab is pressed." " No fancy widget.
"); QWhatsThis::add( altTabLabel, wtstr ); QWhatsThis::add( kdeMode, wtstr ); QWhatsThis::add( cdeMode, wtstr ); traverseAll = new QCheckBox( i18n( "&Traverse windows on all desktops" ), kbdBox ); kLay->addMultiCellWidget( traverseAll, 2, 2, 0, 2 ); wtstr = i18n( "Leave this option disabled if you want to limit walking through" " windows to the current desktop." ); QWhatsThis::add( traverseAll, wtstr ); rollOverDesktops = new QCheckBox( i18n("Desktop navi&gation wraps around"), kbdBox ); kLay->addMultiCellWidget(rollOverDesktops, 3, 3, 0, 2); wtstr = i18n( "Enable this option if you want keyboard or active desktop border navigation beyond" " an edge desktop to bring you to the desktop at the opposite edge." ); QWhatsThis::add( rollOverDesktops, wtstr ); showPopupinfo = new QCheckBox( i18n("Popup desktop name on desktop &switch"), kbdBox ); kLay->addMultiCellWidget(showPopupinfo, 4, 4, 0, 2); wtstr = i18n( "Enable this option if you wish to see the current desktop" " name popup whenever the current desktop is changed." ); QWhatsThis::add( showPopupinfo, wtstr ); lay->addWidget(kbdBox); lay->addStretch(); // Any changes goes to slotChanged() connect(focusCombo, SIGNAL(activated(int)), SLOT(changed())); connect(fcsBox, SIGNAL(clicked(int)), SLOT(changed())); connect(autoRaise, SIGNAL(valueChanged(int)), SLOT(changed())); connect(kdeMode, SIGNAL(clicked()), SLOT(changed())); connect(cdeMode, SIGNAL(clicked()), SLOT(changed())); connect(traverseAll, SIGNAL(clicked()), SLOT(changed())); connect(rollOverDesktops, SIGNAL(clicked()), SLOT(changed())); connect(showPopupinfo, SIGNAL(clicked()), SLOT(changed())); load(); } int KFocusConfig::getFocus() { return focusCombo->currentItem(); } void KFocusConfig::setFocus(int foc) { focusCombo->setCurrentItem(foc); // this will disable/hide the auto raise delay widget if focus==click setAutoRaiseEnabled(); } void KFocusConfig::setAutoRaiseInterval(int tb) { autoRaise->setValue(tb); } int KFocusConfig::getAutoRaiseInterval() { return autoRaise->value(); } void KFocusConfig::setAutoRaise(bool on) { autoRaiseOn->setChecked(on); } void KFocusConfig::setClickRaise(bool on) { clickRaiseOn->setChecked(on); } void KFocusConfig::setAutoRaiseEnabled() { // the auto raise related widgets are: autoRaise if ( focusCombo->currentItem() != CLICK_TO_FOCUS ) { autoRaiseOn->setEnabled(true); autoRaiseOnTog(autoRaiseOn->isChecked()); } else { autoRaiseOn->setEnabled(false); autoRaiseOnTog(false); } } void KFocusConfig::autoRaiseOnTog(bool a) { autoRaise->setEnabled(a); clickRaiseOn->setEnabled( !a ); if ( a ) { clickRaiseOn->setChecked( TRUE ); if(getAutoRaiseInterval() == 0) setAutoRaiseInterval(750); } } void KFocusConfig::clickRaiseOnTog(bool ) { } void KFocusConfig::setAltTabMode(bool a) { kdeMode->setChecked(a); cdeMode->setChecked(!a); } void KFocusConfig::setTraverseAll(bool a) { traverseAll->setChecked(a); } void KFocusConfig::setRollOverDesktops(bool a) { rollOverDesktops->setChecked(a); } void KFocusConfig::setShowPopupinfo(bool a) { showPopupinfo->setChecked(a); } void KFocusConfig::load( void ) { QString key; config->setGroup( "Windows" ); key = config->readEntry(KWIN_FOCUS); if( key == "ClickToFocus") setFocus(CLICK_TO_FOCUS); else if( key == "FocusFollowsMouse") setFocus(FOCUS_FOLLOWS_MOUSE); else if(key == "FocusUnderMouse") setFocus(FOCUS_UNDER_MOUSE); else if(key == "FocusStrictlyUnderMouse") setFocus(FOCUS_STRICTLY_UNDER_MOUSE); int k = config->readNumEntry(KWIN_AUTORAISE_INTERVAL,0); setAutoRaiseInterval(k); key = config->readEntry(KWIN_AUTORAISE); setAutoRaise(key == "on"); key = config->readEntry(KWIN_CLICKRAISE); setClickRaise(key != "off"); setAutoRaiseEnabled(); // this will disable/hide the auto raise delay widget if focus==click key = config->readEntry(KWIN_ALTTABMODE, "KDE"); setAltTabMode(key == "KDE"); setRollOverDesktops( config->readBoolEntry(KWIN_ROLL_OVER_DESKTOPS, true )); config->setGroup( "PopupInfo" ); setShowPopupinfo( config->readBoolEntry(KWIN_SHOW_POPUP, false )); config->setGroup( "TabBox" ); setTraverseAll( config->readBoolEntry(KWIN_TRAVERSE_ALL, false )); config->setGroup("Desktops"); setChanged(false); } void KFocusConfig::save( void ) { int v; config->setGroup( "Windows" ); v = getFocus(); if (v == CLICK_TO_FOCUS) config->writeEntry(KWIN_FOCUS,"ClickToFocus"); else if (v == FOCUS_UNDER_MOUSE) config->writeEntry(KWIN_FOCUS,"FocusUnderMouse"); else if (v == FOCUS_STRICTLY_UNDER_MOUSE) config->writeEntry(KWIN_FOCUS,"FocusStrictlyUnderMouse"); else config->writeEntry(KWIN_FOCUS,"FocusFollowsMouse"); v = getAutoRaiseInterval(); if (v <0) v = 0; config->writeEntry(KWIN_AUTORAISE_INTERVAL,v); if (autoRaiseOn->isChecked()) config->writeEntry(KWIN_AUTORAISE, "on"); else config->writeEntry(KWIN_AUTORAISE, "off"); if (clickRaiseOn->isChecked()) config->writeEntry(KWIN_CLICKRAISE, "on"); else config->writeEntry(KWIN_CLICKRAISE, "off"); if (kdeMode->isChecked()) config->writeEntry(KWIN_ALTTABMODE, "KDE"); else config->writeEntry(KWIN_ALTTABMODE, "CDE"); config->writeEntry( KWIN_ROLL_OVER_DESKTOPS, rollOverDesktops->isChecked()); config->setGroup( "PopupInfo" ); config->writeEntry( KWIN_SHOW_POPUP, showPopupinfo->isChecked()); config->setGroup( "TabBox" ); config->writeEntry( KWIN_TRAVERSE_ALL , traverseAll->isChecked()); config->setGroup("Desktops"); if (standAlone) { config->sync(); if ( !kapp->dcopClient()->isAttached() ) kapp->dcopClient()->attach(); kapp->dcopClient()->send("kwin*", "", "reconfigure()", ""); } setChanged(false); } void KFocusConfig::defaults() { setFocus(CLICK_TO_FOCUS); setAutoRaise(false); setClickRaise(true); setAltTabMode(true); setTraverseAll( false ); setRollOverDesktops(true); setShowPopupinfo(false); setChanged(true); } KAdvancedConfig::~KAdvancedConfig () { if (standAlone) delete config; } KAdvancedConfig::KAdvancedConfig (bool _standAlone, KConfig *_config, QWidget *parent, const char *) : KCModule(parent, "kcmkwm"), config(_config), standAlone(_standAlone) { QString wtstr; QBoxLayout *lay = new QVBoxLayout (this, 0, KDialog::spacingHint()); //iTLabel = new QLabel(i18n(" Allowed overlap:\n" // "(% of desktop space)"), // plcBox); //iTLabel->setAlignment(AlignTop|AlignHCenter); //pLay->addWidget(iTLabel,1,1); //interactiveTrigger = new QSpinBox(0, 500, 1, plcBox); //pLay->addWidget(interactiveTrigger,1,2); //pLay->addRowSpacing(2,KDialog::spacingHint()); //lay->addWidget(plcBox); shBox = new QVButtonGroup(i18n("Shading"), this); animateShade = new QCheckBox(i18n("Anima&te"), shBox); QWhatsThis::add(animateShade, i18n("Animate the action of reducing the window to its titlebar (shading)" " as well as the expansion of a shaded window") ); shadeHoverOn = new QCheckBox(i18n("&Enable hover"), shBox); connect(shadeHoverOn, SIGNAL(toggled(bool)), this, SLOT(shadeHoverChanged(bool))); shadeHover = new KIntNumInput(500, shBox); shadeHover->setLabel(i18n("Dela&y:"), Qt::AlignVCenter|Qt::AlignLeft); shadeHover->setRange(0, 3000, 100, true); shadeHover->setSteps(100, 100); shadeHover->setSuffix(i18n(" msec")); QWhatsThis::add(shadeHoverOn, i18n("If Shade Hover is enabled, a shaded window will un-shade automatically " "when the mouse pointer has been over the title bar for some time.")); wtstr = i18n("Sets the time in milliseconds before the window unshades " "when the mouse pointer goes over the shaded window."); QWhatsThis::add(shadeHover, wtstr); lay->addWidget(shBox); // Any changes goes to slotChanged() connect(animateShade, SIGNAL(toggled(bool)), SLOT(changed())); connect(shadeHoverOn, SIGNAL(toggled(bool)), SLOT(changed())); connect(shadeHover, SIGNAL(valueChanged(int)), SLOT(changed())); electricBox = new QVButtonGroup(i18n("Active Desktop Borders"), this); electricBox->setMargin(15); QWhatsThis::add( electricBox, i18n("If this option is enabled, moving the mouse to a screen border" " will change your desktop. This is e.g. useful if you want to drag windows from one desktop" " to the other.") ); active_disable = new QRadioButton(i18n("D&isabled"), electricBox); active_move = new QRadioButton(i18n("Only &when moving windows"), electricBox); active_always = new QRadioButton(i18n("A&lways enabled"), electricBox); delays = new KIntNumInput(10, electricBox); delays->setRange(0, MAX_EDGE_RES, 50, true); delays->setSuffix(i18n(" msec")); delays->setLabel(i18n("Desktop &switch delay:")); QWhatsThis::add( delays, i18n("Here you can set a delay for switching desktops using the active" " borders feature. Desktops will be switched after the mouse has been pushed against a screen border" " for the specified number of milliseconds.") ); connect( electricBox, SIGNAL(clicked(int)), this, SLOT(setEBorders())); // Any changes goes to slotChanged() connect(electricBox, SIGNAL(clicked(int)), SLOT(changed())); connect(delays, SIGNAL(valueChanged(int)), SLOT(changed())); lay->addWidget(electricBox); + QHBoxLayout* focusStealingLayout = new QHBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint()); + QLabel* focusStealingLabel = new QLabel( i18n( "Focus Stealing Prevention Level:" ), this ); + focusStealing = new QComboBox( this ); + focusStealing->insertItem( i18n( "Focus Stealing Prevention Level", "None" )); + focusStealing->insertItem( i18n( "Focus Stealing Prevention Level", "Low" )); + focusStealing->insertItem( i18n( "Focus Stealing Prevention Level", "Normal" )); + focusStealing->insertItem( i18n( "Focus Stealing Prevention Level", "High" )); + focusStealing->insertItem( i18n( "Focus Stealing Prevention Level", "Extreme" )); + focusStealingLabel->setBuddy( focusStealing ); + focusStealingLayout->addWidget( focusStealingLabel ); + focusStealingLayout->addWidget( focusStealing, AlignLeft ); + wtstr = i18n( "This option specifies how much will KWin try to prevent unwanted focus stealing " + "caused by unexpected activation of new windows.
    " + "
  • None: The standard old behaviour - prevention is turned off " + "and new windows get always activated.
  • " + "
  • Low: Prevention is enabled; when some window doesn't have support " + "for the underlying mechanism and KWin cannot reliably decide whether to " + "activate the window or not, it will be activated. This setting may have both" + "worse and better results than normal level depending on the applications.
  • " + "
  • Normal: Prevention is enabled; the default setting.
  • " + "
  • High: New windows get activated only if no window is currently active " + "or if they belong to the currently active application. This setting is probably " + "not really usable when noting using mouse focus policy.
  • " + "
  • Extreme: All windows must be explicitly activated by the user.
  • " + "
" ); + QWhatsThis::add( focusStealing, wtstr ); + QWhatsThis::add( focusStealingLabel, wtstr ); + + connect(focusStealing, SIGNAL(activated(int)), SLOT(changed())); + + lay->addLayout( focusStealingLayout ); + lay->addStretch(); load(); } void KAdvancedConfig::setShadeHover(bool on) { shadeHoverOn->setChecked(on); shadeHover->setEnabled(on); } void KAdvancedConfig::setShadeHoverInterval(int k) { shadeHover->setValue(k); } int KAdvancedConfig::getShadeHoverInterval() { return shadeHover->value(); } void KAdvancedConfig::shadeHoverChanged(bool a) { shadeHover->setEnabled(a); } void KAdvancedConfig::setAnimateShade(bool a) { animateShade->setChecked(a); } +void KAdvancedConfig::setFocusStealing(int l) { + l = KMAX( 0, KMIN( 4, l )); + focusStealing->setCurrentItem(l); +} + void KAdvancedConfig::load( void ) { config->setGroup( "Windows" ); setAnimateShade(config->readBoolEntry(KWIN_ANIMSHADE, true)); setShadeHover(config->readBoolEntry(KWIN_SHADEHOVER, false)); setShadeHoverInterval(config->readNumEntry(KWIN_SHADEHOVER_INTERVAL, 250)); setElectricBorders(config->readNumEntry(KWM_ELECTRIC_BORDER, false)); setElectricBorderDelay(config->readNumEntry(KWM_ELECTRIC_BORDER_DELAY, 150)); + + setFocusStealing( config->readNumEntry(KWIN_FOCUS_STEALING, 2 )); + setChanged(false); } void KAdvancedConfig::save( void ) { int v; config->setGroup( "Windows" ); config->writeEntry(KWIN_ANIMSHADE, animateShade->isChecked()); if (shadeHoverOn->isChecked()) config->writeEntry(KWIN_SHADEHOVER, "on"); else config->writeEntry(KWIN_SHADEHOVER, "off"); v = getShadeHoverInterval(); if (v<0) v = 0; config->writeEntry(KWIN_SHADEHOVER_INTERVAL, v); config->writeEntry(KWM_ELECTRIC_BORDER, getElectricBorders()); config->writeEntry(KWM_ELECTRIC_BORDER_DELAY,getElectricBorderDelay()); + + config->writeEntry(KWIN_FOCUS_STEALING, focusStealing->currentItem()); if (standAlone) { config->sync(); if ( !kapp->dcopClient()->isAttached() ) kapp->dcopClient()->attach(); kapp->dcopClient()->send("kwin*", "", "reconfigure()", ""); } setChanged(false); } void KAdvancedConfig::defaults() { setAnimateShade(true); setShadeHover(false); setShadeHoverInterval(250); setElectricBorders(0); setElectricBorderDelay(150); + setFocusStealing(2); setChanged(true); } void KAdvancedConfig::setEBorders() { delays->setEnabled(!active_disable->isChecked()); } int KAdvancedConfig::getElectricBorders() { if (active_move->isChecked()) return 1; if (active_always->isChecked()) return 2; return 0; } int KAdvancedConfig::getElectricBorderDelay() { return delays->value(); } void KAdvancedConfig::setElectricBorders(int i){ switch(i) { case 1: active_move->setChecked(true); break; case 2: active_always->setChecked(true); break; default: active_disable->setChecked(true); break; } setEBorders(); } void KAdvancedConfig::setElectricBorderDelay(int delay) { delays->setValue(delay); } KMovingConfig::~KMovingConfig () { if (standAlone) delete config; } KMovingConfig::KMovingConfig (bool _standAlone, KConfig *_config, QWidget *parent, const char *) : KCModule(parent, "kcmkwm"), config(_config), standAlone(_standAlone) { QString wtstr; QBoxLayout *lay = new QVBoxLayout (this, 0, KDialog::spacingHint()); windowsBox = new QButtonGroup(i18n("Windows"), this); windowsBox->setColumnLayout( 0, Qt::Horizontal ); QBoxLayout *wLay = new QVBoxLayout (windowsBox->layout(), KDialog::spacingHint()); QBoxLayout *bLay = new QVBoxLayout; wLay->addLayout(bLay); opaque = new QCheckBox(i18n("Di&splay content in moving windows"), windowsBox); bLay->addWidget(opaque); QWhatsThis::add( opaque, i18n("Enable this option if you want a window's content to be fully shown" " while moving it, instead of just showing a window 'skeleton'. The result may not be satisfying" " on slow machines without graphic acceleration.") ); resizeOpaqueOn = new QCheckBox(i18n("Display content in &resizing windows"), windowsBox); bLay->addWidget(resizeOpaqueOn); QWhatsThis::add( resizeOpaqueOn, i18n("Enable this option if you want a window's content to be shown" " while resizing it, instead of just showing a window 'skeleton'. The result may not be satisfying" " on slow machines.") ); geometryTipOn = new QCheckBox(i18n("Display window &geometry when moving or resizing"), windowsBox); bLay->addWidget(geometryTipOn); QWhatsThis::add(geometryTipOn, i18n("Enable this option if you want a window's geometry to be displayed" " while it is being moved or resized. The window position relative" " to the top-left corner of the screen is displayed together with" " its size.")); QGridLayout *rLay = new QGridLayout(2,3); bLay->addLayout(rLay); rLay->setColStretch(0,0); rLay->setColStretch(1,1); minimizeAnimOn = new QCheckBox(i18n("Animate minimi&ze and restore"), windowsBox); QWhatsThis::add( minimizeAnimOn, i18n("Enable this option if you want an animation shown when" " windows are minimized or restored." ) ); rLay->addWidget(minimizeAnimOn,0,0); minimizeAnimSlider = new QSlider(0,10,10,0,QSlider::Horizontal, windowsBox); minimizeAnimSlider->setSteps(1, 1); // QSlider::Below clashes with a X11/X.h #define #undef Below minimizeAnimSlider->setTickmarks(QSlider::Below); rLay->addMultiCellWidget(minimizeAnimSlider,0,0,1,2); connect(minimizeAnimOn, SIGNAL(toggled(bool)), this, SLOT(setMinimizeAnim(bool))); connect(minimizeAnimSlider, SIGNAL(valueChanged(int)), this, SLOT(setMinimizeAnimSpeed(int))); minimizeAnimSlowLabel= new QLabel(i18n("Slow"),windowsBox); minimizeAnimSlowLabel->setAlignment(Qt::AlignTop|Qt::AlignLeft); rLay->addWidget(minimizeAnimSlowLabel,1,1); minimizeAnimFastLabel= new QLabel(i18n("Fast"),windowsBox); minimizeAnimFastLabel->setAlignment(Qt::AlignTop|Qt::AlignRight); rLay->addWidget(minimizeAnimFastLabel,1,2); wtstr = i18n("Here you can set the speed of the animation shown when windows are" " minimized and restored. "); QWhatsThis::add( minimizeAnimSlider, wtstr ); QWhatsThis::add( minimizeAnimSlowLabel, wtstr ); QWhatsThis::add( minimizeAnimFastLabel, wtstr ); moveResizeMaximized = new QCheckBox( i18n("Allow moving and resizing o&f maximized windows"), windowsBox); bLay->addWidget(moveResizeMaximized); QWhatsThis::add(moveResizeMaximized, i18n("When enabled, this feature activates the border of maximized windows" " and allows you to move or resize them," " just like for normal windows")); QBoxLayout *vLay = new QHBoxLayout(bLay); QLabel *plcLabel = new QLabel(i18n("&Placement:"),windowsBox); placementCombo = new QComboBox(false, windowsBox); placementCombo->insertItem(i18n("Smart"), SMART_PLACEMENT); placementCombo->insertItem(i18n("Cascade"), CASCADE_PLACEMENT); placementCombo->insertItem(i18n("Random"), RANDOM_PLACEMENT); placementCombo->insertItem(i18n("Centered"), CENTERED_PLACEMENT); placementCombo->insertItem(i18n("Zero-Cornered"), ZEROCORNERED_PLACEMENT); // CT: disabling is needed as long as functionality misses in kwin //placementCombo->insertItem(i18n("Interactive"), INTERACTIVE_PLACEMENT); //placementCombo->insertItem(i18n("Manual"), MANUAL_PLACEMENT); placementCombo->setCurrentItem(SMART_PLACEMENT); // FIXME, when more policies have been added to KWin wtstr = i18n("The placement policy determines where a new window" " will appear on the desktop. For now, there are three different policies:" "
  • Smart will try to achieve a minimum overlap of windows
  • " "
  • Cascade will cascade the windows
  • " "
  • Random will use a random position
") ; QWhatsThis::add( plcLabel, wtstr); QWhatsThis::add( placementCombo, wtstr); plcLabel->setBuddy(placementCombo); vLay->addWidget(plcLabel, 0); vLay->addWidget(placementCombo, 1, Qt::AlignLeft); bLay->addSpacing(10); lay->addWidget(windowsBox); //iTLabel = new QLabel(i18n(" Allowed overlap:\n" // "(% of desktop space)"), // plcBox); //iTLabel->setAlignment(AlignTop|AlignHCenter); //pLay->addWidget(iTLabel,1,1); //interactiveTrigger = new QSpinBox(0, 500, 1, plcBox); //pLay->addWidget(interactiveTrigger,1,2); //pLay->addRowSpacing(2,KDialog::spacingHint()); //lay->addWidget(plcBox); //CT 15mar98 - add EdgeResistance, BorderAttractor, WindowsAttractor config MagicBox = new QVButtonGroup(i18n("Snap Zones"), this); MagicBox->setMargin(15); BrdrSnap = new KIntNumInput(10, MagicBox); BrdrSnap->setSpecialValueText( i18n("none") ); BrdrSnap->setRange( 0, MAX_BRDR_SNAP); BrdrSnap->setLabel(i18n("&Border snap zone:")); BrdrSnap->setSuffix(i18n(" pixels")); BrdrSnap->setSteps(1,10); QWhatsThis::add( BrdrSnap, i18n("Here you can set the snap zone for screen borders, i.e." " the 'strength' of the magnetic field which will make windows snap to the border when" " moved near it.") ); WndwSnap = new KIntNumInput(10, MagicBox); WndwSnap->setSpecialValueText( i18n("none") ); WndwSnap->setRange( 0, MAX_WNDW_SNAP); WndwSnap->setLabel(i18n("&Window snap zone:")); WndwSnap->setSuffix( i18n(" pixels")); BrdrSnap->setSteps(1,10); QWhatsThis::add( WndwSnap, i18n("Here you can set the snap zone for windows, i.e." " the 'strength' of the magnetic field which will make windows snap to each other when" " they're moved near another window.") ); OverlapSnap=new QCheckBox(i18n("Snap windows onl&y when overlapping"),MagicBox); QWhatsThis::add( OverlapSnap, i18n("Here you can set that windows will be only" " snapped if you try to overlap them, i.e. they won't be snapped if the windows" " comes only near another window or border.") ); lay->addWidget(MagicBox); lay->addStretch(); load(); // Any changes goes to slotChanged() connect( opaque, SIGNAL(clicked()), SLOT(changed())); connect( resizeOpaqueOn, SIGNAL(clicked()), SLOT(changed())); connect( geometryTipOn, SIGNAL(clicked()), SLOT(changed())); connect( minimizeAnimOn, SIGNAL(clicked() ), SLOT(changed())); connect( minimizeAnimSlider, SIGNAL(valueChanged(int)), SLOT(changed())); connect( moveResizeMaximized, SIGNAL(toggled(bool)), SLOT(changed())); connect( placementCombo, SIGNAL(activated(int)), SLOT(changed())); connect( BrdrSnap, SIGNAL(valueChanged(int)), SLOT(changed())); connect( WndwSnap, SIGNAL(valueChanged(int)), SLOT(changed())); connect( OverlapSnap, SIGNAL(clicked()), SLOT(changed())); } int KMovingConfig::getMove() { return (opaque->isChecked())? OPAQUE : TRANSPARENT; } void KMovingConfig::setMove(int trans) { opaque->setChecked(trans == OPAQUE); } void KMovingConfig::setGeometryTip(bool showGeometryTip) { geometryTipOn->setChecked(showGeometryTip); } bool KMovingConfig::getGeometryTip() { return geometryTipOn->isChecked(); } // placement policy --- CT 31jan98 --- int KMovingConfig::getPlacement() { return placementCombo->currentItem(); } void KMovingConfig::setPlacement(int plac) { placementCombo->setCurrentItem(plac); } bool KMovingConfig::getMinimizeAnim() { return minimizeAnimOn->isChecked(); } int KMovingConfig::getMinimizeAnimSpeed() { return minimizeAnimSlider->value(); } void KMovingConfig::setMinimizeAnim(bool anim) { minimizeAnimOn->setChecked( anim ); minimizeAnimSlider->setEnabled( anim ); minimizeAnimSlowLabel->setEnabled( anim ); minimizeAnimFastLabel->setEnabled( anim ); } void KMovingConfig::setMinimizeAnimSpeed(int speed) { minimizeAnimSlider->setValue(speed); } int KMovingConfig::getResizeOpaque() { return (resizeOpaqueOn->isChecked())? RESIZE_OPAQUE : RESIZE_TRANSPARENT; } void KMovingConfig::setResizeOpaque(int opaque) { resizeOpaqueOn->setChecked(opaque == RESIZE_OPAQUE); } void KMovingConfig::setMoveResizeMaximized(bool a) { moveResizeMaximized->setChecked(a); } void KMovingConfig::load( void ) { QString key; config->setGroup( "Windows" ); key = config->readEntry(KWIN_MOVE, "Opaque"); if( key == "Transparent") setMove(TRANSPARENT); else if( key == "Opaque") setMove(OPAQUE); //CT 17Jun1998 - variable animation speed from 0 (none!!) to 10 (max) bool anim = config->readBoolEntry(KWIN_MINIMIZE_ANIM, true ); int animSpeed = config->readNumEntry(KWIN_MINIMIZE_ANIM_SPEED, 5); if( animSpeed < 1 ) animSpeed = 0; if( animSpeed > 10 ) animSpeed = 10; setMinimizeAnim( anim ); setMinimizeAnimSpeed( animSpeed ); // DF: please keep the default consistent with kwin (options.cpp line 145) key = config->readEntry(KWIN_RESIZE_OPAQUE, "Opaque"); if( key == "Opaque") setResizeOpaque(RESIZE_OPAQUE); else if ( key == "Transparent") setResizeOpaque(RESIZE_TRANSPARENT); //KS 10Jan2003 - Geometry Tip during window move/resize bool showGeomTip = config->readBoolEntry(KWIN_GEOMETRY, false); setGeometryTip( showGeomTip ); // placement policy --- CT 19jan98 --- key = config->readEntry(KWIN_PLACEMENT); //CT 13mar98 interactive placement // if( key.left(11) == "interactive") { // setPlacement(INTERACTIVE_PLACEMENT); // int comma_pos = key.find(','); // if (comma_pos < 0) // interactiveTrigger->setValue(0); // else // interactiveTrigger->setValue (key.right(key.length() // - comma_pos).toUInt(0)); // iTLabel->setEnabled(true); // interactiveTrigger->show(); // } // else { // interactiveTrigger->setValue(0); // iTLabel->setEnabled(false); // interactiveTrigger->hide(); if( key == "Random") setPlacement(RANDOM_PLACEMENT); else if( key == "Cascade") setPlacement(CASCADE_PLACEMENT); //CT 31jan98 //CT 31mar98 manual placement else if( key == "manual") setPlacement(MANUAL_PLACEMENT); else if( key == "Centered") setPlacement(CENTERED_PLACEMENT); else if( key == "ZeroCornered") setPlacement(ZEROCORNERED_PLACEMENT); else setPlacement(SMART_PLACEMENT); // } setMoveResizeMaximized(config->readBoolEntry(KWIN_MOVE_RESIZE_MAXIMIZED, true)); int v; v = config->readNumEntry(KWM_BRDR_SNAP_ZONE, KWM_BRDR_SNAP_ZONE_DEFAULT); if (v > MAX_BRDR_SNAP) setBorderSnapZone(MAX_BRDR_SNAP); else if (v < 0) setBorderSnapZone (0); else setBorderSnapZone(v); v = config->readNumEntry(KWM_WNDW_SNAP_ZONE, KWM_WNDW_SNAP_ZONE_DEFAULT); if (v > MAX_WNDW_SNAP) setWindowSnapZone(MAX_WNDW_SNAP); else if (v < 0) setWindowSnapZone (0); else setWindowSnapZone(v); OverlapSnap->setChecked(config->readBoolEntry("SnapOnlyWhenOverlapping",false)); setChanged(false); } void KMovingConfig::save( void ) { int v; config->setGroup( "Windows" ); v = getMove(); if (v == TRANSPARENT) config->writeEntry(KWIN_MOVE,"Transparent"); else config->writeEntry(KWIN_MOVE,"Opaque"); config->writeEntry(KWIN_GEOMETRY, getGeometryTip()); // placement policy --- CT 31jan98 --- v =getPlacement(); if (v == RANDOM_PLACEMENT) config->writeEntry(KWIN_PLACEMENT, "Random"); else if (v == CASCADE_PLACEMENT) config->writeEntry(KWIN_PLACEMENT, "Cascade"); else if (v == CENTERED_PLACEMENT) config->writeEntry(KWIN_PLACEMENT, "Centered"); else if (v == ZEROCORNERED_PLACEMENT) config->writeEntry(KWIN_PLACEMENT, "ZeroCornered"); //CT 13mar98 manual and interactive placement // else if (v == MANUAL_PLACEMENT) // config->writeEntry(KWIN_PLACEMENT, "Manual"); // else if (v == INTERACTIVE_PLACEMENT) { // QString tmpstr = QString("Interactive,%1").arg(interactiveTrigger->value()); // config->writeEntry(KWIN_PLACEMENT, tmpstr); // } else config->writeEntry(KWIN_PLACEMENT, "Smart"); config->writeEntry(KWIN_MINIMIZE_ANIM, getMinimizeAnim()); config->writeEntry(KWIN_MINIMIZE_ANIM_SPEED, getMinimizeAnimSpeed()); v = getResizeOpaque(); if (v == RESIZE_OPAQUE) config->writeEntry(KWIN_RESIZE_OPAQUE, "Opaque"); else config->writeEntry(KWIN_RESIZE_OPAQUE, "Transparent"); config->writeEntry(KWIN_MOVE_RESIZE_MAXIMIZED, moveResizeMaximized->isChecked()); config->writeEntry(KWM_BRDR_SNAP_ZONE,getBorderSnapZone()); config->writeEntry(KWM_WNDW_SNAP_ZONE,getWindowSnapZone()); config->writeEntry("SnapOnlyWhenOverlapping",OverlapSnap->isChecked()); if (standAlone) { config->sync(); if ( !kapp->dcopClient()->isAttached() ) kapp->dcopClient()->attach(); kapp->dcopClient()->send("kwin*", "", "reconfigure()", ""); } setChanged(false); } void KMovingConfig::defaults() { setMove(OPAQUE); setResizeOpaque(RESIZE_TRANSPARENT); setGeometryTip(false); setPlacement(SMART_PLACEMENT); setMoveResizeMaximized(true); //copied from kcontrol/konq/kwindesktop, aleXXX setWindowSnapZone(KWM_WNDW_SNAP_ZONE_DEFAULT); setBorderSnapZone(KWM_BRDR_SNAP_ZONE_DEFAULT); OverlapSnap->setChecked(false); setMinimizeAnim( true ); setMinimizeAnimSpeed( 5 ); setChanged(true); } int KMovingConfig::getBorderSnapZone() { return BrdrSnap->value(); } void KMovingConfig::setBorderSnapZone(int pxls) { BrdrSnap->setValue(pxls); } int KMovingConfig::getWindowSnapZone() { return WndwSnap->value(); } void KMovingConfig::setWindowSnapZone(int pxls) { WndwSnap->setValue(pxls); } #include "windows.moc" diff --git a/kwin/kcmkwin/kwinoptions/windows.h b/kwin/kcmkwin/kwinoptions/windows.h index 0cd63aea2b..40afa7c015 100644 --- a/kwin/kcmkwin/kwinoptions/windows.h +++ b/kwin/kcmkwin/kwinoptions/windows.h @@ -1,219 +1,223 @@ /* * windows.h * * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca * Copyright (c) 2001 Waldo Bastian bastian@kde.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __KWINDOWCONFIG_H__ #define __KWINDOWCONFIG_H__ #include #include #include class QRadioButton; class QCheckBox; class QPushButton; class QComboBox; class QLabel; class QSlider; class QButtonGroup; class QSpinBox; class QVButtonGroup; class KIntNumInput; #define TRANSPARENT 0 #define OPAQUE 1 #define CLICK_TO_FOCUS 0 #define FOCUS_FOLLOW_MOUSE 1 #define TITLEBAR_PLAIN 0 #define TITLEBAR_SHADED 1 #define RESIZE_TRANSPARENT 0 #define RESIZE_OPAQUE 1 #define SMART_PLACEMENT 0 #define CASCADE_PLACEMENT 1 #define RANDOM_PLACEMENT 2 #define CENTERED_PLACEMENT 3 #define ZEROCORNERED_PLACEMENT 4 #define INTERACTIVE_PLACEMENT 5 #define MANUAL_PLACEMENT 6 #define CLICK_TO_FOCUS 0 #define FOCUS_FOLLOWS_MOUSE 1 #define FOCUS_UNDER_MOUSE 2 #define FOCUS_STRICTLY_UNDER_MOUSE 3 class QSpinBox; class KFocusConfig : public KCModule { Q_OBJECT public: KFocusConfig( bool _standAlone, KConfig *_config, QWidget *parent=0, const char* name=0 ); ~KFocusConfig(); void load(); void save(); void defaults(); private slots: void setAutoRaiseEnabled(); void autoRaiseOnTog(bool);//CT 23Oct1998 void clickRaiseOnTog(bool); void changed() { setChanged(true); } private: int getFocus( void ); int getAutoRaiseInterval( void ); void setFocus(int); void setAutoRaiseInterval(int); void setAutoRaise(bool); void setClickRaise(bool); void setAltTabMode(bool); void setTraverseAll(bool); void setRollOverDesktops(bool); void setShowPopupinfo(bool); QButtonGroup *fcsBox; QComboBox *focusCombo; QCheckBox *autoRaiseOn; QCheckBox *clickRaiseOn; KIntNumInput *autoRaise; QButtonGroup *kbdBox; QRadioButton *kdeMode; QRadioButton *cdeMode; QCheckBox *traverseAll; QCheckBox *rollOverDesktops; QCheckBox *showPopupinfo; KConfig *config; bool standAlone; }; class KMovingConfig : public KCModule { Q_OBJECT public: KMovingConfig( bool _standAlone, KConfig *config, QWidget *parent=0, const char* name=0 ); ~KMovingConfig(); void load(); void save(); void defaults(); private slots: void setMinimizeAnim( bool ); void setMinimizeAnimSpeed( int ); void changed() { setChanged(true); } private: int getMove( void ); bool getMinimizeAnim( void ); int getMinimizeAnimSpeed( void ); int getResizeOpaque ( void ); bool getGeometryTip( void ); //KS int getPlacement( void ); //CT void setMove(int); void setResizeOpaque(int); void setGeometryTip(bool); //KS void setPlacement(int); //CT void setMoveResizeMaximized(bool); QButtonGroup *windowsBox; QCheckBox *opaque; QCheckBox *resizeOpaqueOn; QCheckBox *geometryTipOn; QCheckBox* minimizeAnimOn; QSlider *minimizeAnimSlider; QLabel *minimizeAnimSlowLabel, *minimizeAnimFastLabel; QCheckBox *moveResizeMaximized; QComboBox *placementCombo; KConfig *config; bool standAlone; int getBorderSnapZone(); void setBorderSnapZone( int ); int getWindowSnapZone(); void setWindowSnapZone( int ); QVButtonGroup *MagicBox; KIntNumInput *BrdrSnap, *WndwSnap; QCheckBox *OverlapSnap; }; class KAdvancedConfig : public KCModule { Q_OBJECT public: KAdvancedConfig( bool _standAlone, KConfig *config, QWidget *parent=0, const char* name=0 ); ~KAdvancedConfig(); void load(); void save(); void defaults(); private slots: void shadeHoverChanged(bool); //copied from kcontrol/konq/kwindesktop, aleXXX void setEBorders(); void changed() { setChanged(true); } private: int getShadeHoverInterval (void ); void setAnimateShade(bool); void setShadeHover(bool); void setShadeHoverInterval(int); QCheckBox *animateShade; QButtonGroup *shBox; QCheckBox *shadeHoverOn; KIntNumInput *shadeHover; KConfig *config; bool standAlone; int getElectricBorders( void ); int getElectricBorderDelay(); void setElectricBorders( int ); void setElectricBorderDelay( int ); QVButtonGroup *electricBox; QRadioButton *active_disable; QRadioButton *active_move; QRadioButton *active_always; KIntNumInput *delays; + + void setFocusStealing( int ); + + QComboBox* focusStealing; }; #endif diff --git a/kwin/options.cpp b/kwin/options.cpp index c6065445aa..d33294e2ef 100644 --- a/kwin/options.cpp +++ b/kwin/options.cpp @@ -1,236 +1,239 @@ /***************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 1999, 2000 Matthias Ettrich Copyright (C) 2003 Lubos Lunak You can Freely distribute this program under the GNU General Public License. See the file "COPYING" for the exact licensing terms. ******************************************************************/ #include "options.h" #include #include #include #include #include #include namespace KWinInternal { Options::Options() : electric_borders( 0 ), electric_border_delay(0) { d = new KDecorationOptionsPrivate; d->defaultKWinSettings(); updateSettings(); } Options::~Options() { delete d; } unsigned long Options::updateSettings() { KConfig *config = KGlobal::config(); unsigned long changed = 0; changed |= d->updateKWinSettings( config ); // read decoration settings config->setGroup( "Windows" ); moveMode = config->readEntry("MoveMode", "Opaque" ) == "Opaque"?Opaque:Transparent; resizeMode = config->readEntry("ResizeMode", "Opaque" ) == "Opaque"?Opaque:Transparent; show_geometry_tip = config->readBoolEntry("GeometryTip", false); QString val; val = config->readEntry ("FocusPolicy", "ClickToFocus"); focusPolicy = ClickToFocus; // what a default :-) if ( val == "FocusFollowsMouse" ) focusPolicy = FocusFollowsMouse; else if ( val == "FocusUnderMouse" ) focusPolicy = FocusUnderMouse; else if ( val == "FocusStrictlyUnderMouse" ) focusPolicy = FocusStrictlyUnderMouse; val = config->readEntry ("AltTabStyle", "KDE"); altTabStyle = KDE; // what a default :-) if ( val == "CDE" ) altTabStyle = CDE; rollOverDesktops = config->readBoolEntry("RollOverDesktops", TRUE); + + focusStealingPreventionLevel = config->readNumEntry( "FocusStealingPreventionLevel", 2 ); + focusStealingPreventionLevel = KMAX( 0, KMIN( 4, focusStealingPreventionLevel )); KConfig *gc = new KConfig("kdeglobals", false, false); bool isVirtual = KApplication::desktop()->isVirtualDesktop(); gc->setGroup("Windows"); xineramaEnabled = gc->readBoolEntry ("XineramaEnabled", isVirtual ) && isVirtual; if (xineramaEnabled) { xineramaPlacementEnabled = gc->readBoolEntry ("XineramaPlacementEnabled", true); xineramaMovementEnabled = gc->readBoolEntry ("XineramaMovementEnabled", true); xineramaMaximizeEnabled = gc->readBoolEntry ("XineramaMaximizeEnabled", true); } else { xineramaPlacementEnabled = xineramaMovementEnabled = xineramaMaximizeEnabled = false; } delete gc; val = config->readEntry("Placement","Smart"); if (val == "Random") placement = Random; else if (val == "Cascade") placement = Cascade; else if (val == "Centered") placement = Centered; else if (val == "ZeroCornered") placement = ZeroCornered; else placement = Smart; val = config->readEntry("DialogPlacement", "ObeyApplication" ); // TODO is this good default? if( val == "DialogCentered" ) dialog_placement = DialogCentered; else if( val == "OnMainWindow" ) dialog_placement = OnMainWindow; else if( val == "UnderMouse" ) dialog_placement = UnderMouse; else if( val == "DialogPlaced" ) dialog_placement = DialogPlaced; else dialog_placement = ObeyApplication; animateShade = config->readBoolEntry("AnimateShade", TRUE ); animateMinimize = config->readBoolEntry("AnimateMinimize", TRUE ); animateMinimizeSpeed = config->readNumEntry("AnimateMinimizeSpeed", 5 ); if( focusPolicy == ClickToFocus ) { autoRaise = false; autoRaiseInterval = 0; } else { autoRaise = config->readBoolEntry("AutoRaise", FALSE ); autoRaiseInterval = config->readNumEntry("AutoRaiseInterval", 0 ); } shadeHover = config->readBoolEntry("ShadeHover", FALSE ); shadeHoverInterval = config->readNumEntry("ShadeHoverInterval", 250 ); // important: autoRaise implies ClickRaise clickRaise = autoRaise || config->readBoolEntry("ClickRaise", TRUE ); borderSnapZone = config->readNumEntry("BorderSnapZone", 10); windowSnapZone = config->readNumEntry("WindowSnapZone", 10); snapOnlyWhenOverlapping=config->readBoolEntry("SnapOnlyWhenOverlapping",FALSE); electric_borders = config->readNumEntry("ElectricBorders", 0); electric_border_delay = config->readNumEntry("ElectricBorderDelay", 150); OpTitlebarDblClick = windowOperation( config->readEntry("TitlebarDoubleClickCommand", "Shade"), true ); ignorePositionClasses = config->readListEntry("IgnorePositionClasses"); // Mouse bindings config->setGroup( "MouseBindings"); CmdActiveTitlebar1 = mouseCommand(config->readEntry("CommandActiveTitlebar1","Raise"), true ); CmdActiveTitlebar2 = mouseCommand(config->readEntry("CommandActiveTitlebar2","Lower"), true ); CmdActiveTitlebar3 = mouseCommand(config->readEntry("CommandActiveTitlebar3","Operations menu"), true ); CmdInactiveTitlebar1 = mouseCommand(config->readEntry("CommandInactiveTitlebar1","Activate and raise"), true ); CmdInactiveTitlebar2 = mouseCommand(config->readEntry("CommandInactiveTitlebar2","Activate and lower"), true ); CmdInactiveTitlebar3 = mouseCommand(config->readEntry("CommandInactiveTitlebar3","Operations menu"), true ); CmdWindow1 = mouseCommand(config->readEntry("CommandWindow1","Activate, raise and pass click"), false ); CmdWindow2 = mouseCommand(config->readEntry("CommandWindow2","Activate and pass click"), false ); CmdWindow3 = mouseCommand(config->readEntry("CommandWindow3","Activate and pass click"), false ); CmdAllModKey = (config->readEntry("CommandAllKey","Alt") == "Meta") ? Qt::Key_Meta : Qt::Key_Alt; CmdAll1 = mouseCommand(config->readEntry("CommandAll1","Move"), false ); CmdAll2 = mouseCommand(config->readEntry("CommandAll2","Toggle raise and lower"), false ); CmdAll3 = mouseCommand(config->readEntry("CommandAll3","Resize"), false ); // Read button tooltip animation effect from kdeglobals // Since we want to allow users to enable window decoration tooltips // and not kstyle tooltips and vise-versa, we don't read the // "EffectNoTooltip" setting from kdeglobals. KConfig globalConfig("kdeglobals"); globalConfig.setGroup("KDE"); fade_tooltips = globalConfig.readBoolEntry("EffectFadeTooltip", false); animate_tooltips = globalConfig.readBoolEntry("EffectAnimateTooltip", false); return changed; } // restricted should be true for operations that the user may not be able to repeat // if the window is moved out of the workspace (e.g. if the user moves a window // by the titlebar, and moves it too high beneath Kicker at the top edge, they // may not be able to move it back, unless they know about Alt+LMB) Options::WindowOperation Options::windowOperation(const QString &name, bool restricted ) { if (name == "Move") return restricted ? MoveOp : UnrestrictedMoveOp; else if (name == "Resize") return restricted ? ResizeOp : UnrestrictedResizeOp; else if (name == "Maximize") return MaximizeOp; else if (name == "Minimize") return MinimizeOp; else if (name == "Close") return CloseOp; else if (name == "OnAllDesktops") return OnAllDesktopsOp; else if (name == "Shade") return ShadeOp; else if (name == "Operations") return OperationsOp; else if (name == "Maximize (vertical only)") return VMaximizeOp; else if (name == "Maximize (horizontal only)") return HMaximizeOp; else if (name == "Lower") return LowerOp; return NoOp; } Options::MouseCommand Options::mouseCommand(const QString &name, bool restricted ) { QString lowerName = name.lower(); if (lowerName == "raise") return MouseRaise; if (lowerName == "lower") return MouseLower; if (lowerName == "operations menu") return MouseOperationsMenu; if (lowerName == "toggle raise and lower") return MouseToggleRaiseAndLower; if (lowerName == "activate and raise") return MouseActivateAndRaise; if (lowerName == "activate and lower") return MouseActivateAndLower; if (lowerName == "activate") return MouseActivate; if (lowerName == "activate, raise and pass click") return MouseActivateRaiseAndPassClick; if (lowerName == "activate and pass click") return MouseActivateAndPassClick; if (lowerName == "activate, raise and move") return restricted ? MouseActivateRaiseAndMove : MouseActivateRaiseAndUnrestrictedMove; if (lowerName == "move") return restricted ? MouseMove : MouseUnrestrictedMove; if (lowerName == "resize") return restricted ? MouseResize : MouseUnrestrictedResize; if (lowerName == "shade") return MouseShade; if (lowerName == "minimize") return MouseMinimize; if (lowerName == "nothing") return MouseNothing; return MouseNothing; } bool Options::showGeometryTip() { return show_geometry_tip; } bool Options::fadeTooltips() { return fade_tooltips; } bool Options::animateTooltips() { return animate_tooltips; } int Options::electricBorders() { return electric_borders; } int Options::electricBorderDelay() { return electric_border_delay; } } // namespace diff --git a/kwin/options.h b/kwin/options.h index 4148e8f1a4..dbd3eaf881 100644 --- a/kwin/options.h +++ b/kwin/options.h @@ -1,285 +1,288 @@ /***************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 1999, 2000 Matthias Ettrich Copyright (C) 2003 Lubos Lunak You can Freely distribute this program under the GNU General Public License. See the file "COPYING" for the exact licensing terms. ******************************************************************/ #ifndef KWIN_OPTIONS_H #define KWIN_OPTIONS_H #include #include #include #include #include namespace KWinInternal { class Options : public KDecorationOptions { public: Options(); ~Options(); virtual unsigned long updateSettings(); /*! Different focus policies:
  • ClickToFocus - Clicking into a window activates it. This is also the default.
  • FocusFollowsMouse - Moving the mouse pointer actively onto a normal window activates it. For convenience, the desktop and windows on the dock are excluded. They require clicking.
  • FocusUnderMouse - The window that happens to be under the mouse pointer becomes active. The invariant is: no window can have focus that is not under the mouse. This also means that Alt-Tab won't work properly and popup dialogs are usually unsable with the keyboard. Note that the desktop and windows on the dock are excluded for convenience. They get focus only when clicking on it.
  • FocusStrictlyUnderMouse - this is even worse than FocusUnderMouse. Only the window under the mouse pointer is active. If the mouse points nowhere, nothing has the focus. If the mouse points onto the desktop, the desktop has focus. The same holds for windows on the dock. Note that FocusUnderMouse and FocusStrictlyUnderMouse are not particulary useful. They are only provided for old-fashined die-hard UNIX people ;-)
*/ enum FocusPolicy { ClickToFocus, FocusFollowsMouse, FocusUnderMouse, FocusStrictlyUnderMouse }; FocusPolicy focusPolicy; /** Whether clicking on a window raises it in FocusFollowsMouse mode or not. */ bool clickRaise; /** whether autoraise is enabled FocusFollowsMouse mode or not. */ bool autoRaise; /** autoraise interval */ int autoRaiseInterval; /** Whether shade hover is enabled or not */ bool shadeHover; /** shade hover interval */ int shadeHoverInterval; /** Different Alt-Tab-Styles:
  • KDE - the recommended KDE style. Alt-Tab opens a nice icon box that makes it easy to select the window you want to tab to. The order automatically adjusts to the most recently used windows. Note that KDE style does not work with the FocusUnderMouse and FocusStrictlyUnderMouse focus policies. Choose ClickToFocus or FocusFollowsMouse instead.
  • CDE - the old-fashion CDE style. Alt-Tab cycles between the windows in static order. The current window gets raised, the previous window gets lowered.
*/ enum AltTabStyle { KDE, CDE }; AltTabStyle altTabStyle; /** * Xinerama options */ bool xineramaEnabled; bool xineramaPlacementEnabled; bool xineramaMovementEnabled; bool xineramaMaximizeEnabled; /** MoveResizeMode, either Tranparent or Opaque. */ enum MoveResizeMode { Transparent, Opaque }; MoveResizeMode resizeMode; MoveResizeMode moveMode; /** * Placement policies. How workspace decides the way windows get positioned * on the screen. The better the policy, the heavier the resource use. * Normally you don't have to worry. What the WM adds to the startup time * is nil compared to the creation of the window itself in the memory */ enum PlacementPolicy { Random, Smart, Cascade, Centered, ZeroCornered }; PlacementPolicy placement; enum DialogPlacementPolicy { ObeyApplication, DialogCentered, OnMainWindow, UnderMouse, DialogPlaced }; DialogPlacementPolicy dialog_placement; bool focusPolicyIsReasonable() { return focusPolicy == ClickToFocus || focusPolicy == FocusFollowsMouse; } /** * whether we animate the shading of windows to titlebar or not */ bool animateShade; /** * the size of the zone that triggers snapping on desktop borders */ int borderSnapZone; /** * the number of animation steps (would this be general?) */ int windowSnapZone; /** * snap only when windows will overlap */ bool snapOnlyWhenOverlapping; /** * whether we animate the minimization of windows or not */ bool animateMinimize; /** * Animation speed (0 .. 10 ) */ int animateMinimizeSpeed; /** * whether or not we roll over to the other edge when switching desktops past the edge */ bool rollOverDesktops; + // 0 - 4 , see Workspace::allowClientActivation() + int focusStealingPreventionLevel; + /** * List of window classes to ignore PPosition size hint */ QStringList ignorePositionClasses; WindowOperation operationTitlebarDblClick() { return OpTitlebarDblClick; } enum MouseCommand { MouseRaise, MouseLower, MouseOperationsMenu, MouseToggleRaiseAndLower, MouseActivateAndRaise, MouseActivateAndLower, MouseActivate, MouseActivateRaiseAndPassClick, MouseActivateAndPassClick, MouseMove, MouseUnrestrictedMove, MouseActivateRaiseAndMove, MouseActivateRaiseAndUnrestrictedMove, MouseResize, MouseUnrestrictedResize, MouseShade, MouseMinimize, MouseNothing }; MouseCommand commandActiveTitlebar1() { return CmdActiveTitlebar1; } MouseCommand commandActiveTitlebar2() { return CmdActiveTitlebar2; } MouseCommand commandActiveTitlebar3() { return CmdActiveTitlebar3; } MouseCommand commandInactiveTitlebar1() { return CmdInactiveTitlebar1; } MouseCommand commandInactiveTitlebar2() { return CmdInactiveTitlebar2; } MouseCommand commandInactiveTitlebar3() { return CmdInactiveTitlebar3; } MouseCommand commandWindow1() { return CmdWindow1; } MouseCommand commandWindow2() { return CmdWindow2; } MouseCommand commandWindow3() { return CmdWindow3; } MouseCommand commandAll1() { return CmdAll1; } MouseCommand commandAll2() { return CmdAll2; } MouseCommand commandAll3() { return CmdAll3; } uint keyCmdAllModKey() { return CmdAllModKey; } static WindowOperation windowOperation(const QString &name, bool restricted ); static MouseCommand mouseCommand(const QString &name, bool restricted ); /** * @returns true if the Geometry Tip should be shown during a window move/resize. * @since 3.2 */ bool showGeometryTip(); /** * @returns true if window button tooltips should use a fade-in effect * @see #animateTooltips * @see #showTooltips */ bool fadeTooltips(); // FRAME tohle asi muze jit /** * @returns true if window button tooltips should use an animated effect. * When this is true, tooltips should use a animated scroll effect. If * fadeToolTips is also true, tooltips should be faded-in instead. * @see #fadeTooltips * @see #showTooltips */ bool animateTooltips(); enum { ElectricDisabled = 0, ElectricMoveOnly = 1, ElectricAlways = 2 }; /** * @returns true if electric borders are enabled. With electric borders * you can change desktop by moving the mouse pointer towards the edge * of the screen */ int electricBorders(); /** * @returns the activation delay for electric borders in milliseconds. */ int electricBorderDelay(); private: WindowOperation OpTitlebarDblClick; // mouse bindings MouseCommand CmdActiveTitlebar1; MouseCommand CmdActiveTitlebar2; MouseCommand CmdActiveTitlebar3; MouseCommand CmdInactiveTitlebar1; MouseCommand CmdInactiveTitlebar2; MouseCommand CmdInactiveTitlebar3; MouseCommand CmdWindow1; MouseCommand CmdWindow2; MouseCommand CmdWindow3; MouseCommand CmdAll1; MouseCommand CmdAll2; MouseCommand CmdAll3; uint CmdAllModKey; bool fade_tooltips; bool animate_tooltips; int electric_borders; int electric_border_delay; bool show_geometry_tip; }; extern Options* options; } // namespace #endif