/**
 *
 * Beryl benchmark plugin
 *
 * bench.c
 *
 * Copyright : (C) 2006 by Dennis Kasprzyk
 * E-mail    : onestone@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.
 *
 **/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrender.h>
#include <beryl.h>

#include "bench_tex.h"

#define GET_BENCH_DISPLAY(d)                                  \
    ((BenchDisplay *) (d)->privates[displayPrivateIndex].ptr)

#define BENCH_DISPLAY(d)                      \
    BenchDisplay *bd = GET_BENCH_DISPLAY (d)

#define GET_BENCH_SCREEN(s, bd)                                   \
    ((BenchScreen *) (s)->privates[(bd)->screenPrivateIndex].ptr)

#define BENCH_SCREEN(s)                                                      \
    BenchScreen *bs = GET_BENCH_SCREEN (s, GET_BENCH_DISPLAY (s->display))

#define TIMEVALDIFF(tv1, tv2)                                              \
    (((tv1)->tv_sec == (tv2)->tv_sec || (tv1)->tv_usec >= (tv2)->tv_usec) ? \
     ((((tv1)->tv_sec - (tv2)->tv_sec) * 1000000) +                         \
      ((tv1)->tv_usec - (tv2)->tv_usec)) / 1000 :                           \
     ((((tv1)->tv_sec - 1 - (tv2)->tv_sec) * 1000000) +                     \
      (1000000 + (tv1)->tv_usec - (tv2)->tv_usec)) / 1000)

#define TIMEVALDIFFU(tv1, tv2)                                              \
    (((tv1)->tv_sec == (tv2)->tv_sec || (tv1)->tv_usec >= (tv2)->tv_usec) ? \
     ((((tv1)->tv_sec - (tv2)->tv_sec) * 1000000) +                      \
      ((tv1)->tv_usec - (tv2)->tv_usec)):                                   \
     ((((tv1)->tv_sec - 1 - (tv2)->tv_sec) * 1000000) +                  \
      (1000000 + (tv1)->tv_usec - (tv2)->tv_usec)))

#ifdef GL_DEBUG
static GLenum gl_error;

#define GLERR  gl_error=glGetError(); if (gl_error !=  GL_NO_ERROR) { fprintf (stderr,"GL error 0x%X has occured at %s:%d\n",gl_error,__FILE__,__LINE__); }
#else
#define GLERR
#endif

#define BENCH_DISPLAY_OPTION_INITIATE                       0
#define BENCH_DISPLAY_OPTION_DISABLE_LIMIT                  1
#define BENCH_DISPLAY_OPTION_POS_X                          2
#define BENCH_DISPLAY_OPTION_POS_Y                          3
#define BENCH_DISPLAY_OPTION_OUTPUT_SCREEN                  4
#define BENCH_DISPLAY_OPTION_OUTPUT_CONSOLE                 5
#define BENCH_DISPLAY_OPTION_CONSOLE_UPDATE_TIME            6
#define BENCH_DISPLAY_OPTION_NUM                            7

#define BENCH_DISPLAY_OPTION_DISABLE_LIMIT_DEFAULT          TRUE
#define BENCH_DISPLAY_OPTION_POS_X_DEFAULT                  0
#define BENCH_DISPLAY_OPTION_POS_Y_DEFAULT                  0
#define BENCH_DISPLAY_OPTION_OUTPUT_SCREEN_DEFAULT          TRUE
#define BENCH_DISPLAY_OPTION_OUTPUT_CONSOLE_DEFAULT         FALSE
#define BENCH_DISPLAY_OPTION_CONSOLE_UPDATE_TIME_DEFAULT    5


#define BENCH_DISPLAY_OPTION_INITIATE_KEY                   "F12"
#define BENCH_DISPLAY_OPTION_INITIATE_MOD                   CompSuperMask

#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))

static int displayPrivateIndex = 0;

typedef struct _BenchDisplay
{
	int screenPrivateIndex;
	Bool active;

	CompOption opt[BENCH_DISPLAY_OPTION_NUM];
} BenchDisplay;

