Support for having previews even for unmapped windows - they're
actually kept mapped, so that they still have the backing pixmap. Plus some small tricks to prevent such windows from interfering. Only two basic modes are implemented right now. svn path=/trunk/KDE/kdebase/workspace/; revision=683156
This commit is contained in:
parent
5f003b9ec3
commit
9052116e4f
10 changed files with 138 additions and 29 deletions
|
@ -173,6 +173,11 @@ General TODO
|
|||
% installed headers currently include config.h files to find out about e.g. OpenGL
|
||||
- this needs to be sorted out somehow, installed headers shouldn't do this
|
||||
|
||||
? hidden previews currently needs input shape extension, otherwise the window can possibly interfere
|
||||
- not very likely though, so is this worth bothering at all?
|
||||
|
||||
+ hidden preview has two modes unimplemented
|
||||
|
||||
|
||||
OpenGL TODO
|
||||
=================================
|
||||
|
|
72
client.cpp
72
client.cpp
|
@ -497,7 +497,19 @@ void Client::updateShape()
|
|||
}
|
||||
// !shape() mask setting is done in setMask() when the decoration
|
||||
// calls it or when the decoration is created/destroyed
|
||||
updateInputShape();
|
||||
if( compositing())
|
||||
addDamageFull();
|
||||
if( scene != NULL )
|
||||
scene->windowGeometryShapeChanged( this );
|
||||
if( effects != NULL )
|
||||
static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), geometry());
|
||||
}
|
||||
|
||||
void Client::updateInputShape()
|
||||
{
|
||||
if( hidden_preview ) // sets it to none, don't change
|
||||
return;
|
||||
if( Extensions::shapeInputAvailable())
|
||||
{ // There appears to be no way to find out if a window has input
|
||||
// shape set or not, so always propagate the input shape
|
||||
|
@ -524,12 +536,6 @@ void Client::updateShape()
|
|||
XShapeCombineShape( display(), frameId(), ShapeInput, 0, 0,
|
||||
helper_window, ShapeInput, ShapeSet );
|
||||
}
|
||||
if( compositing())
|
||||
addDamageFull();
|
||||
if( scene != NULL )
|
||||
scene->windowGeometryShapeChanged( this );
|
||||
if( effects != NULL )
|
||||
static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), geometry());
|
||||
}
|
||||
|
||||
void Client::setMask( const QRegion& reg, int mode )
|
||||
|
@ -867,12 +873,20 @@ void Client::rawShow()
|
|||
XMapWindow( display(), wrapper );
|
||||
XMapWindow( display(), client );
|
||||
}
|
||||
if( options->hiddenPreviews == HiddenPreviewsNever )
|
||||
{
|
||||
// XComposite invalidates backing pixmaps on unmap (minimize, different
|
||||
// virtual desktop, etc.). We kept the last known good pixmap around
|
||||
// for use in effects, but now we want to have access to the new pixmap
|
||||
if( compositing() )
|
||||
discardWindowPixmap();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( hidden_preview )
|
||||
setHiddenPreview( false, Allowed );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Reimplemented to unmap the managed window in the window wrapper.
|
||||
|
@ -881,7 +895,10 @@ void Client::rawShow()
|
|||
*/
|
||||
void Client::rawHide()
|
||||
{
|
||||
StackingUpdatesBlocker blocker( workspace());
|
||||
addWorkspaceRepaint( geometry());
|
||||
if( options->hiddenPreviews == HiddenPreviewsNever )
|
||||
{
|
||||
// Here it may look like a race condition, as some other client might try to unmap
|
||||
// the window between these two XSelectInput() calls. However, they're supposed to
|
||||
// use XWithdrawWindow(), which also sends a synthetic event to the root window,
|
||||
|
@ -895,9 +912,52 @@ void Client::rawHide()
|
|||
XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask );
|
||||
if( decoration != NULL )
|
||||
decoration->widget()->hide(); // not really necessary, but let it know the state
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !hidden_preview )
|
||||
{
|
||||
setHiddenPreview( true, Allowed );
|
||||
// actually keep the window mapped (taken from rawShow())
|
||||
if( decoration != NULL )
|
||||
decoration->widget()->show(); // not really necessary, but let it know the state
|
||||
XMapWindow( display(), frameId());
|
||||
if( !isShade())
|
||||
{
|
||||
XMapWindow( display(), wrapper );
|
||||
XMapWindow( display(), client );
|
||||
}
|
||||
}
|
||||
}
|
||||
workspace()->clientHidden( this );
|
||||
}
|
||||
|
||||
// XComposite doesn't keep window pixmaps of unmapped windows, which means
|
||||
// there wouldn't be any previews of windows that are minimized or on another
|
||||
// virtual desktop. Therefore rawHide() actually keeps such windows mapped.
|
||||
// However special care needs to be taken so that such windows don't interfere.
|
||||
// Therefore they're put very low in the stacking order and they have input shape
|
||||
// set to none, which hopefully is enough. If there's no input shape available,
|
||||
// then it's hoped that there will be some other desktop above it *shrug*.
|
||||
// Using normal shape would be better, but that'd affect other things, e.g. painting
|
||||
// of the actual preview.
|
||||
void Client::setHiddenPreview( bool set, allowed_t )
|
||||
{
|
||||
if( set && !hidden_preview )
|
||||
{ // set
|
||||
hidden_preview = true;
|
||||
workspace()->forceRestacking();
|
||||
if( Extensions::shapeInputAvailable())
|
||||
XShapeCombineRectangles( display(), frameId(), ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted );
|
||||
}
|
||||
else if( !set && hidden_preview )
|
||||
{ // unset
|
||||
hidden_preview = false;
|
||||
workspace()->forceRestacking();
|
||||
updateInputShape();
|
||||
}
|
||||
}
|
||||
|
||||
void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long data2, long data3)
|
||||
{
|
||||
XEvent ev;
|
||||
|
|
12
client.h
12
client.h
|
@ -219,6 +219,7 @@ class Client
|
|||
void updateVisibility();
|
||||
// hides a client - basically like minimize, but without effects, it's simply hidden
|
||||
void hideClient( bool hide );
|
||||
bool hiddenPreview() const; // window is mapped in order to get a window pixmap
|
||||
|
||||
QString caption( bool full = true ) const;
|
||||
void updateCaption();
|
||||
|
@ -322,8 +323,7 @@ class Client
|
|||
void syncTimeout();
|
||||
|
||||
private:
|
||||
// ICCCM 4.1.3.1, 4.1.4 , NETWM 2.5.1
|
||||
void setMappingState( int s );
|
||||
void setMappingState( int s ); // ICCCM 4.1.3.1, 4.1.4 , NETWM 2.5.1
|
||||
int mappingState() const;
|
||||
bool isIconicState() const;
|
||||
bool isNormalState() const;
|
||||
|
@ -382,6 +382,8 @@ class Client
|
|||
|
||||
void rawShow(); // just shows it
|
||||
void rawHide(); // just hides it
|
||||
void setHiddenPreview( bool set, allowed_t );
|
||||
void updateInputShape();
|
||||
|
||||
Time readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
|
||||
bool session ) const;
|
||||
|
@ -446,6 +448,7 @@ class Client
|
|||
uint urgency : 1; // XWMHints, UrgencyHint
|
||||
uint ignore_focus_stealing : 1; // don't apply focus stealing prevention to this client
|
||||
uint demands_attention : 1;
|
||||
uint hidden_preview : 1; // mapped only to get a window pixmap for compositing
|
||||
WindowRules client_rules;
|
||||
void getWMHints();
|
||||
void readIcons();
|
||||
|
@ -768,6 +771,11 @@ inline void Client::removeRule( Rules* rule )
|
|||
client_rules.remove( rule );
|
||||
}
|
||||
|
||||
inline bool Client::hiddenPreview() const
|
||||
{
|
||||
return hidden_preview;
|
||||
}
|
||||
|
||||
KWIN_COMPARE_PREDICATE( WrapperIdMatchPredicate, Client, Window, cl->wrapperId() == value );
|
||||
|
||||
} // namespace
|
||||
|
|
16
layers.cpp
16
layers.cpp
|
@ -105,7 +105,8 @@ void Workspace::updateStackingOrder( bool propagate_new_clients )
|
|||
return;
|
||||
}
|
||||
ClientList new_stacking_order = constrainedStackingOrder();
|
||||
bool changed = ( new_stacking_order != stacking_order );
|
||||
bool changed = ( new_stacking_order != stacking_order || force_restacking );
|
||||
force_restacking = false;
|
||||
stacking_order = new_stacking_order;
|
||||
#if 0
|
||||
kDebug() << "stacking:" << changed << endl;
|
||||
|
@ -153,6 +154,8 @@ void Workspace::propagateClients( bool propagate_new_clients )
|
|||
int topmenu_space_pos = 1; // not 0, that's supportWindow !!!
|
||||
for ( int i = stacking_order.size() - 1; i >= 0; i-- )
|
||||
{
|
||||
if( stacking_order.at( i )->hiddenPreview())
|
||||
continue;
|
||||
new_stack[ pos++ ] = stacking_order.at( i )->frameId();
|
||||
if( stacking_order.at( i )->belongsToLayer() >= DockLayer )
|
||||
topmenu_space_pos = pos;
|
||||
|
@ -166,6 +169,17 @@ void Workspace::propagateClients( bool propagate_new_clients )
|
|||
new_stack[ topmenu_space_pos ] = topmenu_space->winId();
|
||||
++pos;
|
||||
}
|
||||
// when having hidden previews, stack hidden windows below everything else
|
||||
// (as far as pure X stacking order is concerned), in order to avoid having
|
||||
// these windows that should be unmapped to interfere with other windows
|
||||
for ( int i = stacking_order.size() - 1; i >= 0; i-- )
|
||||
{
|
||||
if( !stacking_order.at( i )->hiddenPreview())
|
||||
continue;
|
||||
new_stack[ pos++ ] = stacking_order.at( i )->frameId();
|
||||
if( stacking_order.at( i )->belongsToLayer() >= DockLayer )
|
||||
topmenu_space_pos = pos;
|
||||
}
|
||||
// TODO isn't it too inefficient to restack always all clients?
|
||||
// TODO don't restack not visible windows?
|
||||
assert( new_stack[ 0 ] == supportWindow->winId());
|
||||
|
|
|
@ -193,6 +193,8 @@ unsigned long Options::updateSettings()
|
|||
glDirect = config.readEntry("GLDirect", true );
|
||||
glVSync = config.readEntry("GLVSync", true );
|
||||
glStrictBinding = config.readEntry( "GLStrictBinding", false );
|
||||
const HiddenPreviews hps[] = { HiddenPreviewsNever, HiddenPreviewsKeep, HiddenPreviewUpdate, HiddenPreviewsActive };
|
||||
hiddenPreviews = hps[ qBound( 0, config.readEntry( "HiddenPreviews", 3 ), 3 ) ];
|
||||
|
||||
// Read button tooltip animation effect from kdeglobals
|
||||
// Since we want to allow users to enable window decoration tooltips
|
||||
|
|
|
@ -18,6 +18,7 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#include <kdecoration_p.h>
|
||||
|
||||
#include "placement.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -290,6 +291,7 @@ class Options : public KDecorationOptions
|
|||
|
||||
//translucency settings
|
||||
bool useTranslucency;
|
||||
HiddenPreviews hiddenPreviews;
|
||||
|
||||
uint refreshRate;
|
||||
int smoothScale; // 0 = no, 1 = yes when transformed,
|
||||
|
|
|
@ -290,7 +290,7 @@ void Scene::Window::discardShape()
|
|||
}
|
||||
|
||||
// Find out the shape of the window using the XShape extension
|
||||
// or if not shape is set then simply it's the window geometry.
|
||||
// or if shape is not set then simply it's the window geometry.
|
||||
QRegion Scene::Window::shape() const
|
||||
{
|
||||
if( !shape_valid )
|
||||
|
|
8
utils.h
8
utils.h
|
@ -125,6 +125,14 @@ enum ShadeMode
|
|||
ShadeActivated // "shaded", but visible due to alt+tab to the window
|
||||
};
|
||||
|
||||
enum HiddenPreviews // whether to keep all windows mapped when compositing
|
||||
{ // do not reorder (config file)
|
||||
HiddenPreviewsNever, // don't keep pixmaps of unmapped windows at all
|
||||
/**/ HiddenPreviewsKeep, // only keep pixmaps, but unmap windows
|
||||
/**/ HiddenPreviewUpdate, // unmap, keep, but when needed map back and wait
|
||||
HiddenPreviewsActive // keep windows mapped
|
||||
};
|
||||
|
||||
class Extensions
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -88,6 +88,7 @@ Workspace::Workspace( bool restore )
|
|||
pending_take_activity ( NULL ),
|
||||
active_screen (0),
|
||||
delayfocus_client (0),
|
||||
force_restacking( false ),
|
||||
showing_desktop( false ),
|
||||
block_showing_desktop( 0 ),
|
||||
was_user_interaction (false),
|
||||
|
|
|
@ -131,6 +131,7 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
void restoreSessionStackingOrder( Client* c );
|
||||
void restackUnmanaged( Unmanaged* c, Window above );
|
||||
void reconfigure();
|
||||
void forceRestacking();
|
||||
|
||||
void clientHidden( Client* );
|
||||
void clientAttentionChanged( Client* c, bool set );
|
||||
|
@ -591,6 +592,7 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
ClientList unconstrained_stacking_order; // topmost last
|
||||
ClientList stacking_order; // topmost last
|
||||
UnmanagedList unmanaged_stacking_order;
|
||||
bool force_restacking;
|
||||
QVector< ClientList > focus_chain; // currently ative last
|
||||
ClientList global_focus_chain; // this one is only for things like tabbox's MRU
|
||||
ClientList should_get_focus; // last is most recent
|
||||
|
@ -870,6 +872,13 @@ bool Workspace::rulesUpdatesDisabled() const
|
|||
return rules_updates_disabled;
|
||||
}
|
||||
|
||||
inline
|
||||
void Workspace::forceRestacking()
|
||||
{
|
||||
force_restacking = true;
|
||||
StackingUpdatesBlocker blocker( this ); // do restacking if not blocked
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline Client* Workspace::findClient( T predicate )
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue