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

opacify.c

/**
 * 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 <beryl.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 OPACIFY_DISPLAY_OPTION_TOGGLE 0
#define OPACIFY_DISPLAY_OPTION_TOGGLE_FREEZE 1
#define OPACIFY_DISPLAY_OPTION_INIT_TOGGLE 2
#define OPACIFY_DISPLAY_OPTION_NUM 3

#define OPACIFY_TOGGLE_KEY "o"
#define OPACIFY_TOGGLE_MOD CompSuperMask


#define OPACIFY_SCREEN_OPTION_ACTIVE_OP 0
#define OPACIFY_SCREEN_OPTION_PASSIVE_OP 1
#define OPACIFY_SCREEN_OPTION_ONLY_IF_BLOCK 2
#define OPACIFY_SCREEN_OPTION_WINDOW_TYPE 3
#define OPACIFY_SCREEN_OPTION_TIMEOUT 4
#define OPACIFY_SCREEN_OPTION_FOCUS_INSTANT 5
#define OPACIFY_SCREEN_OPTION_NO_DELAY_CHANGE 6
#define OPACIFY_SCREEN_OPTION_NUM 7
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
#define N_WIN_TYPE (sizeof (winType) / sizeof (winType[0]))

/* 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;
      Bool toggle_reset;
      CompOption opt[OPACIFY_DISPLAY_OPTION_NUM];
} OpacifyDisplay;

static char *winType[] = {
      N_("Toolbar"),
      N_("Utility"),
      N_("Dialog"),
      N_("ModalDialog"),
      N_("Fullscreen"),
      N_("Normal")
};

typedef struct _OpacifyScreen
{
      CompWindow *new_active;
      Window active;
      Window passive[MAX_WINDOWS];
      Region intersect;
      unsigned short int passive_num;
      unsigned int active_op;
      unsigned int passive_op;
      unsigned int timeout;
      int wMask;
      Bool only_if_block;
      Bool just_moved;
      CompTimeoutHandle timeout_handle;
      CompOption opt[OPACIFY_SCREEN_OPTION_NUM];
} OpacifyScreen;

/* Core opacify functions. These do the real work. ---------------------*/

/* Finds the corrosponding CompWindow for Window id. Returns NULL if
 * there is no such window. 
 */
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;
}

/* Sets the real opacity and damages the window if actual opacity and 
 * requested opacity differs. */