typedef struct _BenchScreen
{
	GLuint dList;
	float rrVal;
	float fps;
	float alpha;
	struct timeval initTime;
	struct timeval lastRedraw;
	float ctime;
	float frames;

	GLuint numTex[10];
	GLuint backTex;

	PreparePaintScreenProc preparePaintScreen;
	DonePaintScreenProc donePaintScreen;
	PaintScreenProc paintScreen;

} BenchScreen;

static void benchPreparePaintScreen(CompScreen * s, int msSinceLastPaint)
{
	BENCH_SCREEN(s);
	BENCH_DISPLAY(s->display);

	float nRrVal;
	float ratio = 0.05;
	int timediff;
	struct timeval now;

	gettimeofday(&now, 0);

	timediff = TIMEVALDIFF(&now, &bs->lastRedraw);

	nRrVal = MIN(1.1, (float)s->optimalRedrawTime / (float)timediff);

	bs->rrVal = (bs->rrVal * (1.0 - ratio)) + (nRrVal * ratio);

	bs->fps =
			(bs->fps * (1.0 - ratio)) +
			(1000000.0 / TIMEVALDIFFU(&now, &bs->lastRedraw) * ratio);

	bs->lastRedraw = now;

	if (bd->opt[BENCH_DISPLAY_OPTION_OUTPUT_CONSOLE].value.b && bd->active)
	{
		bs->frames++;
		bs->ctime += timediff;
		if (bs->ctime >
			bd->opt[BENCH_DISPLAY_OPTION_CONSOLE_UPDATE_TIME].value.i * 1000)
		{
			printf("[BENCH] : %.0f frames in %.1f seconds = %.3f FPS\n",
				   bs->frames, bs->ctime / 1000.0,
				   bs->frames / (bs->ctime / 1000.0));
			bs->frames = 0;
			bs->ctime = 0;
		}
	}

	UNWRAP(bs, s, preparePaintScreen);
	(*s->preparePaintScreen) (s,
							  (bs->alpha >
							   0.0) ? timediff : msSinceLastPaint);
	WRAP(bs, s, preparePaintScreen, benchPreparePaintScreen);

	if (bd->active)
		bs->alpha += timediff / 1000.0;
	else
		bs->alpha -= timediff / 1000.0;

	bs->alpha = MIN(1.0, MAX(0.0, bs->alpha));
}

static void benchDonePaintScreen(CompScreen * s)
{
	BENCH_SCREEN(s);
	BENCH_DISPLAY(s->display);

	if (bs->alpha > 0.0)
	{
		damageScreen(s);
		glFlush();
		XSync(s->display->display, FALSE);
		if (bd->opt[BENCH_DISPLAY_OPTION_DISABLE_LIMIT].value.b)
		{
			s->lastRedraw = bs->initTime;
			s->timeMult = 0;
		}
		if (!bd->active)
			s->timeMult = 0;
	}
	UNWRAP(bs, s, donePaintScreen);
	(*s->donePaintScreen) (s);
	WRAP(bs, s, donePaintScreen, benchDonePaintScreen);
}


