From 6655d0207d187e5f47ff3409f06a56562b539d6e Mon Sep 17 00:00:00 2001 From: Matthias Ettrich Date: Thu, 22 Jun 2000 18:08:35 +0000 Subject: [PATCH] focus policies and alt-tab style: /*! Different focus policies: */ FocusPolicy=ClickToFocus | FocusFollowsMouse | FocusUnderMouse | FocusStrictlyUnderMouse /** Different Alt-Tab-Styles: */ AltTabStyle=KDE | CDE svn path=/trunk/kdebase/kwin/; revision=54010 --- README | 66 +++++++++++++++++++++++++++++++++++++++++++---- client.cpp | 65 ++++++++++++++++++++++++++++++++++------------ client.h | 38 +++++++++++++-------------- options.cpp | 18 +++++++++---- options.h | 60 +++++++++++++++++++++++++++++++++---------- workspace.cpp | 71 ++++++++++++++++++++++++--------------------------- workspace.h | 14 +--------- 7 files changed, 221 insertions(+), 111 deletions(-) diff --git a/README b/README index 9fa9ee1bb3..20c33a478e 100644 --- a/README +++ b/README @@ -7,15 +7,71 @@ Currently supported options in the kwinrc: [Windows] -MoveMode=Opaque|Transparent -ResizeMode=Opaque|Transparent -Placement=Smart|Random|Cascade +MoveMode=Opaque |Transparent +ResizeMode=Opaque |Transparent +Placement=Smart | Random | Cascade AnimateShade=true|false AnimSteps= BorderSnapZone= WindowSnapZone= -TitlebarDoubleClickCommand=Move|Resize| - Maximize|Iconify|Close|Sticky|Shade|Operations +TitlebarDoubleClickCommand=Move | Resize | + Maximize | Iconify | Close | Sticky | Shade | Operations + + + /*! + 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 ;-) + +
+ */ +FocusPolicy=ClickToFocus | FocusFollowsMouse | FocusUnderMouse | FocusStrictlyUnderMouse + + + /** + 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. + +
+ */ +AltTabStyle=KDE | CDE + + [MouseBindings] diff --git a/client.cpp b/client.cpp index 77fbb1ff88..b0bf7e572a 100644 --- a/client.cpp +++ b/client.cpp @@ -1052,7 +1052,7 @@ void Client::mouseMoveEvent( QMouseEvent * e) return; } - if ( !mayMove()) return; + if ( !isMovable()) return; if ( !moveResizeMode ) { @@ -1326,7 +1326,7 @@ void Client::invalidateWindow() void Client::iconify() { - if (!mayMove()) + if (!isMovable()) return; if ( isShade() ) @@ -1371,7 +1371,7 @@ void Client::killWindow() void Client::maximize( MaximizeMode m) { - if (!mayMove()) + if (!isMovable()) return; QRect clientArea = workspace()->clientArea(); @@ -1423,9 +1423,6 @@ void Client::maximize( MaximizeMode m) void Client::toggleSticky() { - if (!mayMove()) - return; - setSticky( !isSticky() ); } @@ -1514,23 +1511,28 @@ void Client::gravitate( bool invert ) /*! Reimplement to handle crossing events (qt should provide xroot, yroot) + + Crossing events are necessary for the focus-follows-mouse focus + policies, to do proper activation and deactivation. */ bool Client::x11Event( XEvent * e) { - if ( e->type == EnterNotify ) { - if (( options->focusPolicy != Options::ClickToFocus ) && - (( options->focusPolicy != Options::FocusFollowsMouse) || - !passiveFocus())) - workspace()->requestFocus( this ); + if ( e->type == EnterNotify && e->xcrossing.mode == NotifyNormal ) { + if ( options->focusPolicy == Options::ClickToFocus ) + return TRUE; + + if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() ) ) + return TRUE; + + workspace()->requestFocus( this ); return TRUE; } - if ( e->type == LeaveNotify ) { + if ( e->type == LeaveNotify && e->xcrossing.mode == NotifyNormal ) { if ( !buttonDown ) setCursor( arrowCursor ); - if ( options->focusPolicy == Options::FocusStrictlyUnderMouse ) { + if ( options->focusPolicy == Options::FocusStrictlyUnderMouse ) if ( isActive() && !rect().contains( QPoint( e->xcrossing.x, e->xcrossing.y ) ) ) workspace()->requestFocus( 0 ) ; - } return TRUE; } return FALSE; @@ -1613,7 +1615,7 @@ bool Client::isShade() const void Client::setShade( bool s ) { - if (!mayMove()) + if (!isMovable()) return; if ( shaded == s ) @@ -1864,7 +1866,7 @@ bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPo replay = TRUE; break; case Options::MouseMove: - if (!mayMove()) + if (!isMovable()) break; mode = Center; moveResizeMode = TRUE; @@ -1878,7 +1880,7 @@ bool Client::performMouseCommand( Options::MouseCommand command, QPoint globalPo XGrabServer( qt_xdisplay() ); break; case Options::MouseResize: - if (!mayMove()) + if (!isMovable()) break; moveResizeMode = TRUE; workspace()->setEnableFocusChange(false); @@ -2070,6 +2072,35 @@ void Client::activateLayout() } +NET::WindowType Client::windowType() const +{ + NET::WindowType wt = info->windowType(); + if ( wt == NET::Unknown ) + wt = NET::Normal; + return wt; +} + +bool Client::wantsTabFocus() const +{ + return windowType() == NET::Normal; +} + +bool Client::isMovable() const +{ + return windowType() == NET::Normal || windowType() == NET::Toolbar; +} + +bool Client::isDesktop() const +{ + return windowType() == NET::Desktop; +} + +bool Client::isDock() const +{ + return windowType() == NET::Dock; +} + + /*! Returns \a area with the client's strut taken into account. diff --git a/client.h b/client.h index 65468167ae..4fa85c4b6b 100644 --- a/client.h +++ b/client.h @@ -11,6 +11,7 @@ Copyright (C) 1999, 2000 Matthias Ettrich #include #include #include +#include #include #include #include @@ -69,6 +70,7 @@ public: WId transientFor() const; bool isTransient() const; Client* mainClient(); + NET::WindowType windowType() const; virtual bool windowEvent( XEvent * ); @@ -115,15 +117,12 @@ public: bool isSticky() const; void setSticky( bool ); - bool mayMove() const { return may_move; } - void setMayMove( bool m) { may_move = m; } - - /** - * A window with passive focus will only get focus when - * the user explicitly selects the window. - **/ - bool passiveFocus() const { return passive_focus; } - void setPassiveFocus( bool p) { passive_focus = p; } + + // auxiliary functions, depend on the windowType + bool wantsTabFocus() const; + bool isMovable() const; + bool isDesktop() const; + bool isDock() const; void takeFocus(); @@ -147,7 +146,6 @@ public: { move( p.x(), p.y() ); } - virtual bool wantsTabFocus() const { return TRUE;} //### just for now bool providesContextHelp() const; @@ -155,7 +153,7 @@ public: QCString windowRole(); QCString sessionId(); - + QRect adjustedClientArea( const QRect& area ) const; public slots: @@ -235,22 +233,22 @@ private: XSizeHints xSizeHint; void sendSynteticConfigureNotify(); int state; - bool active; QRect original_geometry; QRect geom; //### TODO - bool shaded; WId transient_for; - bool is_sticky; - bool is_shape; - bool may_move; - bool passive_focus; - void getWMHints(); - void getWindowProtocols(); + uint shaded :1; + uint active :1; + uint is_sticky :1; + uint is_shape :1; + uint may_move :1; + uint passive_focus :1; uint Pdeletewindow :1; // does the window understand the DeleteWindow protocol? uint Ptakefocus :1;// does the window understand the TakeFocus protocol? uint Pcontexthelp : 1; // does the window understand the ContextHelp protocol? uint input :1; // does the window want input in its wm_hints uint mapped :1; // keeps track of our visiblity within the asynchronous event flow + void getWMHints(); + void getWindowProtocols(); QPixmap icon_pix; QPixmap miniicon_pix; QRect geom_restore; @@ -348,6 +346,7 @@ inline bool Client::shape() const return is_shape; } + inline const QRegion& Client::getMask() const { return mask; @@ -360,7 +359,6 @@ public: NoBorderClient( Workspace *ws, WId w, QWidget *parent=0, const char *name=0 ); ~NoBorderClient(); - bool wantsTabFocus() const { return FALSE;} //### just for now }; #endif diff --git a/options.cpp b/options.cpp index 8d308cf1d9..711a29489a 100644 --- a/options.cpp +++ b/options.cpp @@ -1,6 +1,6 @@ /***************************************************************** kwin - the KDE window manager - + Copyright (C) 1999, 2000 Matthias Ettrich ******************************************************************/ #include "options.h" @@ -134,11 +134,19 @@ void Options::reload() QString val; - val = config->readEntry ("focusPolicy", "ClickToFocus"); - if (val == "ClickToFocus") - focusPolicy = ClickToFocus; - else + 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; val = config->readEntry("Placement","Smart"); if (val == "Smart") placement = Smart; diff --git a/options.h b/options.h index a228d25045..abf8951360 100644 --- a/options.h +++ b/options.h @@ -1,6 +1,6 @@ /***************************************************************** kwin - the KDE window manager - + Copyright (C) 1999, 2000 Matthias Ettrich ******************************************************************/ #ifndef OPTIONS_H @@ -29,15 +29,22 @@ public: also the default.
  • FocusFollowsMouse - Moving the mouse pointer actively onto a - window activates it. + 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. + 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 - Only the window under the mouse - pointer is active. If the mouse points nowhere, nothing has the - focus. In practice, this is the same as FocusUnderMouse, since - kdesktop can take the focus. +
  • 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 @@ -48,15 +55,32 @@ public: enum FocusPolicy { ClickToFocus, FocusFollowsMouse, FocusUnderMouse, FocusStrictlyUnderMouse }; FocusPolicy focusPolicy; - enum MoveResizeMode { Transparent, Opaque }; - + /** - * Basic color types that should be recognized by all decoration styles. - * Not all styles have to implement all the colors, but for the ones that - * are implemented you should retrieve them here. + 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. + +
    */ - // increment KWINCOLORS if you add something (mosfet) - enum ColorType{TitleBar=0, TitleBlend, Font, ButtonBg, Frame, Handle}; + enum AltTabStyle { KDE, CDE }; + AltTabStyle altTabStyle; + + + /** + MoveResizeMode, either Tranparent or Opaque. + */ + enum MoveResizeMode { Transparent, Opaque }; MoveResizeMode resizeMode; MoveResizeMode moveMode; @@ -74,6 +98,14 @@ public: return focusPolicy == ClickToFocus || focusPolicy == FocusFollowsMouse; } + /** + * Basic color types that should be recognized by all decoration styles. + * Not all styles have to implement all the colors, but for the ones that + * are implemented you should retrieve them here. + */ + // increment KWINCOLORS if you add something (mosfet) + enum ColorType{TitleBar=0, TitleBlend, Font, ButtonBg, Frame, Handle}; + /** * Return the color for the given decoration. */ diff --git a/workspace.cpp b/workspace.cpp index 73b23d9efa..914b7b374a 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -174,25 +174,14 @@ Client* Workspace::clientFactory( WId w ) XLowerWindow( qt_xdisplay(), w ); Client * c = new NoBorderClient( this, w); c->setSticky( TRUE ); - c->setMayMove( FALSE ); setDesktopClient( c ); - c->setPassiveFocus( TRUE ); return c; } + case NET::Menu: case NET::Dock: { Client * c = new NoBorderClient( this, w); c->setSticky( TRUE ); - c->setMayMove( FALSE ); - c->setPassiveFocus( TRUE ); - return c; - } - - case NET::Menu: { - Client * c = new NoBorderClient( this, w); - c->setSticky( TRUE ); - c->setMayMove( FALSE ); - c->setPassiveFocus( TRUE ); return c; } @@ -665,8 +654,6 @@ bool Workspace::keyPress(XKeyEvent key) int kc = XKeycodeToKeysym(qt_xdisplay(), key.keycode, 0); int km = key.state & (ControlMask | Mod1Mask | ShiftMask); - const bool options_alt_tab_mode_is_CDE_style = FALSE; // TODO - if (!control_grab){ if( (kc == XK_Tab) && @@ -674,7 +661,7 @@ bool Workspace::keyPress(XKeyEvent key) || km == (Mod1Mask) )){ if (!tab_grab){ - if (options_alt_tab_mode_is_CDE_style ){ + if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable() ){ // CDE style raise / lower Client* c = topClientOnDesktop(); Client* nc = c; @@ -683,7 +670,7 @@ bool Workspace::keyPress(XKeyEvent key) nc = previousStaticClient(nc); } while (nc && nc != c && (!nc->isOnDesktop(currentDesktop()) || - nc->isIconified())); + nc->isIconified() || !nc->wantsTabFocus() ) ); } else @@ -691,11 +678,15 @@ bool Workspace::keyPress(XKeyEvent key) nc = nextStaticClient(nc); } while (nc && nc != c && (!nc->isOnDesktop(currentDesktop()) || - nc->isIconified())); + nc->isIconified() || !nc->wantsTabFocus() ) ); if (c && c != nc) - ;//TODO lowerClient(c); - if (nc) - activateClient( nc ); + lowerClient( c, false ); + if (nc) { + if ( options->focusPolicyIsReasonable() ) + activateClient( nc ); + else + raiseClient( nc ); + } freeKeyboard(FALSE); return TRUE; } @@ -725,10 +716,6 @@ bool Workspace::keyPress(XKeyEvent key) ( km == (ControlMask | ShiftMask) || km == (ControlMask) )){ -//TODO if (!options.ControlTab){ -// freeKeyboard(TRUE); -// return TRUE; -// } if (!control_grab){ XGrabPointer( qt_xdisplay(), root, TRUE, (uint)(ButtonPressMask | ButtonReleaseMask | @@ -872,14 +859,16 @@ Client* Workspace::previousStaticClient( Client* c ) const } -/*! - Returns topmost visible client within the specified layer range on - the current desktop, or 0 if no clients are visible. \a fromLayer has to - be smaller than \a toLayer. +/*! + Returns topmost visible client. Windows on the dock and the + desktop are excluded. */ -Client* Workspace::topClientOnDesktop( int fromLayer, int toLayer) const +Client* Workspace::topClientOnDesktop() const { - fromLayer = toLayer = 0; + for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) { + if ( !(*it)->isDesktop() && !(*it)->isDock() ) + return *it; + } return 0; } @@ -1439,7 +1428,7 @@ void Workspace::cascadeDesktop() if((!(*it)->isOnDesktop(currentDesktop())) || ((*it)->isIconified()) || ((*it)->isSticky()) || - (!(*it)->mayMove()) ) + (!(*it)->isMovable()) ) continue; cascadePlacement(*it); } @@ -1456,7 +1445,7 @@ void Workspace::unclutterDesktop() if((!(*it)->isOnDesktop(currentDesktop())) || ((*it)->isIconified()) || ((*it)->isSticky()) || - (!(*it)->mayMove()) ) + (!(*it)->isMovable()) ) continue; smartPlacement(*it); } @@ -1684,7 +1673,7 @@ void Workspace::setCurrentDesktop( int new_desktop ){ if (options->focusPolicy == Options::FocusFollowsMouse) { // Search in focus chain for( ClientList::ConstIterator it = focus_chain.fromLast(); it != focus_chain.end(); --it) { - if ( (*it)->isVisible() && !(*it)->passiveFocus() ) { + if ( (*it)->isVisible() ) { c = *it; break; } @@ -1695,7 +1684,7 @@ void Workspace::setCurrentDesktop( int new_desktop ){ if (!c) { // Search top-most visible window for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) { - if ( (*it)->isVisible() && !(*it)->passiveFocus() ) { + if ( (*it)->isVisible() ) { c = *it; break; } @@ -2072,7 +2061,7 @@ void Workspace::slotWindowOperations() { if ( !active_client ) return; - if ( !active_client->mayMove()) + if ( !active_client->isMovable()) return; QPopupMenu* p = clientPopup( active_client ); @@ -2512,6 +2501,10 @@ SessionInfo* Workspace::takeSessionInfo( Client* c ) Updates the current client area according to the current clients. If the area changes, the new area is propagate to the world. + + The client area is the area that is available for clients (that + which is not taken by windows like panels, the top-of-screen menu + etc). \sa clientArea() */ @@ -2537,8 +2530,12 @@ void Workspace::updateClientArea() } -/*! - Returns the current client area +/*! + returns the area available for clients. This is the desktop + geometry minus windows on the dock. Placement algorithms should + refer to this rather than geometry(). + + \sa geometry() */ QRect Workspace::clientArea() { diff --git a/workspace.h b/workspace.h index 55fbb58a3f..35b7a722dd 100644 --- a/workspace.h +++ b/workspace.h @@ -92,12 +92,6 @@ public: QRect geometry() const; - /** - * @return the area available for clients. This is the desktop - * geometry adjusted for edge-anchored windows. - * Placement algorithms should refer to this rather than geometry(). - * @sa geometry() - */ QRect clientArea(); bool destroyClient( Client* ); @@ -152,8 +146,7 @@ public: */ const ClientList& stackingOrder() const; - //#### TODO right layers as default - Client* topClientOnDesktop( int fromLayer = 0, int toLayer = 0) const; + Client* topClientOnDesktop() const; QPopupMenu* clientPopup( Client* ); @@ -172,11 +165,6 @@ public: SessionInfo* takeSessionInfo( Client* ); - /** - * When the area that is available for clients (that which is not - * taken by windows like panels, the top-of-screen menu etc) may - * have changed, this will recalculate the available space. - */ virtual void updateClientArea();