static void set_opacity(CompWindow * w, int 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 ow)
{
      CompWindow *w;

      if (!ow)
            return;
      w = find_window(s, ow);
      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 (UNLIKELY(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(os->passive_op, 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 (!(w->type & os->wMask))
                  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 (screenGrabExist(s, "move", 0))
      {
            os->just_moved = True;
            return;
      }

      if (screenGrabExist(s, "rotate", "scale", "resize", 0))
      {
            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->type & os->wMask) && !w->shaded)
      {
            os->active = w->id;
            num = passive_windows(s, w->region);
            if (num || !os->only_if_block)
                  set_opacity(w, MAX(os->active_op, w->paint.opacity));
      }
}

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

      os->timeout_handle = 0;
      if (UNLIKELY(!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(OpacifyScreen *os, CompScreen *s, CompDisplay *d)
{
      if ((os->opt[OPACIFY_SCREEN_OPTION_FOCUS_INSTANT].value.b
           && os->new_active && (os->new_active->id == d->activeWindow)))
             return True;
      if (!os->timeout)
           return True;
      if (!os->new_active || (os->new_active->id == s->root))
            return False;
      if (os->new_active->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
            return False;
      if (os->opt[OPACIFY_SCREEN_OPTION_NO_DELAY_CHANGE].value.b && os->passive_num)
            return True;
      return False;


}
/* 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 os->timeout 
 * micro seconds, or directly if os->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 && !od->toggle_reset)
            return;

      switch (event->type)
      {
      case EnterNotify:
            s = findScreenAtDisplay(d, event->xcrossing.root);
            if (LIKELY(s))
            {
                  OPACIFY_SCREEN(s);
                  if (!od->toggle && !os->active)
                        return;
                  os->new_active = findTopLevelWindowAtScreen(s, event->xcrossing.window);
                  if (os->timeout_handle)
                        compRemoveTimeout(os->timeout_handle);
                  if (check_delay(os,s,d))
                        handle_timeout(s);
                  else
                        os->timeout_handle =
                                    compAddTimeout(os->timeout, handle_timeout, s);
            }
            break;
      case ConfigureNotify:
            s = findScreenAtDisplay(d, event->xconfigure.event);
            if (LIKELY(s))
            {
                  OPACIFY_SCREEN(s);
                  if (os->active != event->xconfigure.window)
                        break;
                  clear_passive(s);
                  if (LIKELY(os->active))
                        w = find_window(s, os->active);
                  if (w)
                        passive_windows(s, w->region);
            }
            break;
      default:
            break;
      }
}


/* Configuration, initialization, boring stuff. ----------------------- */
static void opacifyFiniScreen(CompPlugin * p, CompScreen * s)
{
      OPACIFY_SCREEN(s);
      OPACIFY_DISPLAY(s->display);
      if (os->opt[OPACIFY_SCREEN_OPTION_WINDOW_TYPE].value.list.value)
            free(os->opt[OPACIFY_SCREEN_OPTION_WINDOW_TYPE].value.list.value);

      removeScreenAction(s, &od->opt[OPACIFY_DISPLAY_OPTION_TOGGLE].value.
                                 action);
      if (os->timeout_handle)
            compRemoveTimeout(os->timeout_handle);
      XDestroyRegion(os->intersect);
      free(os);
}

static Bool opacifySetScreenOptions(CompScreen * screen, char *name,
                                                      CompOptionValue * value)
{
      CompOption *o;
      int index;

      OPACIFY_SCREEN(screen);
      o = compFindOption(os->opt, NUM_OPTIONS(os), name, &index);
      if (!o)
            return FALSE;

      switch (index)
      {
      case OPACIFY_SCREEN_OPTION_ACTIVE_OP:
            if (compSetIntOption(o, value))
            {
                  os->active_op = (o->value.i * 0xffff) / 100;
                  return TRUE;
            }
            break;
      case OPACIFY_SCREEN_OPTION_PASSIVE_OP:
            if (compSetIntOption(o, value))
            {
                  os->passive_op = (o->value.i * 0xffff) / 100;
                  return TRUE;
            }
            break;
      case OPACIFY_SCREEN_OPTION_TIMEOUT:
            if (compSetIntOption(o, value))
            {
                  os->timeout = o->value.i * 100;
                  return TRUE;
            }
            break;
      case OPACIFY_SCREEN_OPTION_WINDOW_TYPE:
            if (compSetOptionList(o, value))
            {
                  os->wMask = compWindowTypeMaskFromStringList(&o->value);
                  return TRUE;
            }
            break;
      case OPACIFY_SCREEN_OPTION_FOCUS_INSTANT:
      case OPACIFY_SCREEN_OPTION_NO_DELAY_CHANGE:
            if (compSetBoolOption(o, value))
                  return TRUE;
            break;
      case OPACIFY_SCREEN_OPTION_ONLY_IF_BLOCK:
            if (compSetBoolOption(o, value))
            {
                  os->only_if_block = o->value.b;
                  return TRUE;
            }
            break;
      default:
            break;
      }

      return FALSE;
}

static void opacifyScreenInitOptions(OpacifyScreen * os)
{
      CompOption *o;
      int i;

      o = &os->opt[OPACIFY_SCREEN_OPTION_ONLY_IF_BLOCK];
      o->name = "only_if_block";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Only increase opacity if a window is blocking");
      o->longDesc =
                  N_
                  ("Only increase the opacity on the targeted window if it "
                   "has one or more windows blocking it from view.");
      o->type = CompOptionTypeBool;
      o->value.b = FALSE;
      o->advanced = False;
      os->only_if_block = FALSE;

      o = &os->opt[OPACIFY_SCREEN_OPTION_FOCUS_INSTANT];
      o->name = "focus_instant";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc =
                  N_
                  ("Bypass delay when the new active window is the focused window.");
      o->longDesc =
                  N_("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\".");
      o->type = CompOptionTypeBool;
      o->value.b = FALSE;
      o->advanced = True;

      o = &os->opt[OPACIFY_SCREEN_OPTION_NO_DELAY_CHANGE];
      o->name = "no_delay_change";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc =
                  N_
                  ("Bypass delay when Opacify is reducing the opacity on one or more windows already.");
      o->longDesc =
                  N_("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.");
      o->type = CompOptionTypeBool;
      o->value.b = FALSE;
      o->advanced = True;

      o = &os->opt[OPACIFY_SCREEN_OPTION_ACTIVE_OP];
      o->name = "active_op";
      o->group = N_("Misc. options");
      o->subGroup = N_("Opacity levels");
      o->displayHints = "";
      o->shortDesc = N_("Active Opacity");
      o->longDesc =
                  N_
                  ("The minimum opacity to ensure a targeted window has. "
                   "A target window will have either this opacity or the "
                   "preset opacity, whichever is higher.");
      o->type = CompOptionTypeInt;
      o->value.i = 100;
      o->rest.i.min = 1;
      o->rest.i.max = 100;
      o->advanced = False;
      os->active_op = OPAQUE;

      o = &os->opt[OPACIFY_SCREEN_OPTION_PASSIVE_OP];
      o->name = "passive_op";
      o->group = N_("Misc. options");
      o->subGroup = N_("Opacity levels");
      o->displayHints = "";
      o->shortDesc = N_("Passive Opacity");
      o->longDesc =
                  N_
                  ("The maximum opacity a window blocking the current targeted "
                   "window can have. A blocking window will have either this "
                   "opacity or the preset opacity, whichever is lower.");
      o->type = CompOptionTypeInt;
      o->value.i = 10;
      o->rest.i.min = 1;
      o->rest.i.max = 100;
      o->advanced = False;
      os->passive_op = 0xffff / 10;

      o = &os->opt[OPACIFY_SCREEN_OPTION_TIMEOUT];
      o->name = "timeout";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Delay until Opacification");
      o->longDesc =
                  N_
                  ("The delay in 1/10th of a second before Opacify changes "
                   "opacity after the active window has changed.");
      o->type = CompOptionTypeInt;
      o->value.i = 7;
      o->rest.i.min = 0;
      o->rest.i.max = 100;
      o->advanced = False;
      os->timeout = 700;

      o = &os->opt[OPACIFY_SCREEN_OPTION_WINDOW_TYPE];
      o->name = "window_types";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Window Types");
      o->longDesc = N_("Window types that should be Opacified.");
      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;
      os->wMask = compWindowTypeMaskFromStringList(&o->value);


}

static Bool opacifyInitScreen(CompPlugin * p, CompScreen * s)
{
      OPACIFY_DISPLAY(s->display);
      OpacifyScreen *os = (OpacifyScreen *) calloc(1, sizeof(OpacifyScreen));

      s->privates[od->screenPrivateIndex].ptr = os;
      os->intersect = XCreateRegion();
      opacifyScreenInitOptions(os);
      os->just_moved = False;
      addScreenAction(s, &od->opt[OPACIFY_DISPLAY_OPTION_TOGGLE].value.action);
      return TRUE;
}

static CompOption *opacifyGetScreenOptions(CompScreen * screen, int *count)
{
      if (screen)
      {
            OPACIFY_SCREEN(screen);

            *count = NUM_OPTIONS(os);
            return os->opt;
      }
      else
      {
            OpacifyScreen *os = malloc(sizeof(OpacifyScreen));

            opacifyScreenInitOptions(os);
            *count = NUM_OPTIONS(os);
            return os->opt;
      }
}

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 opacifyDisplayInitOptions(OpacifyDisplay * od)
{
      CompOption *o;

      o = &od->opt[OPACIFY_DISPLAY_OPTION_TOGGLE];
      o->name = "toggle";
      o->group = N_("Bindings");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Toggle Opacify");
      o->longDesc =
                  N_
                  ("Use this to enable/disable Opacify on the fly. Previously "
                   "opacified windows will not be reset once you disable it like this.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = opacify_toggle;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.key.modifiers = OPACIFY_TOGGLE_MOD;
      o->value.action.key.keysym = XStringToKeysym(OPACIFY_TOGGLE_KEY);
      o->advanced = False;

      o = &od->opt[OPACIFY_DISPLAY_OPTION_TOGGLE_FREEZE];
      o->name = "toggle_reset";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Reset opacity to original values when toggling");
      o->longDesc =
                  N_
                  ("Reset the opacity of all windows modified by opacify when "
                   "toggling Opacify with the defined key-combination.");
      o->type = CompOptionTypeBool;
      o->value.b = TRUE;
      o->advanced = True;
      od->toggle_reset = TRUE;

      o = &od->opt[OPACIFY_DISPLAY_OPTION_INIT_TOGGLE];
      o->name = "init_toggle";
      o->group = N_("Misc. options");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Toggle opacify on by default");
      o->longDesc =
                  N_
                  ("With this enabled, opacify will be on when you load Opacify, "
                   "which is usually when you start Beryl.");
      o->type = CompOptionTypeBool;
      o->value.b = True;
      o->advanced = False;
      od->toggle = True;
}

static Bool opacifySetDisplayOptions(CompDisplay * display, char *name,
                                                       CompOptionValue * value)
{
      CompOption *o;
      int index;

      OPACIFY_DISPLAY(display);

      o = compFindOption(od->opt, NUM_OPTIONS(od), name, &index);
      if (!o)
            return FALSE;

      switch (index)
      {
      case OPACIFY_DISPLAY_OPTION_TOGGLE:
            if (setDisplayAction(display, o, value))
                  return TRUE;
            break;
      case OPACIFY_DISPLAY_OPTION_INIT_TOGGLE:
            if (compSetBoolOption(o, value))
            {
                  od->toggle = o->value.b;
                  return TRUE;
            }
            break;
      case OPACIFY_DISPLAY_OPTION_TOGGLE_FREEZE:
            if (compSetBoolOption(o, value))
            {
                  od->toggle_reset = o->value.b;
                  return TRUE;
            }
            break;
      default:
            break;
      }
      return FALSE;
}

static CompOption *opacifyGetDisplayOptions(CompDisplay * display, int *count)
{
      if (display)
      {
            OPACIFY_DISPLAY(display);
            *count = NUM_OPTIONS(od);
            return od->opt;
      }
      else
      {
            OpacifyDisplay *od = malloc(sizeof(OpacifyDisplay));

            opacifyDisplayInitOptions(od);
            *count = NUM_OPTIONS(od);
            return od->opt;
      }
}

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;
      }
      opacifyDisplayInitOptions(od);
      d->privates[displayPrivateIndex].ptr = od;
      WRAP(od, d, handleEvent, opacifyHandleEvent);
      return TRUE;
}

static void opacifyFiniDisplay(CompPlugin * p, CompDisplay * d)
{
      OPACIFY_DISPLAY(d);
      UNWRAP(od, d, handleEvent);
      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);
}

CompPluginVTable opacifyVTable = {
      "opacify",
      N_("Opacify"),
      N_("Make windows easily visible by hovering the mouse over them"),
      opacifyInit,
      opacifyFini,
      opacifyInitDisplay,
      opacifyFiniDisplay,
      opacifyInitScreen,
      opacifyFiniScreen,
      0,
      0,
      opacifyGetDisplayOptions,
      opacifySetDisplayOptions,
      opacifyGetScreenOptions,
      opacifySetScreenOptions,
      0,
      0,
      0,
      0,
      BERYL_ABI_INFO,
      "beryl-plugins",
      "accessibility",
      0,
      0,
      False,
};

CompPluginVTable *getCompPluginInfo(void)
{
      return &opacifyVTable;
}

Generated by  Doxygen 1.6.0   Back to index