static Bool
benchPaintScreen(CompScreen * s, const ScreenPaintAttrib * sa,
				 Region region, int output, unsigned int mask)
{

	Bool status, isSet;
	unsigned int fps;

	BENCH_SCREEN(s);
	BENCH_DISPLAY(s->display);

	UNWRAP(bs, s, paintScreen);
	status = (*s->paintScreen) (s, sa, region, output, mask);
	WRAP(bs, s, paintScreen, benchPaintScreen);

	if (bs->alpha <= 0.0
		|| !bd->opt[BENCH_DISPLAY_OPTION_OUTPUT_SCREEN].value.b)
		return status;
	glGetError();
	glPushAttrib(GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT);
	GLERR;

	glPushMatrix();
	glLoadIdentity();
	prepareXCoords(s, output, -DEFAULT_Z_CAMERA);

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glColor4f(1.0, 1.0, 1.0, bs->alpha);

	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

	glTranslatef(bd->opt[BENCH_DISPLAY_OPTION_POS_X].value.i,
				 bd->opt[BENCH_DISPLAY_OPTION_POS_Y].value.i, 0);

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, bs->backTex);

	glBegin(GL_QUADS);
	glTexCoord2f(0, 0);
	glVertex2f(0, 0);
	glTexCoord2f(0, 1);
	glVertex2f(0, 256);
	glTexCoord2f(1, 1);
	glVertex2f(512, 256);
	glTexCoord2f(1, 0);
	glVertex2f(512, 0);
	glEnd();

	glBindTexture(GL_TEXTURE_2D, 0);
	glDisable(GL_TEXTURE_2D);


	glTranslatef(53, 83, 0);
	float rrVal = MIN(1.0, MAX(0.0, bs->rrVal));

	if (rrVal < 0.5)
	{

		glBegin(GL_QUADS);
		glColor4f(1.0, 0.0, 0.0, bs->alpha);
		glVertex2f(0.0, 0.0);
		glVertex2f(0.0, 25.0);
		glColor4f(1.0, rrVal * 2.0, 0.0, bs->alpha);
		glVertex2f(330.0 * rrVal, 25.0);
		glVertex2f(330.0 * rrVal, 0.0);
		glEnd();
	}
	else
	{

		glBegin(GL_QUADS);
		glColor4f(1.0, 0.0, 0.0, bs->alpha);
		glVertex2f(0.0, 0.0);
		glVertex2f(0.0, 25.0);
		glColor4f(1.0, 1.0, 0.0, bs->alpha);
		glVertex2f(165.0, 25.0);
		glVertex2f(165.0, 0.0);
		glEnd();

		glBegin(GL_QUADS);
		glColor4f(1.0, 1.0, 0.0, bs->alpha);
		glVertex2f(165.0, 0.0);
		glVertex2f(165.0, 25.0);
		glColor4f(1.0 - ((rrVal - 0.5) * 2.0), 1.0, 0.0, bs->alpha);
		glVertex2f(165.0 + 330.0 * (rrVal - 0.5), 25.0);
		glVertex2f(165.0 + 330.0 * (rrVal - 0.5), 0.0);
		glEnd();

	}

	glColor4f(0.0, 0.0, 0.0, bs->alpha);

	glCallList(bs->dList);

	glTranslatef(72, 45, 0);

	float red;

	if (bs->fps > 30.0)
		red = 0.0;
	else
		red = 1.0;
	if (bs->fps <= 30.0 && bs->fps > 20.0)
		red = 1.0 - ((bs->fps - 20.0) / 10.0);

	glColor4f(red, 0.0, 0.0, bs->alpha);

	glEnable(GL_TEXTURE_2D);
	isSet = FALSE;
	fps = (bs->fps * 100.0);
	fps = MIN(999999, fps);

	if (fps >= 100000)
	{
		glBindTexture(GL_TEXTURE_2D, bs->numTex[fps / 100000]);
		glCallList(bs->dList + 1);
		isSet = TRUE;
	}
	fps %= 100000;
	glTranslatef(12, 0, 0);
	if (fps >= 10000 || isSet)
	{
		glBindTexture(GL_TEXTURE_2D, bs->numTex[fps / 10000]);
		glCallList(bs->dList + 1);
		isSet = TRUE;
	}
	fps %= 10000;
	glTranslatef(12, 0, 0);
	if (fps >= 1000 || isSet)
	{
		glBindTexture(GL_TEXTURE_2D, bs->numTex[fps / 1000]);
		glCallList(bs->dList + 1);
	}
	fps %= 1000;
	glTranslatef(12, 0, 0);

	glBindTexture(GL_TEXTURE_2D, bs->numTex[fps / 100]);
	glCallList(bs->dList + 1);
	fps %= 100;

	glTranslatef(19, 0, 0);

	glBindTexture(GL_TEXTURE_2D, bs->numTex[fps / 10]);
	glCallList(bs->dList + 1);
	fps %= 10;

	glTranslatef(12, 0, 0);

	glBindTexture(GL_TEXTURE_2D, bs->numTex[fps]);
	glCallList(bs->dList + 1);

	glBindTexture(GL_TEXTURE_2D, 0);
	glDisable(GL_TEXTURE_2D);

	glPopMatrix();

	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

	glColor4f(1.0, 1.0, 1.0, 1.0);

	glPopAttrib();
	glGetError();

	return status;
}

