summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Spilsbury <smspillaz@gmail.com>2010-08-08 11:12:12 +0800
committerSam Spilsbury <smspillaz@gmail.com>2010-08-08 11:14:11 +0800
commit54f2523f1706eb66b53bbd00087320dc02d4bd9d (patch)
tree242898d119ef552c517dd835b0e0ce9c08e4fa2f
parente07ee731c1b91f1d705347a895fee8288cb72cc4 (diff)
downloadworkarounds-54f2523f1706eb66b53bbd00087320dc02d4bd9d.tar.gz
workarounds-54f2523f1706eb66b53bbd00087320dc02d4bd9d.tar.bz2
Added "keep thumbnails of minimized windows" option, as a WORKAROUND.
This wraps ::minimize, ::unminimize and ::minimized in order to lie to plugins and also tell pagers etc that the window is gone. It also shapes out the input of the window, and does not paint the window, and on unminimize restores the shape of the window
-rw-r--r--src/workarounds.cpp309
-rw-r--r--src/workarounds.h38
-rw-r--r--workarounds.xml.in5
3 files changed, 349 insertions, 3 deletions
diff --git a/src/workarounds.cpp b/src/workarounds.cpp
index 65a9215..7965c60 100644
--- a/src/workarounds.cpp
+++ b/src/workarounds.cpp
@@ -30,6 +30,251 @@ bool haveOpenGL;
COMPIZ_PLUGIN_20090315 (workarounds, WorkaroundsPluginVTable);
+/*
+ * WorkaroundsWindow::clearInputShape
+ *
+ */
+void
+WorkaroundsWindow::clearInputShape (HideInfo *hideInfo)
+{
+ XRectangle *rects;
+ int count = 0, ordering;
+ Window xid = hideInfo->shapeWindow;
+
+ rects = XShapeGetRectangles (screen->dpy (), xid, ShapeInput,
+ &count, &ordering);
+
+ if (count == 0)
+ return;
+
+ /* check if the returned shape exactly matches the window shape -
+ * if that is true, the window currently has no set input shape */
+ if ((count == 1) &&
+ (rects[0].x == -window->serverGeometry ().border ()) &&
+ (rects[0].y == -window->serverGeometry ().border ()) &&
+ (rects[0].width == (window->serverGeometry ().width () +
+ window->serverGeometry ().border ())) &&
+ (rects[0].height == (window->serverGeometry ().height () +
+ window->serverGeometry ().border ())))
+ {
+ count = 0;
+ }
+
+ if (hideInfo->inputRects)
+ XFree (hideInfo->inputRects);
+
+ hideInfo->inputRects = rects;
+ hideInfo->nInputRects = count;
+ hideInfo->inputRectOrdering = ordering;
+
+ XShapeSelectInput (screen->dpy (), xid, NoEventMask);
+
+ XShapeCombineRectangles (screen->dpy (), xid, ShapeInput, 0, 0,
+ NULL, 0, ShapeSet, 0);
+
+ XShapeSelectInput (screen->dpy (), xid, ShapeNotify);
+}
+
+/*
+ * GroupWindow::restoreInputShape
+ *
+ */
+void
+WorkaroundsWindow::restoreInputShape (HideInfo *info)
+{
+ Window xid = info->shapeWindow;
+
+ if (info->nInputRects)
+ {
+ XShapeCombineRectangles (screen->dpy (), xid, ShapeInput, 0, 0,
+ info->inputRects, info->nInputRects,
+ ShapeSet, info->inputRectOrdering);
+ }
+ else
+ {
+ XShapeCombineMask (screen->dpy (), xid, ShapeInput,
+ 0, 0, None, ShapeSet);
+ }
+
+ if (info->inputRects)
+ XFree (info->inputRects);
+
+ XShapeSelectInput (screen->dpy (), xid, info->shapeMask);
+}
+/*
+ * groupSetWindowVisibility
+ *
+ */
+void
+WorkaroundsWindow::setVisibility (bool visible)
+{
+ if (!visible && !windowHideInfo)
+ {
+ HideInfo *info;
+
+ windowHideInfo = info = new HideInfo ();
+ if (!windowHideInfo)
+ return;
+
+ info->inputRects = NULL;
+ info->nInputRects = 0;
+ info->shapeMask = XShapeInputSelected (screen->dpy (), window->id ());
+
+ /* We are a reparenting window manager now, which means that we either
+ * shape the frame window, or if it does not exist, shape the window **/
+
+ if (window->frame ())
+ info->shapeWindow = window->frame ();
+ else
+ info->shapeWindow = window->id ();
+
+ clearInputShape (info);
+
+ info->skipState = window->state () & (CompWindowStateSkipPagerMask |
+ CompWindowStateSkipTaskbarMask);
+ }
+ else if (visible && windowHideInfo)
+ {
+ HideInfo *info = windowHideInfo;
+
+ restoreInputShape (info);
+
+ XShapeSelectInput (screen->dpy (), window->id (), info->shapeMask);
+ delete info;
+ windowHideInfo = NULL;
+ }
+
+ cWindow->addDamage ();
+ gWindow->glPaintSetEnabled (this, !visible);
+}
+
+bool
+WorkaroundsWindow::isGroupTransient (Window clientLeader)
+{
+ if (!clientLeader)
+ return false;
+
+ if (window->transientFor () == None || window->transientFor () == screen->root ())
+ {
+ if (window->type () & (CompWindowTypeUtilMask |
+ CompWindowTypeToolbarMask |
+ CompWindowTypeMenuMask |
+ CompWindowTypeDialogMask |
+ CompWindowTypeModalDialogMask))
+ {
+ if (window->clientLeader () == clientLeader)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+WorkaroundsWindow::minimize ()
+{
+ if (!window->managed ())
+ return;
+
+ if (!window->minimized ())
+ {
+ WORKAROUNDS_SCREEN (screen);
+
+ unsigned long data[2];
+ int state = IconicState;
+ CompOption::Vector propTemplate = ws->inputDisabledAtom.getReadTemplate ();
+ CompOption::Value enabled = CompOption::Value (true);
+
+ window->windowNotify (CompWindowNotifyMinimize);
+
+ foreach (CompWindow *w, screen->windows ())
+ {
+ if (w->transientFor () == window->id () ||
+ WorkaroundsWindow::get (w)->isGroupTransient (window->clientLeader ()))
+ w->unminimize ();
+ }
+
+ setVisibility (false);
+
+ /* HACK ATTACK */
+
+ data[0] = state;
+ data[1] = None;
+
+ XChangeProperty (screen->dpy (), window->id (),
+ Atoms::wmState, Atoms::wmState,
+ 32, PropModeReplace, (unsigned char *) data, 2);
+
+
+ propTemplate.at (0).set (enabled);
+ ws->inputDisabledAtom.updateProperty (window->id (),
+ propTemplate,
+ XA_CARDINAL);
+
+
+ isMinimized = true;
+ }
+}
+
+void
+WorkaroundsWindow::unminimize ()
+{
+ if (isMinimized)
+ {
+ WORKAROUNDS_SCREEN (screen);
+
+ unsigned long data[2];
+ int state = NormalState;
+ CompOption::Vector propTemplate = ws->inputDisabledAtom.getReadTemplate ();
+ CompOption::Value enabled = CompOption::Value (false);
+
+ window->windowNotify (CompWindowNotifyUnminimize);
+
+ isMinimized = false;
+
+ setVisibility (true);
+
+ foreach (CompWindow *w, screen->windows ())
+ {
+ if (w->transientFor () == window->id () ||
+ WorkaroundsWindow::get (w)->isGroupTransient (window->clientLeader ()))
+ w->unminimize ();
+ }
+
+ /* HACK ATTACK */
+
+ data[0] = state;
+ data[1] = None;
+
+ XChangeProperty (screen->dpy (), window->id (),
+ Atoms::wmState, Atoms::wmState,
+ 32, PropModeReplace, (unsigned char *) data, 2);
+
+ propTemplate.at (0).set (enabled);
+ ws->inputDisabledAtom.updateProperty (window->id (),
+ propTemplate,
+ XA_CARDINAL);
+ }
+}
+
+bool
+WorkaroundsWindow::minimized ()
+{
+ return isMinimized;
+}
+
+bool
+WorkaroundsWindow::glPaint (const GLWindowPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ unsigned int mask)
+{
+ if (isMinimized)
+ mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
+
+ return gWindow->glPaint (attrib, transform, region, mask);
+}
+
void
WorkaroundsScreen::checkFunctions (bool checkWindow, bool checkScreen)
{
@@ -561,6 +806,40 @@ WorkaroundsScreen::optionChanged (CompOption *opt,
else
GL::copySubBuffer = origCopySubBuffer;
}
+
+ if (optionGetKeepMinimizedWindows ())
+ {
+ foreach (CompWindow *window, screen->windows ())
+ {
+ WORKAROUNDS_WINDOW (window);
+ bool m = window->minimized ();
+ if (m)
+ window->unminimize ();
+ window->minimizeSetEnabled (ww, true);
+ window->unminimizeSetEnabled (ww, true);
+ window->minimizedSetEnabled (ww, true);
+ if (m)
+ window->minimize ();
+ }
+ }
+ else
+ {
+ foreach (CompWindow *window, screen->windows ())
+ {
+ WORKAROUNDS_WINDOW (window);
+ bool m = window->minimized ();
+ if (m)
+ window->unminimize ();
+ window->minimizeSetEnabled (ww, false);
+ window->unminimizeSetEnabled (ww, false);
+ window->minimizedSetEnabled (ww, false);
+ if (m)
+ {
+ ww->isMinimized = false;
+ window->minimize ();
+ }
+ }
+ }
}
void
@@ -681,12 +960,17 @@ WorkaroundsScreen::WorkaroundsScreen (CompScreen *screen) :
gScreen (GLScreen::get (screen)),
roleAtom (XInternAtom (screen->dpy (), "WM_WINDOW_ROLE", 0))
{
+ CompOption::Vector propTemplate;
+
ScreenInterface::setHandler (screen, false);
if (haveOpenGL)
{
CompositeScreenInterface::setHandler (cScreen, false);
GLScreenInterface::setHandler (gScreen, false);
}
+
+ propTemplate.push_back (CompOption ("enabled", CompOption::TypeBool));
+ inputDisabledAtom = PropertyWriter ("COMPIZ_NET_WM_INPUT_DISABLED", propTemplate);
optionSetStickyAlldesktopsNotify (boost::bind (
&WorkaroundsScreen::optionChanged, this,
@@ -708,7 +992,10 @@ WorkaroundsScreen::WorkaroundsScreen (CompScreen *screen) :
optionSetNoWaitForVideoSyncNotify (boost::bind (
&WorkaroundsScreen::optionChanged, this,
_1, _2));
-
+ optionSetKeepMinimizedWindowsNotify (boost::bind (
+ &WorkaroundsScreen::optionChanged, this,
+ _1, _2));
+
if (haveOpenGL)
{
origProgramEnvParameter4f = GL::programEnvParameter4f;
@@ -748,9 +1035,12 @@ WorkaroundsWindow::WorkaroundsWindow (CompWindow *window) :
madeSticky (false),
madeFullscreen (false),
isFullscreen (false),
- madeDemandAttention (false)
+ madeDemandAttention (false),
+ isMinimized (window->minimized ()),
+ windowHideInfo (NULL)
{
WindowInterface::setHandler (window, false);
+ GLWindowInterface::setHandler (gWindow, false);
WORKAROUNDS_SCREEN (screen);
@@ -759,11 +1049,26 @@ WorkaroundsWindow::WorkaroundsWindow (CompWindow *window) :
window->getAllowedActionsSetEnabled (this, false);
window->resizeNotifySetEnabled (this, false);
}
+ if (ws->optionGetKeepMinimizedWindows ())
+ {
+ window->minimizeSetEnabled (this, true);
+ window->unminimizeSetEnabled (this, true);
+ window->minimizedSetEnabled (this, true);
+ }
}
WorkaroundsWindow::~WorkaroundsWindow ()
{
+ if (isMinimized)
+ {
+ window->unminimize ();
+ window->minimizeSetEnabled (this, false);
+ window->unminimizeSetEnabled (this, false);
+ window->minimizedSetEnabled (this, false);
+ window->minimize ();
+ }
+
if (!window->destroyed ())
{
if (adjustedWinType)
diff --git a/src/workarounds.h b/src/workarounds.h
index e8ef0c7..c110a59 100644
--- a/src/workarounds.h
+++ b/src/workarounds.h
@@ -31,7 +31,9 @@
#include <composite/composite.h>
#include <opengl/opengl.h>
#include <core/atoms.h>
+#include <core/propertywriter.h>
#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
#include "workarounds_options.h"
@@ -58,6 +60,8 @@ class WorkaroundsScreen :
Atom roleAtom;
std::list <Window> mfwList;
+
+ PropertyWriter inputDisabledAtom;
GL::GLProgramParameter4fProc origProgramEnvParameter4f;
GLProgramParameter4dvProc programEnvParameter4dv;
@@ -110,9 +114,24 @@ class WorkaroundsScreen :
class WorkaroundsWindow :
public PluginClassHandler <WorkaroundsWindow, CompWindow>,
- public WindowInterface
+ public WindowInterface,
+ public GLWindowInterface
{
public:
+
+ typedef struct _HideInfo {
+ Window shapeWindow;
+
+ unsigned long skipState;
+ unsigned long shapeMask;
+
+ XRectangle *inputRects;
+ int nInputRects;
+ int inputRectOrdering;
+
+ } HideInfo;
+
+ public:
WorkaroundsWindow (CompWindow *);
~WorkaroundsWindow ();
@@ -126,13 +145,30 @@ class WorkaroundsWindow :
bool madeFullscreen;
bool isFullscreen;
bool madeDemandAttention;
+ bool isMinimized;
+ HideInfo *windowHideInfo;
+
+ bool
+ isGroupTransient (Window);
+
void
resizeNotify (int, int, int, int);
void
getAllowedActions (unsigned int &,
unsigned int &);
+
+ void minimize ();
+ void unminimize ();
+ bool minimized ();
+
+ bool glPaint (const GLWindowPaintAttrib &, const GLMatrix &,
+ const CompRegion &, unsigned int);
+
+ void setVisibility (bool);
+ void restoreInputShape (HideInfo *);
+ void clearInputShape (HideInfo *);
void
removeSticky ();
diff --git a/workarounds.xml.in b/workarounds.xml.in
index c6bd4a0..a7ad260 100644
--- a/workarounds.xml.in
+++ b/workarounds.xml.in
@@ -18,6 +18,11 @@
</deps>
<options>
+ <option type="bool" name="keep_minimized_windows">
+ <_short>Keep previews of minimized windows</_short>
+ <_long>Don't delete window contents on minimize. This does not work with some applications</_long>
+ <default>false</default>
+ </option>
<option type="bool" name="legacy_fullscreen">
<_short>Legacy Fullscreen Support</_short>
<_long>Make Wine and legacy applications fullscreen properly.</_long>