Logo Search packages:      
Sourcecode: beryl-plugins version File versions

trailfocus2.c

/**
 * 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;
}

Generated by  Doxygen 1.6.0   Back to index