static Bool benchInitScreen(CompPlugin * p, CompScreen * s)
{
	int i;

	BENCH_DISPLAY(s->display);

	BenchScreen *bs = (BenchScreen *) calloc(1, sizeof(BenchScreen));

	s->privates[bd->screenPrivateIndex].ptr = bs;

	WRAP(bs, s, paintScreen, benchPaintScreen);
	WRAP(bs, s, preparePaintScreen, benchPreparePaintScreen);
	WRAP(bs, s, donePaintScreen, benchDonePaintScreen);

	glGenTextures(10, bs->numTex);
	glGenTextures(1, &bs->backTex);

	glGetError();

	glEnable(GL_TEXTURE_2D);

	bs->alpha = 0;
	bs->ctime = 0;
	bs->frames = 0;

	for (i = 0; i < 10; i++)
	{
		//Bind the texture
		glBindTexture(GL_TEXTURE_2D, bs->numTex[i]);

		//Load the parameters
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

		glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 16, 32, 0,
					 GL_RGBA, GL_UNSIGNED_BYTE, number_data[i]);
		GLERR;
	}

	glBindTexture(GL_TEXTURE_2D, bs->backTex);

	//Load the parameters
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

	glTexImage2D(GL_TEXTURE_2D, 0, 4, 512, 256, 0, GL_RGBA,
				 GL_UNSIGNED_BYTE, image_data);
	GLERR;

	glBindTexture(GL_TEXTURE_2D, 0);
	glDisable(GL_TEXTURE_2D);

	bs->dList = glGenLists(2);
	glNewList(bs->dList, GL_COMPILE);

	glLineWidth(2.0);

	glBegin(GL_LINE_LOOP);
	glVertex2f(0, 0);
	glVertex2f(0, 25);
	glVertex2f(330, 25);
	glVertex2f(330, 0);
	glEnd();

	glLineWidth(1.0);

	glBegin(GL_LINES);
	for (i = 33; i < 330; i += 33)
	{
		glVertex2f(i, 15);
		glVertex2f(i, 25);
	}
	for (i = 16; i < 330; i += 33)
	{
		glVertex2f(i, 20);
		glVertex2f(i, 25);
	}
	glEnd();

	glEndList();

	glNewList(bs->dList + 1, GL_COMPILE);
	glBegin(GL_QUADS);
	glTexCoord2f(0, 0);
	glVertex2f(0, 0);
	glTexCoord2f(0, 1);
	glVertex2f(0, 32);
	glTexCoord2f(1, 1);
	glVertex2f(16, 32);
	glTexCoord2f(1, 0);
	glVertex2f(16, 0);
	glEnd();
	glEndList();


	gettimeofday(&bs->initTime, 0);
	gettimeofday(&bs->lastRedraw, 0);

	addScreenAction(s, &bd->opt[BENCH_DISPLAY_OPTION_INITIATE].value.action);

	return TRUE;
}


