diff --git a/client.cpp b/client.cpp
index 02859c4f2b..9d202c3424 100644
--- a/client.cpp
+++ b/client.cpp
@@ -76,7 +76,12 @@ public:
m_client->maximize( Client::MaximizeHorizontal );
else
m_client->maximize( Client::MaximizeRestore );
- }
+ }
+
+ if ( mask & NET::StaysOnTop ) {
+ m_client->setStaysOnTop( state & NET::StaysOnTop );
+ m_client->workspace()->raiseClient( m_client );
+ }
}
private:
::Client * m_client;
@@ -411,6 +416,7 @@ Client::Client( Workspace *ws, WId w, QWidget *parent, const char *name, WFlags
passive_focus = FALSE;
is_shape = FALSE;
is_sticky = FALSE;
+ stays_on_top = FALSE;
may_move = TRUE;
getWMHints();
@@ -426,10 +432,17 @@ Client::Client( Workspace *ws, WId w, QWidget *parent, const char *name, WFlags
// should we open this window on a certain desktop?
-
- if ( info->desktop() )
+ if ( info->desktop() == NETWinInfo::OnAllDesktops )
+ setSticky( TRUE );
+ else if ( info->desktop() )
desk= info->desktop(); // window had the initial desktop property!
+
+ // window wants to stay on top?
+ stays_on_top = info->state() & NET::StaysOnTop;
+
+
+
// if this window is transient, ensure that it is opened on the
// same window as its parent. this is necessary when an application
@@ -862,7 +875,7 @@ bool Client::propertyNotify( XPropertyEvent& e )
*/
bool Client::clientMessage( XClientMessageEvent& e )
{
-
+
if ( e.message_type == atoms->kde_wm_change_state ) {
if ( e.data.l[0] == IconicState && isNormal() ) {
if ( e.data.l[1] )
@@ -879,7 +892,7 @@ bool Client::clientMessage( XClientMessageEvent& e )
}
blockAnimation = FALSE;
} else if ( e.message_type == atoms->wm_change_state) {
- if ( e.data.l[0] == IconicState && isNormal() )
+ if ( e.data.l[0] == IconicState && isNormal() )
iconify();
return TRUE;
}
@@ -1372,16 +1385,16 @@ void Client::iconify()
}
Events::raise( Events::Iconify );
setMappingState( IconicState );
-
+
if ( !isTransient() )
animateIconifyOrDeiconify( TRUE );
hide();
-
+
workspace()->iconifyOrDeiconifyTransientsOf( this );
}
-/*!
+/*!
Closes the window by either sending a delete_window message or
using XKill.
*/
@@ -1426,7 +1439,7 @@ void Client::maximize( MaximizeMode m)
if ( !geom_restore.isNull() )
m = MaximizeRestore;
-
+
if ( m != MaximizeRestore ) {
Events::raise( Events::Maximize );
geom_restore = geometry();
@@ -1451,7 +1464,7 @@ void Client::maximize( MaximizeMode m)
);
info->setState( NET::MaxHoriz, NET::MaxHoriz );
break;
-
+
case MaximizeRestore: {
Events::raise( Events::UnMaximize );
setGeometry(geom_restore);
@@ -1753,10 +1766,12 @@ void Client::setSticky( bool b )
if ( is_sticky == b )
return;
is_sticky = b;
- if ( is_sticky )
- Events::raise( Events::Sticky );
- else
- Events::raise( Events::UnSticky );
+ if ( isVisible() ) {
+ if ( is_sticky )
+ Events::raise( Events::Sticky );
+ else
+ Events::raise( Events::UnSticky );
+ }
if ( !is_sticky )
setDesktop( workspace()->currentDesktop() );
else
@@ -1766,6 +1781,20 @@ void Client::setSticky( bool b )
}
+/*!
+ Let the window stay on top or not, depending on \a b
+
+ \sa Workspace::setClientOnTop()
+ */
+void Client::setStaysOnTop( bool b )
+{
+ if ( b == staysOnTop() )
+ return;
+ stays_on_top = b;
+ info->setState( b?NET::StaysOnTop:0, NET::StaysOnTop );
+}
+
+
void Client::setDesktop( int desktop)
{
desk = desktop;
@@ -2208,15 +2237,15 @@ void Client::animateIconifyOrDeiconify( bool iconify)
before = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
after = QRect( x(), y(), width(), pm.height() );
}
-
+
lf = (after.left() - before.left())/step;
- rf = (after.right() - before.right())/step;
- tf = (after.top() - before.top())/step;
+ rf = (after.right() - before.right())/step;
+ tf = (after.top() - before.top())/step;
bf = (after.bottom() - before.bottom())/step;
XGrabServer( qt_xdisplay() );
-
+
QRect area = before;
QRect area2;
QPixmap pm2;
@@ -2259,7 +2288,7 @@ void Client::animateIconifyOrDeiconify( bool iconify)
} while ( t.elapsed() < step);
if (area2 == area || need_to_clear )
p.drawPixmap( area2.x(), area2.y(), pm2 );
-
+
p.end();
XUngrabServer( qt_xdisplay() );
}
diff --git a/client.h b/client.h
index 944a89e969..38df2a7cc1 100644
--- a/client.h
+++ b/client.h
@@ -117,6 +117,8 @@ public:
bool isSticky() const;
void setSticky( bool );
+ bool staysOnTop() const;
+ void setStaysOnTop( bool );
// auxiliary functions, depend on the windowType
bool wantsTabFocus() const;
@@ -153,7 +155,7 @@ public:
QCString sessionId();
QRect adjustedClientArea( const QRect& area ) const;
-
+
public slots:
void iconify();
void closeWindow();
@@ -198,7 +200,7 @@ protected:
virtual MousePosition mousePosition( const QPoint& ) const;
virtual void setMouseCursor( MousePosition m );
-
+
virtual void animateIconifyOrDeiconify( bool iconify );
virtual QPixmap animationPixmap( int w );
@@ -242,6 +244,7 @@ private:
uint shaded :1;
uint active :1;
uint is_sticky :1;
+ uint stays_on_top : 1;
uint is_shape :1;
uint may_move :1;
uint passive_focus :1;
@@ -343,6 +346,11 @@ inline bool Client::isSticky() const
return is_sticky;
}
+inline bool Client::staysOnTop() const
+{
+ return stays_on_top;
+}
+
inline bool Client::shape() const
{
diff --git a/options.cpp b/options.cpp
index 711a29489a..3e98e0395e 100644
--- a/options.cpp
+++ b/options.cpp
@@ -161,7 +161,7 @@ void Options::reload()
window_snap_zone = config->readNumEntry("WindowSnapZone", 10);
- OpTitlebarDblClick = windowOperation( config->readEntry("TitlebarDoubleClickCommand", "winShade") );
+ OpTitlebarDblClick = windowOperation( config->readEntry("TitlebarDoubleClickCommand", "Shade") );
// Mouse bindings
config->setGroup( "MouseBindings");
diff --git a/options.h b/options.h
index abf8951360..ec20f23ebb 100644
--- a/options.h
+++ b/options.h
@@ -55,28 +55,28 @@ public:
enum FocusPolicy { ClickToFocus, FocusFollowsMouse, FocusUnderMouse, FocusStrictlyUnderMouse };
FocusPolicy focusPolicy;
-
+
/**
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;
-
-
+
+
/**
MoveResizeMode, either Tranparent or Opaque.
*/
@@ -148,6 +148,7 @@ public:
CloseOp,
StickyOp,
ShadeOp,
+ StaysOnTopOp,
OperationsOp,
NoOp
};
diff --git a/stdclient.cpp b/stdclient.cpp
index a08f70f122..1e6d9d71a8 100644
--- a/stdclient.cpp
+++ b/stdclient.cpp
@@ -13,6 +13,7 @@ Copyright (C) 1999, 2000 Matthias Ettrich
#include
#include
#include
+#include
#include "workspace.h"
#include "options.h"
@@ -355,8 +356,6 @@ void StdClient::init()
{
Client::init();
button[0]->setIconSet( miniIcon() );
-
- // ### TODO transient etc.
}
void StdClient::iconChange()
@@ -369,12 +368,25 @@ void StdClient::iconChange()
}
-/*!
- Indicates that the menu button has been clicked
+/*!
+ Indicates that the menu button has been clicked. One press shows
+ the window operation menu, a double click closes the window.
*/
void StdClient::menuButtonPressed()
{
- (void ) workspace()->clientPopup( this ); //trigger the popup menu
+ static QTime* t = 0;
+ static StdClient* tc = 0;
+ if ( !t )
+ t = new QTime;
+
+ if ( tc != this || t->elapsed() > QApplication::doubleClickInterval() )
+ button[0]->setPopup( workspace()->clientPopup( this ) );
+ else {
+ button[0]->setPopup( 0 );
+ closeWindow();
+ }
+ t->start();
+ tc = this;
}
diff --git a/workspace.cpp b/workspace.cpp
index 52181bd7db..5b6e8f420d 100644
--- a/workspace.cpp
+++ b/workspace.cpp
@@ -1082,6 +1082,7 @@ QPopupMenu* Workspace::clientPopup( Client* c )
popup->insertItem( i18n("Mi&nimize"), Options::IconifyOp );
popup->insertItem( i18n("Ma&ximize"), Options::MaximizeOp );
popup->insertItem( i18n("Sh&ade"), Options::ShadeOp );
+ popup->insertItem( i18n("Always &On Top"), Options::StaysOnTopOp );
popup->insertSeparator();
@@ -1119,6 +1120,10 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
case Options::ShadeOp:
c->setShade( !c->isShade() );
break;
+ case Options::StaysOnTopOp:
+ c->setStaysOnTop( !c->staysOnTop() );
+ raiseClient( c );
+ break;
default:
break;
}
@@ -1450,9 +1455,9 @@ void Workspace::reconfigure()
}
-/*!
- Lowers the client \a c taking layers, transient windows and window
- groups into account.
+/*!
+ Lowers the client \a c taking stays-on-top flags, layers,
+ transient windows and window groups into account.
*/
void Workspace::lowerClient( Client* c, bool dropFocus )
{
@@ -1489,16 +1494,18 @@ void Workspace::lowerClient( Client* c, bool dropFocus )
stacking_order.remove(c);
stacking_order.prepend(c);
- Window* new_stack = new Window[ stacking_order.count()+1];
+ ClientList list = constrainedStackingOrder( stacking_order );
+ Window* new_stack = new Window[ list.count() + 1 ];
int i = 0;
Client *new_top = 0;
- for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
+ for ( ClientList::ConstIterator it = list.fromLast(); it != list.end(); --it) {
new_stack[i++] = (*it)->winId();
if (!new_top && (*it)->isVisible()) new_top = (*it);
}
XRaiseWindow(qt_xdisplay(), new_stack[0]);
XRestackWindows(qt_xdisplay(), new_stack, i);
delete [] new_stack;
+
propagateClients( TRUE );
if (dropFocus && new_top) {
requestFocus(new_top);
@@ -1506,9 +1513,9 @@ void Workspace::lowerClient( Client* c, bool dropFocus )
}
-/*!
- Raises the client \a c taking layers, transient windows and window
- groups into account.
+/*!
+ Raises the client \a c taking layers, stays-on-top flags,
+ transient windows and window groups into account.
*/
void Workspace::raiseClient( Client* c )
{
@@ -1546,10 +1553,11 @@ void Workspace::raiseClient( Client* c )
saveset.clear();
saveset.append( c );
raiseTransientsOf(saveset, c );
-
- Window* new_stack = new Window[ stacking_order.count()+1];
+
+ ClientList list = constrainedStackingOrder( stacking_order );
+ Window* new_stack = new Window[ list.count() + 1 ];
int i = 0;
- for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
+ for ( ClientList::ConstIterator it = list.fromLast(); it != list.end(); --it) {
new_stack[i++] = (*it)->winId();
}
XRaiseWindow(qt_xdisplay(), new_stack[0]);
@@ -1583,10 +1591,7 @@ void Workspace::raiseTransientsOf( ClientList& safeset, Client* c )
void Workspace::lowerTransientsOf( ClientList& safeset, Client* c )
{
ClientList local = stacking_order;
- ClientList::ConstIterator it = local.fromLast();
- /* QT docu says --begin() is undefined, actually it is ==end(),
- so the usual for loops work: for(bla;it!=end()...) */
- for (; it!=local.end(); --it) {
+ for ( ClientList::ConstIterator it = local.fromLast(); it!=local.end(); --it) {
if ((*it)->transientFor() == c->window() && !safeset.contains(*it)) {
safeset.append( *it );
lowerTransientsOf( safeset, *it );
@@ -1596,6 +1601,30 @@ void Workspace::lowerTransientsOf( ClientList& safeset, Client* c )
}
}
+
+
+/*!
+ Returns a stacking order based upon \a list that fulfills certain contained.
+
+ Currently it obeyes the staysOnTop flag only.
+
+ \sa Client::staysOnTop()
+ */
+ClientList Workspace::constrainedStackingOrder( const ClientList& list )
+{
+ ClientList result;
+ ClientList::ConstIterator it;
+ for ( it = list.begin(); it!=list.end(); ++it) {
+ if ( !(*it)->staysOnTop() )
+ result.append( *it );
+ }
+ for ( it = list.begin(); it!=list.end(); ++it) {
+ if ( (*it)->staysOnTop() )
+ result.append( *it );
+ }
+ return result;
+}
+
/*!
Puts the focus on a dummy window
*/
@@ -1785,7 +1814,7 @@ bool Workspace::addSystemTrayWin( WId w )
return TRUE;
}
-/*!
+/*!
Check whether \a w is a system tray window. If so, remove it from
the respective datastructures and propagate this to the world.
*/
@@ -2019,6 +2048,7 @@ void Workspace::clientPopupAboutToShow()
return;
popup->setItemChecked( Options::MaximizeOp, popup_client->isMaximized() );
popup->setItemChecked( Options::ShadeOp, popup_client->isShade() );
+ popup->setItemChecked( Options::StaysOnTopOp, popup_client->staysOnTop() );
}
@@ -2552,4 +2582,5 @@ QRect Workspace::clientArea()
return area;
}
+
#include "workspace.moc"
diff --git a/workspace.h b/workspace.h
index 870ce00bc5..ffa0ee8ce1 100644
--- a/workspace.h
+++ b/workspace.h
@@ -139,8 +139,8 @@ public:
Client* previousClient(Client*) const;
Client* nextStaticClient(Client*) const;
Client* previousStaticClient(Client*) const;
-
- /**
+
+ /**
* Returns the list of clients sorted in stacking order, with topmost client
* at the last position
*/
@@ -223,6 +223,8 @@ private:
void init();
void createKeybindings();
void freeKeyboard(bool pass);
+
+ ClientList constrainedStackingOrder( const ClientList& list );
Client* clientFactory(WId w);
@@ -327,4 +329,5 @@ inline const ClientList& Workspace::stackingOrder() const
return stacking_order;
}
+
#endif