summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanny Baumann <dannybaumann@web.de>2007-04-06 17:22:57 +0200
committerDanny Baumann <dannybaumann@web.de>2007-04-06 17:22:57 +0200
commit3a6ece86d89c2de0f10838b9e3fef5e368decc5b (patch)
tree55cfcefbeb46858c78a2009696176571292dc2d4
parent436fda8ce2aaaf9a5692aa848b4dcad89f36776f (diff)
downloadberyl-premerge-3a6ece86d89c2de0f10838b9e3fef5e368decc5b.tar.gz
beryl-premerge-3a6ece86d89c2de0f10838b9e3fef5e368decc5b.tar.bz2
added opacify
-rw-r--r--src/Makefile.am5
-rw-r--r--src/opacify.c536
-rw-r--r--src/opacify.options70
3 files changed, 611 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 35fbc66..69845f6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,6 +21,10 @@ libaddhelper_la_LDFLAGS = $(PFLAGS)
libaddhelper_la_LIBADD = @COMPIZ_LIBS@
libaddhelper_la_SOURCES = addhelper_options.c addhelper.c
+libopacify_la_LDFLAGS = $(PFLAGS)
+libopacify_la_LIBADD = @COMPIZ_LIBS@
+libopacify_la_SOURCES = opacify_options.c opacify.c
+
libextrawm_la_LDFLAGS = $(PFLAGS)
libextrawm_la_LIBADD = @COMPIZ_LIBS@
libextrawm_la_SOURCES = extrawm_options.c extrawm.c
@@ -111,6 +115,7 @@ module_LTLIBRARIES = \
libbench.la \
libextrawm.la \
libaddhelper.la \
+ libopacify.la \
$(libwall_module) \
$(libimgjpeg_module) \
$(libtext_module)
diff --git a/src/opacify.c b/src/opacify.c
new file mode 100644
index 0000000..1a33b40
--- /dev/null
+++ b/src/opacify.c
@@ -0,0 +1,536 @@
+/**
+ * Beryl Opacify
+ *
+ * Copyright (c) 2006 Kristian LyngstĂžl <kristian@beryl-project.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.
+ *
+ *
+ * Opacify increases opacity on targeted windows and reduces it on
+ * blocking windows, making whatever window you are targeting easily
+ * visible.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrender.h>
+
+#include <compiz.h>
+#include "opacify_options.h"
+
+#define GET_OPACIFY_DISPLAY(d) \
+ ((OpacifyDisplay *) (d)->privates[displayPrivateIndex].ptr)
+#define OPACIFY_DISPLAY(d) \
+ OpacifyDisplay *od = GET_OPACIFY_DISPLAY (d)
+#define GET_OPACIFY_SCREEN(s, od) \
+ ((OpacifyScreen *) (s)->privates[(od)->screenPrivateIndex].ptr)
+#define OPACIFY_SCREEN(s) \
+ OpacifyScreen *os = GET_OPACIFY_SCREEN (s, GET_OPACIFY_DISPLAY (s->display))
+#define GET_OPACIFY_WINDOW(w, os) \
+ ((OpacifyWindow *) (w)->privates[(os)->windowPrivateIndex].ptr)
+#define OPACIFY_WINDOW(s) \
+ OpacifyWindow *ow = GET_OPACIFY_WINDOW(w, GET_OPACIFY_SCREEN (w->screen, GET_OPACIFY_DISPLAY (w->screen->display)))
+
+/* Size of the Window array storing passive windows. */
+#define MAX_WINDOWS 64
+
+static int displayPrivateIndex = 0;
+
+typedef struct _OpacifyDisplay
+{
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+ Bool toggle;
+ int active_screen;
+ CompTimeoutHandle timeout_handle;
+} OpacifyDisplay;
+
+typedef struct _OpacifyScreen
+{
+ int windowPrivateIndex;
+ PaintWindowProc paintWindow;
+
+ CompWindow *new_active;
+ Window active;
+ Window passive[MAX_WINDOWS];
+ Region intersect;
+ unsigned short int passive_num;
+ Bool just_moved;
+} OpacifyScreen;
+
+typedef struct _OpacifyWindow
+{
+ Bool opacified;
+ int opacity;
+} OpacifyWindow;
+
+/* Core opacify functions. These do the real work. ---------------------*/
+
+/* Sets the real opacity and damages the window if actual opacity and
+ * requested opacity differs. */
+static void set_opacity(CompWindow * w, int opacity)
+{
+ OPACIFY_WINDOW(w);
+
+ if (!ow->opacified || (w->paint.opacity != opacity))
+ addWindowDamage(w);
+
+ ow->opacified = TRUE;
+ ow->opacity = opacity;
+
+ //setWindowOpacity(w, opacity, PL_TEMP_HELLO);
+}
+
+/* Resets the Window to the original opacity if it still exists.
+ */
+static void reset_opacity(CompScreen * s, Window id)
+{
+ CompWindow *w;
+
+ w = findWindowAtScreen(s, id);
+ if (!w)
+ return;
+
+ OPACIFY_WINDOW(w);
+ ow->opacified = FALSE;
+ //resetWindowOpacity(w, PL_TEMP_HELLO);
+}
+
+/* Resets the opacity of windows on the passive list.
+ */
+static void clear_passive(CompScreen * s)
+{
+ OPACIFY_SCREEN(s);
+ int i;
+
+ for (i = 0; i < os->passive_num; i++)
+ reset_opacity(s, os->passive[i]);
+ os->passive_num = 0;
+}
+
+/* Dim an (inactive) window. Place it on the passive list and
+ * update passive_num. Then change the opacity.
+ */
+static void dim_window(CompScreen * s, CompWindow * w)
+{
+ OPACIFY_SCREEN(s);
+ if (os->passive_num >= MAX_WINDOWS - 1)
+ {
+ fprintf(stderr, "opacify: Trying to store information "
+ "about too many windows, or you hit a bug.\nIf "
+ "you don't have around %d windows blocking the "
+ "currently targeted window, please report this.\n",
+ MAX_WINDOWS);
+ return;
+ }
+ os->passive[os->passive_num++] = w->id;
+ set_opacity(w, MIN(OPAQUE * opacifyGetPassiveOpacity(s) / 100, w->paint.opacity));
+}
+
+/* Walk through all windows, skip until we've passed the active
+ * window, skip if it's invisible, hidden or minimized, skip if
+ * it's not a window type we're looking for.
+ * Dim it if it intersects.
+ *
+ * Returns number of changed windows.
+ */
+static int passive_windows(CompScreen * s, Region a_region)
+{
+ CompWindow *w;
+
+ OPACIFY_SCREEN(s);
+ Bool flag = FALSE;
+ int i = 0;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (w->id == os->active)
+ {
+ flag = TRUE;
+ continue;
+ }
+ if (!flag)
+ continue;
+ if (!matchEval(opacifyGetWindowMatch(s), w))
+ continue;
+ if (w->invisible || w->hidden || w->minimized)
+ continue;
+ XIntersectRegion(w->region, a_region, os->intersect);
+ if (!XEmptyRegion(os->intersect))
+ {
+ dim_window(s, w);
+ i++;
+ }
+ }
+ return i;
+}
+
+/* Check if we switched active window, reset the old passive windows
+ * if we did. If we have an active window and switched: reset that too.
+ * If we have a window (w is true), update the active id and
+ * passive list. just_moved is to make sure we recalculate opacity after
+ * moving. We can't reset before moving because if we're using a delay
+ * and the window being moved is not the active but overlapping, it will
+ * be reset, which would conflict with move's opacity change.
+ * FIXME: A more final solution should be to use IPCS to signal
+ * which window is being moved.
+ */
+static void opacify_handle_enter(CompScreen * s, CompWindow * w)
+{
+ OPACIFY_SCREEN(s);
+ int num;
+
+ if (otherScreenGrabExist(s, 0))
+ {
+ if (!otherScreenGrabExist(s, "move", 0))
+ {
+ os->just_moved = True;
+ return;
+ }
+ clear_passive(s);
+ reset_opacity(s, os->active);
+ os->active = 0;
+ return;
+ }
+ if (!w || os->active != w->id || os->just_moved)
+ {
+ os->just_moved = False;
+ clear_passive(s);
+ reset_opacity(s, os->active);
+ os->active = 0;
+ }
+ if (!w)
+ return;
+ if (w->id != os->active && !w->shaded &&
+ matchEval(opacifyGetWindowMatch(s), w))
+ {
+ os->active = w->id;
+ num = passive_windows(s, w->region);
+ if (num || opacifyGetOnlyIfBlock(s))
+ set_opacity(w, MAX(OPAQUE * opacifyGetActiveOpacity(s) / 100, w->paint.opacity));
+ }
+}
+
+/* Check if we are on the same screen. We only want opacify active on
+ * one screen, so if we are on a diffrent screen, we reset the old one.
+ * Returns True if the screen has switched.
+ */
+static Bool check_screen_switch(CompScreen *s)
+{
+ OPACIFY_DISPLAY(s->display);
+ if (od->active_screen == s->screenNum)
+ return False;
+ CompScreen * tmp;
+ for (tmp = s->display->screens; tmp; tmp = tmp->next)
+ {
+ OPACIFY_SCREEN(tmp);
+ clear_passive(tmp);
+ reset_opacity(tmp, os->active);
+ os->active = 0;
+ }
+ od->active_screen = s->screenNum;
+ return True;
+}
+
+/* Decides what to do after a timeout occured.
+ * Either we reset the opacity because we just toggled,
+ * or we handle the event.
+ */
+static Bool handle_timeout(void *data)
+{
+ CompScreen *s = (CompScreen *) data;
+
+ OPACIFY_SCREEN(s);
+ OPACIFY_DISPLAY(s->display);
+
+ od->timeout_handle = 0;
+ check_screen_switch(s);
+ if (!od->toggle)
+ {
+ clear_passive(s);
+ reset_opacity(s, os->active);
+ os->active = 0;
+ }
+ opacify_handle_enter(s, os->new_active);
+
+ return FALSE;
+}
+
+/* Checks whether we should delay or not.
+ * Returns true if immediate execution.
+ */
+static inline Bool check_delay(CompScreen *s)
+{
+ CompDisplay * d = s->display;
+ OPACIFY_SCREEN(s);
+
+ if (opacifyGetFocusInstant(s) && os->new_active &&
+ (os->new_active->id == d->activeWindow))
+ return True;
+ if (!opacifyGetTimeout(d))
+ return True;
+ if (!os->new_active || (os->new_active->id == s->root))
+ return False;
+ if (os->new_active->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
+ return False;
+ if (opacifyGetNoDelayChange(s) && os->passive_num)
+ return True;
+ return False;
+
+
+}
+
+static Bool opacifyPaintWindow (CompWindow *w, const WindowPaintAttrib *attrib,
+ const CompTransform *transform, Region region,
+ unsigned int mask)
+{
+ Bool status;
+ CompScreen *s = w->screen;
+ OPACIFY_SCREEN(s);
+ OPACIFY_WINDOW(w);
+
+ if (ow->opacified)
+ {
+ WindowPaintAttrib wAttrib = *attrib;
+ wAttrib.opacity = ow->opacity;
+
+ UNWRAP(os, s, paintWindow);
+ status = (*s->paintWindow) (w, &wAttrib, transform, region, mask);
+ WRAP(os, s, paintWindow, opacifyPaintWindow);
+ }
+ else
+ {
+ UNWRAP(os, s, paintWindow);
+ status = (*s->paintWindow) (w, attrib, transform, region, mask);
+ WRAP(os, s, paintWindow, opacifyPaintWindow);
+ }
+
+ return status;
+}
+
+/* Takes the inital event.
+ * If we were configured, recalculate the opacify-windows if
+ * it was our window.
+ * If a window was entered: call upon handle_timeout after od->timeout
+ * micro seconds, or directly if od->timeout is 0 (no delay).
+ *
+ * FIXME: In the perfect world, toggle-resetting is done in the action
+ * handler that does the actual toggling.
+ */
+static void opacifyHandleEvent(CompDisplay * d, XEvent * event)
+{
+ CompScreen *s;
+ CompWindow *w = NULL;
+
+ OPACIFY_DISPLAY(d);
+
+ UNWRAP(od, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP(od, d, handleEvent, opacifyHandleEvent);
+
+ if (!od->toggle && !opacifyGetToggleReset(d))
+ return;
+
+ switch (event->type)
+ {
+ case EnterNotify:
+ s = findScreenAtDisplay(d, event->xcrossing.root);
+ if (s)
+ {
+ OPACIFY_SCREEN(s);
+ if (!od->toggle && !os->active)
+ return;
+ os->new_active = findTopLevelWindowAtScreen(s, event->xcrossing.window);
+ if (od->timeout_handle)
+ compRemoveTimeout(od->timeout_handle);
+ if (check_delay(s))
+ handle_timeout(s);
+ else
+ od->timeout_handle =
+ compAddTimeout(opacifyGetTimeout(d), handle_timeout, s);
+ }
+ break;
+ case ConfigureNotify:
+ s = findScreenAtDisplay(d, event->xconfigure.event);
+ if (s)
+ {
+ OPACIFY_SCREEN(s);
+ if (os->active != event->xconfigure.window)
+ break;
+ clear_passive(s);
+ if (os->active)
+ w = findWindowAtScreen(s, os->active);
+ if (w)
+ passive_windows(s, w->region);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+/* Configuration, initialization, boring stuff. ----------------------- */
+
+static Bool opacifyInitWindow(CompPlugin * p, CompWindow * w)
+{
+ OPACIFY_SCREEN(w->screen);
+ OpacifyWindow *ow = (OpacifyWindow *) calloc(1, sizeof(OpacifyWindow));
+
+ ow->opacified = FALSE;
+
+ w->privates[os->windowPrivateIndex].ptr = ow;
+
+ return TRUE;
+}
+
+static void opacifyFiniWindow(CompPlugin * p, CompWindow * w)
+{
+ OPACIFY_WINDOW(w);
+
+ free(ow);
+}
+
+static void opacifyFiniScreen(CompPlugin * p, CompScreen * s)
+{
+ OPACIFY_SCREEN(s);
+
+ UNWRAP(os, s, paintWindow);
+
+ XDestroyRegion(os->intersect);
+ free(os);
+}
+
+static Bool opacifyInitScreen(CompPlugin * p, CompScreen * s)
+{
+ OPACIFY_DISPLAY(s->display);
+ OpacifyScreen *os = (OpacifyScreen *) calloc(1, sizeof(OpacifyScreen));
+
+ os->windowPrivateIndex = allocateWindowPrivateIndex(s);
+ if (os->windowPrivateIndex < 0)
+ {
+ free(os);
+ return FALSE;
+ }
+
+ WRAP(os, s, paintWindow, opacifyPaintWindow);
+
+ s->privates[od->screenPrivateIndex].ptr = os;
+ os->intersect = XCreateRegion();
+ os->just_moved = False;
+
+ return TRUE;
+}
+
+static Bool opacify_toggle(CompDisplay * d, CompAction * ac,
+ CompActionState state, CompOption * option,
+ int nOption)
+{
+ OPACIFY_DISPLAY(d);
+ od->toggle = !od->toggle;
+ return TRUE;
+}
+
+static void opacifyDisplayOptionChanged(CompDisplay *d, CompOption *opt, OpacifyDisplayOptions num)
+{
+ OPACIFY_DISPLAY(d);
+
+ switch (num)
+ {
+ case OpacifyDisplayOptionInitToggle:
+ od->toggle = opt->value.b;
+ break;
+ default:
+ break;
+ }
+}
+
+static Bool opacifyInitDisplay(CompPlugin * p, CompDisplay * d)
+{
+ OpacifyDisplay *od = (OpacifyDisplay *) malloc(sizeof(OpacifyDisplay));
+
+ od->screenPrivateIndex = allocateScreenPrivateIndex(d);
+ if (od->screenPrivateIndex < 0)
+ {
+ free(od);
+ return FALSE;
+ }
+ d->privates[displayPrivateIndex].ptr = od;
+ od->active_screen = d->screens->screenNum;
+ od->toggle = TRUE;
+
+ opacifySetToggleInitiate (d, opacify_toggle);
+ opacifySetInitToggleNotify(d, opacifyDisplayOptionChanged);
+
+ WRAP(od, d, handleEvent, opacifyHandleEvent);
+ return TRUE;
+}
+
+static void opacifyFiniDisplay(CompPlugin * p, CompDisplay * d)
+{
+ OPACIFY_DISPLAY(d);
+ UNWRAP(od, d, handleEvent);
+ if (od->timeout_handle)
+ compRemoveTimeout(od->timeout_handle);
+ freeScreenPrivateIndex(d, od->screenPrivateIndex);
+ free(od);
+}
+
+static Bool opacifyInit(CompPlugin * p)
+{
+ displayPrivateIndex = allocateDisplayPrivateIndex();
+ if (displayPrivateIndex < 0)
+ return FALSE;
+ return TRUE;
+}
+
+static void opacifyFini(CompPlugin * p)
+{
+ if (displayPrivateIndex >= 0)
+ freeDisplayPrivateIndex(displayPrivateIndex);
+}
+
+static int opacifyGetVersion(CompPlugin * p, int version)
+{
+ return ABIVERSION;
+}
+
+CompPluginVTable opacifyVTable = {
+ "opacify",
+ N_("Opacify"),
+ N_("Make windows easily visible by hovering the mouse over them"),
+ opacifyGetVersion,
+ opacifyInit,
+ opacifyFini,
+ opacifyInitDisplay,
+ opacifyFiniDisplay,
+ opacifyInitScreen,
+ opacifyFiniScreen,
+ opacifyInitWindow,
+ opacifyFiniWindow,
+ 0,
+ 0,
+ 0,
+ 0,
+ NULL,
+ 0,
+ 0,
+ 0
+};
+
+CompPluginVTable *getCompPluginInfo(void)
+{
+ return &opacifyVTable;
+}
diff --git a/src/opacify.options b/src/opacify.options
new file mode 100644
index 0000000..d959ea8
--- /dev/null
+++ b/src/opacify.options
@@ -0,0 +1,70 @@
+<plugin name="opacify">
+ <display>
+ <group name="Bindings">
+ <option name="toggle" type="action">
+ <short>Toggle Opacify</short>
+ <long>Use this to enable/disable Opacify on the fly. Previously opacified windows will not be reset once you disable it like this.</long>
+ <key>Super+o</key>
+ </option>
+ </group>
+ <group name="Misc. Options">
+ <option name="toggle_reset" type="bool">
+ <short>Reset opacity to original values when toggling</short>
+ <long>Reset the opacity of all windows modified by opacify when toggling Opacify with the defined key-combination.</long>
+ <default>true</default>
+ </option>
+ <option name="timeout" type="int">
+ <short>Delay until Opacification</short>
+ <long>The delay (in ms) before Opacify changes opacity after the active window has changed.</long>
+ <default>700</default>
+ <min>0</min>
+ <max>10000</max>
+ </option>
+ <option name="init_toggle" type="bool">
+ <short>Toggle Opacify on by default</short>
+ <long>With this enabled, opacify will be on when you load Opacify, which is usually when you start Beryl.</long>
+ <default>true</default>
+ </option>
+ </group>
+ </display>
+ <screen>
+ <group name="Misc. Options">
+ <option name="only_if_block" type="bool">
+ <short>Only increase opacity if a window is blocking</short>
+ <long>Only increase the opacity on the targeted window if it has one or more windows blocking it from view.</long>
+ <default>false</default>
+ </option>
+ <option name="focus_instant" type="bool">
+ <short>Bypass delay when the new active window is the focused window.</short>
+ <long>Do not wait if the window we are hovering is the focused window. This allows us to instantly see the focused window. You probably want to disable this if you are not using 'Click to Focus'.</long>
+ <default>false</default>
+ </option>
+ <option name="no_delay_change" type="bool">
+ <short>Bypass delay when Opacify is reducing the opacity on one or more windows already.</short>
+ <long>This enables you to let Opacify instantly opacify new windows when you're already making one or more windows invisible. Makes for faster behavior while looking through layers of hidden windows.</long>
+ <default>false</default>
+ </option>
+ <option name="window_match" type="match">
+ <short>Window Match</short>
+ <long>Windows that should be opacified.</long>
+ <default>Toolbar | Utility | Dialog | ModelDialog | Fullscreen | Normal</default>
+ </option>
+ <subgroup name="Opacity Levels">
+ <option name="active_opacity" type="int">
+ <short>Active Opacity</short>
+ <long>The minimum opacity percentage to ensure a targeted window has. A target window will have either this opacity or the preset opacity, whichever is higher.</long>
+ <default>100</default>
+ <min>1</min>
+ <max>100</max>
+ </option>
+ <option name="passive_opacity" type="int">
+ <short>Passive Opacity</short>
+ <long>The maximum opacity percentage a window blocking the current targeted window can have. A blocking window will have either this opacity or the preset opacity, whichever is lower.</long>
+ <default>10</default>
+ <min>1</min>
+ <max>100</max>
+ </option>
+ </subgroup>
+ </group>
+ </screen>
+</plugin>