static void benchFiniScreen(CompPlugin * p, CompScreen * s)
{

	BENCH_SCREEN(s);
	BENCH_DISPLAY(s->display);
	glDeleteLists(bs->dList, 2);

	glDeleteTextures(10, bs->numTex);
	glDeleteTextures(1, &bs->backTex);

	//Restore the original function
	UNWRAP(bs, s, paintScreen);
	UNWRAP(bs, s, preparePaintScreen);
	UNWRAP(bs, s, donePaintScreen);

	removeScreenAction(s,
					   &bd->opt[BENCH_DISPLAY_OPTION_INITIATE].value.action);

	//Free the pointer
	free(bs);

}

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

	BENCH_DISPLAY(display);

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

	switch (index)
	{
	case BENCH_DISPLAY_OPTION_INITIATE:
		if (setDisplayAction(display, o, value))
			return TRUE;
		break;
	case BENCH_DISPLAY_OPTION_DISABLE_LIMIT:
	case BENCH_DISPLAY_OPTION_OUTPUT_SCREEN:
	case BENCH_DISPLAY_OPTION_OUTPUT_CONSOLE:
		if (compSetBoolOption(o, value))
			return TRUE;
		break;
	case BENCH_DISPLAY_OPTION_POS_X:
	case BENCH_DISPLAY_OPTION_POS_Y:
	case BENCH_DISPLAY_OPTION_CONSOLE_UPDATE_TIME:
		if (compSetIntOption(o, value))
			return TRUE;
		break;

	default:
		break;
	}

	return FALSE;
}

static Bool
benchInitiate(CompDisplay * d, CompAction * ac, CompActionState state,
			  CompOption * option, int nOption)
{
	CompScreen *s;

	BENCH_DISPLAY(d);
	bd->active = !bd->active;
	bd->active &= bd->opt[BENCH_DISPLAY_OPTION_OUTPUT_SCREEN].value.b
			|| bd->opt[BENCH_DISPLAY_OPTION_OUTPUT_CONSOLE].value.b;
	s = findScreenAtDisplay(d, getIntOptionNamed(option, nOption, "root", 0));
	if (s)
	{
		BENCH_SCREEN(s);
		damageScreen(s);
		bs->ctime = 0;
		bs->frames = 0;
	}
	return FALSE;
}

static void benchDisplayInitOptions(BenchDisplay * bd)
{
	CompOption *o;

	o = &bd->opt[BENCH_DISPLAY_OPTION_INITIATE];
	o->advanced = False;
	o->name = "initiate";
	o->group = N_("Main");
	o->subGroup = N_("");
	o->displayHints = "";
	o->shortDesc = N_("Initiate");
	o->longDesc = N_("Start benchmark");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = benchInitiate;
	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 = BENCH_DISPLAY_OPTION_INITIATE_MOD;
	o->value.action.key.keysym =
			XStringToKeysym(BENCH_DISPLAY_OPTION_INITIATE_KEY);

	o = &bd->opt[BENCH_DISPLAY_OPTION_OUTPUT_SCREEN];
	o->advanced = False;
	o->name = "output_screen";
	o->group = N_("Main");
	o->subGroup = N_("Screen Output");
	o->displayHints = "";
	o->shortDesc = N_("Enable");
	o->longDesc = N_("Display FPS on screen");
	o->type = CompOptionTypeBool;
	o->value.b = BENCH_DISPLAY_OPTION_OUTPUT_SCREEN_DEFAULT;

	o = &bd->opt[BENCH_DISPLAY_OPTION_OUTPUT_CONSOLE];
	o->advanced = False;
	o->name = "output_console";
	o->group = N_("Main");
	o->subGroup = N_("Console Output");
	o->displayHints = "";
	o->shortDesc = N_("Enable");
	o->longDesc = N_("Print FPS to console");
	o->type = CompOptionTypeBool;
	o->value.b = BENCH_DISPLAY_OPTION_OUTPUT_CONSOLE_DEFAULT;

	o = &bd->opt[BENCH_DISPLAY_OPTION_CONSOLE_UPDATE_TIME];
	o->advanced = False;
	o->name = "console_update_time";
	o->group = N_("Main");
	o->subGroup = N_("Console Output");
	o->displayHints = "";
	o->shortDesc = N_("Update time");
	o->longDesc = N_("Console output update time");
	o->type = CompOptionTypeInt;
	o->value.i = BENCH_DISPLAY_OPTION_CONSOLE_UPDATE_TIME_DEFAULT;
	o->rest.i.min = 1;
	o->rest.i.max = 60;

	o = &bd->opt[BENCH_DISPLAY_OPTION_DISABLE_LIMIT];
	o->advanced = False;
	o->name = "disable_limiter";
	o->group = N_("Main");
	o->subGroup = N_("");
	o->displayHints = "";
	o->shortDesc = N_("Disable limiter");
	o->longDesc = N_("Disable beryl integrated FPS limiter");
	o->type = CompOptionTypeBool;
	o->value.b = BENCH_DISPLAY_OPTION_DISABLE_LIMIT_DEFAULT;

	o = &bd->opt[BENCH_DISPLAY_OPTION_POS_X];
	o->advanced = False;
	o->name = "position_x";
	o->group = N_("Main");
	o->subGroup = N_("Screen Output");
	o->displayHints = "";
	o->shortDesc = N_("X position");
	o->longDesc = N_("X Position of benchmark window");
	o->type = CompOptionTypeInt;
	o->value.i = BENCH_DISPLAY_OPTION_POS_X_DEFAULT;
	o->rest.i.min = 0;
	o->rest.i.max = 4096;

	o = &bd->opt[BENCH_DISPLAY_OPTION_POS_Y];
	o->advanced = False;
	o->name = "position_y";
	o->group = N_("Main");
	o->subGroup = N_("Screen Output");
	o->displayHints = "";
	o->shortDesc = N_("Y position");
	o->longDesc = N_("Y Position of benchmark window");
	o->type = CompOptionTypeInt;
	o->value.i = BENCH_DISPLAY_OPTION_POS_X_DEFAULT;
	o->rest.i.min = 0;
	o->rest.i.max = 4096;
}

