/**
* Beryl Trailfocus - take three
*
* 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.
*
* This version is completly rewritten from scratch with opacify as a
* basic template. The original trailfocus was written by:
* François Ingelrest <Athropos@gmail.com> and rewritten by:
* Dennis Kasprzyk <onestone@beryl-project.org>
*
*
* Trailfocus modifies the opacity, brightness and saturation on a window
* based on when it last had focus.
*
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrender.h>
#include <beryl.h>
#define GET_TRAILFOCUS_DISPLAY(d) \
((TrailfocusDisplay *) (d)->privates[displayPrivateIndex].ptr)
#define TRAILFOCUS_DISPLAY(d) \
TrailfocusDisplay *td = GET_TRAILFOCUS_DISPLAY (d)
#define GET_TRAILFOCUS_SCREEN(s, td) \
((TrailfocusScreen *) (s)->privates[(td)->screenPrivateIndex].ptr)
#define TRAILFOCUS_SCREEN(s) \
TrailfocusScreen *ts = GET_TRAILFOCUS_SCREEN (s, GET_TRAILFOCUS_DISPLAY (s->display))
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
#define N_WIN_TYPE (sizeof (winType) / sizeof (winType[0]))
static int displayPrivateIndex = 0;
static char *winType[] = {
N_("Toolbar"),
N_("Utility"),
N_("Dialog"),
N_("ModalDialog"),
N_("Fullscreen"),
N_("Normal")
};
typedef enum _TfOpt
{
SOPT_MAX_OPACITY = 0,
SOPT_MAX_BRIGHTNESS,
SOPT_MAX_SATURATION,
SOPT_MIN_OPACITY,
SOPT_MIN_BRIGHTNESS,
SOPT_MIN_SATURATION,
SOPT_WINDOWS_START,
SOPT_WINDOWS,
SOPT_WINDOW_TYPE,
SOPT_IGNORE_SKIPTASKBAR,
SOPT_IGNORE_SKIPPAGER,
SOPT_NUM
} TrailfocusScreenOptions;
typedef struct _TrailfocusDisplay
{
int screenPrivateIndex;
HandleEventProc handleEvent;
} TrailfocusDisplay;
typedef struct _TfWindowAttributes
{
GLushort opacity;
GLushort brightness;
GLushort saturation;
} TfAttrib;
typedef struct _TrailfocusScreen
{
int wMask;
Window *win;
int win_max;
TfAttrib *inc;
CompOption opt[SOPT_NUM];
} TrailfocusScreen;
/* Core trailfocus functions. These do the real work. ---------------*/
/* Checks if a window is a window trailfocus is supposed to touch or not. */
static Bool is_trailfocus_window(TrailfocusScreen * ts, CompWindow * w)
{
if (!(w->type & ts->wMask))
return False;
if (w->defaultPaintLock.opacity && w->defaultPaintLock.saturation
&& w->defaultPaintLock.brightness)
return False;
if (ts->opt[SOPT_IGNORE_SKIPTASKBAR].value.b
&& w->state & CompWindowStateSkipTaskbarMask)
return False;
if (ts->opt[SOPT_IGNORE_SKIPPAGER].value.b
&& w->state & CompWindowStateSkipPagerMask)
return False;
return True;
}
/* The set_[opacity|brightness|saturation] functions of the
* respective values. These set the default values, see
* paint.c or beryl.h for description of how
* default-vs-permanant paint attributes work.
*/
static inline void set_opacity(CompWindow * w, int opacity)
{
setDefaultWindowOpacity(w, opacity, PL_NO_LOCK);
}
static inline void set_brightness(CompWindow * w, int brightness)
{
setDefaultWindowBrightness(w, brightness, PL_NO_LOCK);
}
static inline void set_saturation(CompWindow * w, int sat)
{
setDefaultWindowSaturation(w, sat, PL_NO_LOCK);
}
/* Resets a window's paint attribute when we're bailing out.
*
*/
static inline void bail_out_window(CompWindow * w)
{
setWindowBailout(w, PL_NO_LOCK);
}
/* Meant for unload. Reset all windows handled by us. */
static void bail_out_tf(CompScreen * s)
{
CompWindow *w;
TRAILFOCUS_SCREEN(s);
for (w = s->windows; w; w = w->next)
if (is_trailfocus_window(ts, w))
bail_out_window(w);
}
/* Meant for option change. Reset all windows not handled by us.
* Ideally we should have a window-diff here, but alas... we don't.
* So we reset all we don't handle. Room for improvement if necesarry.
*/
static void bail_out_non_tf(CompScreen * s)
{
CompWindow *w;
TRAILFOCUS_SCREEN(s);
for (w = s->windows; w; w = w->next)
if (!is_trailfocus_window(ts, w))
bail_out_window(w);
}
/* Sets the opacity, saturation and brightness to that of a window
* that had focus N times ago.
*/
static inline void set_window(TrailfocusScreen * ts, CompWindow * w, int n)
{
set_opacity(w, ts->inc[n].opacity);
set_saturation(w, ts->inc[n].saturation);
set_brightness(w, ts->inc[n].brightness);
}
/* Walks through the window-list and sets the opacity-levels for
* all windows. The inner loop will result in ts->win[i] either
* representing a recently focused window, or the least
* focused window.
*/
static void set_windows(CompScreen * s)
{
CompWindow *w;
TRAILFOCUS_SCREEN(s);
int i = 0;
for (w = s->windows; w; w = w->next)
{
if (w->invisible || w->hidden || w->minimized)
continue;
if (!is_trailfocus_window(ts, w))
continue;
for (i = 0; i < ts->win_max; i++)
if (w->id == ts->win[i])
break;
set_window(ts, w, i);
}
}
/* Push a new window-id on the trailfocus window-stack (not to be
* confused with the real window stack). Only keep one copy of a
* window on the stack. If the window allready exist on the stack,
* move it to the top.
*/
static CompScreen *push_window(CompDisplay * d, Window id)
{
int i;
short int tmp;
CompWindow *w;
CompScreen *s;
w = findWindowAtDisplay(d, id);
if (UNLIKELY(!w))
return NULL;
s = w->screen;
if (UNLIKELY(!s))
return NULL;
TRAILFOCUS_SCREEN(s);
if (!is_trailfocus_window(ts, w))
return NULL;
tmp = ts->win_max;
for (i = 0; i < ts->win_max; i++)
if (ts->win[i] == id)
break;
if (UNLIKELY(i == 0))
return NULL;
for (; i > 0; i--)
ts->win[i] = ts->win[i - 1];
ts->win[0] = id;
return s;
}
/* Find a window on a screen.... Unlike the findWindowAtScreen which
* core provides, we don't intend to search for the same window several
* times in a row so we optimize for* the normal situation of searching for
* a window only once in a row.
*/
static CompWindow *find_window(CompScreen * s, Window id)
{
CompWindow *w;
for (w = s->windows; w; w = w->next)
if (w->id == id)
return w;
return NULL;
}
/* Walks through the existing stack and removes windows that should
* (no longer) be there. Used for option-change.
*/
static void clean_list(CompScreen * s)
{
TRAILFOCUS_SCREEN(s);
CompWindow *w;
int i, j, length;
for (i = 0; i < ts->win_max; i++)
{
w = find_window(s, ts->win[i]);
if (!w || !is_trailfocus_window(ts, w))
ts->win[i] = 0;
}
length = ts->win_max;
for (i = 0; i < length; i++)
{
if (!ts->win[i])
{
for (j = i; j < length - 1; j++)
ts->win[j] = ts->win[j + 1];
length--;
}
}
for (; length < ts->win_max; length++)
ts->win[length] = 0;
}
/* Handles the event if it was a FocusIn event. */
static void trailfocusHandleEvent(CompDisplay * d, XEvent * event)
{
TRAILFOCUS_DISPLAY(d);
CompScreen *s;
switch (event->type)
{
case FocusIn:
s = push_window(d, event->xfocus.window);
if (s)
set_windows(s);
break;
default:
break;
}
UNWRAP(td, d, handleEvent);
(*d->handleEvent) (d, event);
WRAP(td, d, handleEvent, trailfocusHandleEvent);
}
/* Settings changed. Reallocate rs->inc and re-populate it and the
* rest of the TrailfocusScreen (-wMask).
*/
static void recalculate_attributes(TrailfocusScreen * ts)
{
TfAttrib tmp, min, max;
int i;
int start;
start = ts->opt[SOPT_WINDOWS_START].value.i - 1;
ts->win_max = ts->opt[SOPT_WINDOWS].value.i;
if (start >= ts->win_max)
{
fprintf(stderr,
"trailfocus: WARNING: Attempting to define start higher than max windows.\n");
start = ts->win_max - 1;
}
min.opacity = ts->opt[SOPT_MIN_OPACITY].value.i * OPAQUE / 100;
min.brightness = ts->opt[SOPT_MIN_BRIGHTNESS].value.i * OPAQUE / 100;
min.saturation = ts->opt[SOPT_MIN_SATURATION].value.i * OPAQUE / 100;
max.opacity = ts->opt[SOPT_MAX_OPACITY].value.i * OPAQUE / 100;
max.brightness = ts->opt[SOPT_MAX_BRIGHTNESS].value.i * OPAQUE / 100;
max.saturation = ts->opt[SOPT_MAX_SATURATION].value.i * OPAQUE / 100;
ts->win = realloc(ts->win, sizeof(Window) * (ts->win_max + 1));
ts->inc = realloc(ts->inc, sizeof(TfAttrib) * (ts->win_max + 1));
tmp.opacity = (max.opacity - min.opacity) / ((ts->win_max - start));
tmp.brightness =
(max.brightness - min.brightness) / ((ts->win_max - start));
tmp.saturation =
(max.saturation - min.saturation) / ((ts->win_max - start));
for (i = 0; i < start; ++i)
ts->inc[i] = max;
for (i = 0; i + start <= ts->win_max; i++)
{
ts->inc[i + start].opacity = max.opacity - (tmp.opacity * i);
ts->inc[i + start].brightness = max.brightness - (tmp.brightness * i);
ts->inc[i + start].saturation = max.saturation - (tmp.saturation * i);
ts->win[i + start] = 0;
}
// ts->inc[i+start] = min;
}
/* Unlike the traditional setScreenOptions, we return on failure in the
* switch, so we can execute a couple of common functions at the end.
*/
static Bool trailfocusSetScreenOptions(CompScreen * screen, char *name,
CompOptionValue * value)
{
CompOption *o;
int index;
TRAILFOCUS_SCREEN(screen);
o = compFindOption(ts->opt, NUM_OPTIONS(ts), name, &index);
if (!o)
return FALSE;
switch (index)
{
case SOPT_MAX_OPACITY:
case SOPT_MAX_BRIGHTNESS:
case SOPT_MAX_SATURATION:
case SOPT_MIN_OPACITY:
case SOPT_MIN_BRIGHTNESS:
case SOPT_MIN_SATURATION:
case SOPT_WINDOWS:
case SOPT_WINDOWS_START:
if (!compSetIntOption(o, value))
return FALSE;
recalculate_attributes(ts);
break;
case SOPT_WINDOW_TYPE:
if (!compSetOptionList(o, value))
return FALSE;
ts->wMask = compWindowTypeMaskFromStringList(&o->value);
break;
case SOPT_IGNORE_SKIPPAGER:
case SOPT_IGNORE_SKIPTASKBAR:
if (!compSetBoolOption(o, value))
return FALSE;
break;
default:
return FALSE;
break;
}
bail_out_non_tf(screen);
clean_list(screen);
push_window(screen->display, screen->display->activeWindow);
set_windows(screen);
return TRUE;
}
/* Configuration, initliazation, boring stuff. ----------------------- */
/* Remember to reset windows to some sane value when we unload */
static void trailfocusFiniScreen(CompPlugin * p, CompScreen * s)
{
TRAILFOCUS_SCREEN(s);
bail_out_tf(s);
if (ts->win)
free(ts->win);
if (ts->inc)
free(ts->inc);
if (ts->opt[SOPT_WINDOW_TYPE].value.list.value)
free(ts->opt[SOPT_WINDOW_TYPE].value.list.value);
free(ts);
}
static void trailfocusScreenInitOptions(TrailfocusScreen * ts)
{
CompOption *o;
int i;
o = &ts->opt[SOPT_MAX_OPACITY];
o->name = "max_opacity";
o->group = N_("Appearance");
o->subGroup = N_("Opacity");
o->displayHints = "";
o->shortDesc = N_("Opacity Level of Focused Windows");
o->longDesc = N_("Opacity of the currently Focused Window. Windows "
"will get Opacity Levels between the Focused "
"and Minimum.");
o->type = CompOptionTypeInt;
o->value.i = 100;
o->rest.i.min = 1;
o->rest.i.max = 100;
o->advanced = False;
o = &ts->opt[SOPT_MAX_BRIGHTNESS];
o->name = "max_brightness";
o->group = N_("Appearance");
o->subGroup = N_("Brightness");
o->displayHints = "";
o->shortDesc = N_("Brightness Level of Focused Windows");
o->longDesc = N_("Brightness of the currently Focused Window. Windows "
"will get Brightness Levels between the Focused "
"and Minimum. ");
o->type = CompOptionTypeInt;
o->value.i = 100;
o->rest.i.min = 1;
o->rest.i.max = 100;
o->advanced = False;
o = &ts->opt[SOPT_MAX_SATURATION];
o->name = "max_saturation";
o->group = N_("Appearance");
o->subGroup = N_("Saturation");
o->displayHints = "";
o->shortDesc = N_("Saturation Level of Focused Windows");
o->longDesc = N_("Saturation of the currently Focused Window. Windows "
"will get Saturation Levels between the Focused "
"and Minimum. ");
o->type = CompOptionTypeInt;
o->value.i = 100;
o->rest.i.min = 1;
o->rest.i.max = 100;
o->advanced = False;
o = &ts->opt[SOPT_MIN_OPACITY];
o->name = "min_opacity";
o->group = N_("Appearance");
o->subGroup = N_("Opacity");
o->displayHints = "";
o->shortDesc = N_("Opacity Level of Unfocused Windows");
o->longDesc = N_("Opacity of the least Focused Windows. Windows "
"will get Opacity Levels between the Focused "
"and Minimum. ");
o->type = CompOptionTypeInt;
o->value.i = 70;
o->rest.i.min = 1;
o->rest.i.max = 100;
o->advanced = False;
o = &ts->opt[SOPT_MIN_BRIGHTNESS];
o->name = "min_brightness";
o->group = N_("Appearance");
o->subGroup = N_("Brightness");
o->displayHints = "";
o->shortDesc = N_("Brightness Level of Unfocused Windows");
o->longDesc = N_("Brightness of the least Focused Windows. Windows "
"will get Brightness Levels between the Focused "
"and Minimum. ");
o->type = CompOptionTypeInt;
o->value.i = 100;
o->rest.i.min = 1;
o->rest.i.max = 100;
o->advanced = False;
o = &ts->opt[SOPT_MIN_SATURATION];
o->name = "min_saturation";
o->group = N_("Appearance");
o->subGroup = N_("Saturation");
o->displayHints = "";
o->shortDesc = N_("Saturation Level of Unfocused Windows");
o->longDesc = N_("Saturation of the least Focused Windows. Windows "
"will get Saturation Levels between the Focused "
"and Minimum. ");
o->type = CompOptionTypeInt;
o->value.i = 100;
o->rest.i.min = 1;
o->rest.i.max = 100;
o->advanced = False;
o = &ts->opt[SOPT_WINDOWS];
o->name = "windows";
o->group = N_("Behaviour");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Number of Windows to Track");
o->longDesc = N_("Number of Windows Trailfocus will keep track of. "
"Windows had focus this amount of windows ago or "
"more, will be considered completly unfocused.");
o->type = CompOptionTypeInt;
o->value.i = 5;
o->rest.i.min = 1;
o->rest.i.max = 150;
o->advanced = False;
ts->win_max = 5;
o = &ts->opt[SOPT_WINDOWS_START];
o->name = "windows_start";
o->group = N_("Behaviour");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("What Window to Start Fading");
o->longDesc = N_("This defines when Trailfocus will Start Fading "
"Windows, this lets you set up trailfocus to "
"treat the N first Windows as fully focused.");
o->type = CompOptionTypeInt;
o->value.i = 2;
o->rest.i.min = 1;
o->rest.i.max = 20;
o->advanced = False;
o = &ts->opt[SOPT_WINDOW_TYPE];
o->name = "window_types";
o->group = N_("Behaviour");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Window Types");
o->longDesc = N_("Window Types that should be handled by Trailfocus.");
o->type = CompOptionTypeList;
o->value.list.type = CompOptionTypeString;
o->value.list.nValue = N_WIN_TYPE;
o->value.list.value = malloc(sizeof(CompOptionValue) * N_WIN_TYPE);
for (i = 0; i < N_WIN_TYPE; i++)
o->value.list.value[i].s = strdup(winType[i]);
o->rest.s.string = (char **)windowTypeString;
o->rest.s.nString = nWindowTypeString;
o->advanced = True;
o = &ts->opt[SOPT_IGNORE_SKIPTASKBAR];
o->advanced = True;
o->name = "ignore_skiptaskbar";
o->group = N_("Behaviour");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Ignore \"SkipTaskbar\" Windows");
o->longDesc = N_("Ignore \"SkipTaskbar\" Windows.");
o->type = CompOptionTypeBool;
o->value.b = True;
o = &ts->opt[SOPT_IGNORE_SKIPPAGER];
o->advanced = True;
o->name = "ignore_skippager";
o->group = N_("Behaviour");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Ignore \"SkipPager\" Windows");
o->longDesc = N_("Ignore \"SkipPager\" Windows.");
o->type = CompOptionTypeBool;
o->value.b = True;
}
/* Remember to populate the TrailFocus screen properly, and push the
* active window on the stack, then set windows.
*/
static Bool trailfocusInitScreen(CompPlugin * p, CompScreen * s)
{
TRAILFOCUS_DISPLAY(s->display);
TrailfocusScreen *ts =
(TrailfocusScreen *) calloc(1, sizeof(TrailfocusScreen));
s->privates[td->screenPrivateIndex].ptr = ts;
trailfocusScreenInitOptions(ts);
ts->wMask =
compWindowTypeMaskFromStringList(&ts->opt[SOPT_WINDOW_TYPE].
value);
recalculate_attributes(ts);
push_window(s->display, s->display->activeWindow);
set_windows(s);
return TRUE;
}
static CompOption *trailfocusGetScreenOptions(CompScreen * screen, int *count)
{
if (screen)
{
TRAILFOCUS_SCREEN(screen);
*count = NUM_OPTIONS(ts);
return ts->opt;
}
else
{
TrailfocusScreen *ts = malloc(sizeof(TrailfocusScreen));
trailfocusScreenInitOptions(ts);
*count = NUM_OPTIONS(ts);
return ts->opt;
}
}
static Bool trailfocusInitDisplay(CompPlugin * p, CompDisplay * d)
{
TrailfocusDisplay *td =
(TrailfocusDisplay *) malloc(sizeof(TrailfocusDisplay));
td->screenPrivateIndex = allocateScreenPrivateIndex(d);
if (td->screenPrivateIndex < 0)
{
free(td);
return FALSE;
}
d->privates[displayPrivateIndex].ptr = td;
WRAP(td, d, handleEvent, trailfocusHandleEvent);
return TRUE;
}
static void trailfocusFiniDisplay(CompPlugin * p, CompDisplay * d)
{
TRAILFOCUS_DISPLAY(d);
UNWRAP(td, d, handleEvent);
freeScreenPrivateIndex(d, td->screenPrivateIndex);
free(td);
}
static Bool trailfocusInit(CompPlugin * p)
{
displayPrivateIndex = allocateDisplayPrivateIndex();
if (displayPrivateIndex < 0)
return FALSE;
return TRUE;
}
static void trailfocusFini(CompPlugin * p)
{
if (displayPrivateIndex >= 0)
freeDisplayPrivateIndex(displayPrivateIndex);
}
CompPluginVTable trailfocusVTable = {
"trailfocus2",
N_("Trailfocus"),
N_("Adjust the opacity, saturation and brightness of windows based on when they last had focus."),
trailfocusInit,
trailfocusFini,
trailfocusInitDisplay,
trailfocusFiniDisplay,
trailfocusInitScreen,
trailfocusFiniScreen,
0,
0,
0, // trailfocusGetDisplayOptions,
0, // trailfocusSetDisplayOptions,
trailfocusGetScreenOptions,
trailfocusSetScreenOptions,
0,
0,
0,
0,
BERYL_ABI_INFO,
"beryl-plugins",
"effects",
0,
0,
False,
};
CompPluginVTable *getCompPluginInfo(void)
{
return &trailfocusVTable;
}
syntax highlighted by Code2HTML, v. 0.9.1