static CompOption *benchGetDisplayOptions(CompDisplay * display, int *count)
{
	if (display)
	{
		BENCH_DISPLAY(display);

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

		benchDisplayInitOptions(bd);
		*count = NUM_OPTIONS(bd);
		return bd->opt;
	}
}



static Bool benchInitDisplay(CompPlugin * p, CompDisplay * d)
{
	//Generate a bench display
	BenchDisplay *bd = (BenchDisplay *) malloc(sizeof(BenchDisplay));

	//Allocate a private index
	bd->screenPrivateIndex = allocateScreenPrivateIndex(d);
	//Check if its valid
	if (bd->screenPrivateIndex < 0)
	{
		//Its invalid so free memory and return
		free(bd);
		return FALSE;
	}
	benchDisplayInitOptions(bd);
	bd->active = FALSE;
	//Record the display
	d->privates[displayPrivateIndex].ptr = bd;
	return TRUE;
}

static void benchFiniDisplay(CompPlugin * p, CompDisplay * d)
{
	BENCH_DISPLAY(d);
	//Free the private index
	freeScreenPrivateIndex(d, bd->screenPrivateIndex);
	//Free the pointer
	free(bd);
}



static Bool benchInit(CompPlugin * p)
{
	displayPrivateIndex = allocateDisplayPrivateIndex();

	if (displayPrivateIndex < 0)
		return FALSE;

	return TRUE;
}

static void benchFini(CompPlugin * p)
{
	if (displayPrivateIndex >= 0)
		freeDisplayPrivateIndex(displayPrivateIndex);
}


CompPluginVTable benchVTable = {
	"bench",
	N_("Benchmark"),
	N_("A simple benchmark plugin"),
	benchInit,
	benchFini,
	benchInitDisplay,
	benchFiniDisplay,
	benchInitScreen,
	benchFiniScreen,
	0,
	0,
	benchGetDisplayOptions,
	benchSetDisplayOption,
	0,
	0,
	0,
	0,
	0,
	0,
	BERYL_ABI_INFO,
	"beryl-plugins",
	"misc",
	0,
	0,
	False,
};

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


syntax highlighted by Code2HTML, v. 0.9.1