/**
*
* Beryl snow plugin
*
* snow.c
*
* Copyright (c) 2006 Eckhart P. <beryl@cornergraf.net>
* Copyright (c) 2006 Brian Jørgensen <qte@fundanemt.com>
*
* 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.
*
**/
/*
* Many thanks to Atie H. <atie.at.matrix@gmail.com> for providing
* a clean plugin template
* Also thanks to the folks from #beryl-dev, especially Quinn_Storm
* for helping me make this possible
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrender.h>
#include <beryl.h>
// ------------------------------------------------------------ CONSTANTS -----------------------------------------------------
#define MAX_SNOWFLAKES 10000
// ------------------------------------------------------------ WRAPPERS -----------------------------------------------------
#define GET_SNOW_DISPLAY(d) \
((SnowDisplay *) (d)->privates[displayPrivateIndex].ptr)
#define SNOW_DISPLAY(d) \
SnowDisplay *sd = GET_SNOW_DISPLAY (d)
#define GET_SNOW_SCREEN(s, sd) \
((SnowScreen *) (s)->privates[(sd)->screenPrivateIndex].ptr)
#define SNOW_SCREEN(s) \
SnowScreen *ss = GET_SNOW_SCREEN (s, GET_SNOW_DISPLAY (s->display))
// ------------------------------------------------------------ OPTIONS -----------------------------------------------------
#define SNOW_DISPLAY_OPTION_NUM_SNOWFLAKES 0
#define SNOW_DISPLAY_OPTION_SNOW_SIZE 1
#define SNOW_DISPLAY_OPTION_SNOW_SPEED 2
#define SNOW_DISPLAY_OPTION_SCREEN_BOXING 3
#define SNOW_DISPLAY_OPTION_SCREEN_DEPTH 4
#define SNOW_DISPLAY_OPTION_INITIATE 5
#define SNOW_DISPLAY_OPTION_ON_TOP 6
#define SNOW_DISPLAY_OPTION_USE_BLENDING 7
#define SNOW_DISPLAY_OPTION_USE_TEXTURES 8
#define SNOW_DISPLAY_OPTION_SNOW_UPDATE_DELAY 9
#define SNOW_DISPLAY_OPTION_SNOW_TEXTURES 10
#define SNOW_DISPLAY_OPTION_SNOW_DIRECTION 11
#define SNOW_DISPLAY_OPTION_ROTATION 12
#define SNOW_DISPLAY_OPTION_NUM 13
#define NUM_SNOW_DIRECTIONS 4
#define SNOW_DISPLAY_OPTION_SNOW_UPDATE_DELAY_DEFAULT 40
#define SNOW_DISPLAY_OPTION_NUM_SNOWFLAKES_DEFAULT 1500.0
#define SNOW_DISPLAY_OPTION_SNOW_SIZE_DEFAULT 10.0
#define SNOW_DISPLAY_OPTION_SNOW_SPEED_DEFAULT 85.0
#define SNOW_DISPLAY_OPTION_SCREEN_BOXING_DEFAULT 400.0
#define SNOW_DISPLAY_OPTION_SCREEN_DEPTH_DEFAULT 1000.0
#define SNOW_DISPLAY_OPTION_SNOW_TEXTURES_DEFAULT ""
#define SNOW_DISPLAY_OPTION_INITIATE_KEY "F3"
#define SNOW_DISPLAY_OPTION_INITIATE_MOD CompSuperMask
#define SNOW_DISPLAY_OPTION_ON_TOP_DEFAULT FALSE
#define SNOW_DISPLAY_OPTION_ROTATION_DEFAULT TRUE
#define SNOW_DISPLAY_OPTION_USE_BLENDING_DEFAULT TRUE
#define SNOW_DISPLAY_OPTION_USE_TEXTURES_DEFAULT TRUE
#define SNOW_DISPLAY_OPTION_DIRECTION_DEFAULT 0
static char *snowDirections[] = {
N_("Top to bottom"),
N_("Bottom to top"),
N_("Right to left"),
N_("Left to right")
};
static char *snowTextures[] = {
IMAGEDIR "/snowflake2.png"
};
#define N_SNOW_TEXTURES (sizeof (snowTextures) / sizeof (snowTextures[0]))
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
static int displayPrivateIndex = 0;
static int numFlakes;
static int snowRotate;
static int snowUpdateDelay;
static float snowSize;
static float snowSpeed;
static float boxing;
static float depth;
static Bool onTop;
static Bool useBlending;
static Bool useTextures;
static Bool displayListNeedsUpdating;
// ------------------------------------------------------------ STRUCTS -----------------------------------------------------
typedef struct _SnowDisplay
{
int screenPrivateIndex;
Bool useBlending;
Bool useTextures;
int snowTexNFiles;
CompOptionValue *snowTexFiles;
float snowSize;
Bool displayListNeedsUpdating;
CompOption opt[SNOW_DISPLAY_OPTION_NUM];
} SnowDisplay;
typedef struct _SnowScreen SnowScreen;
typedef struct _SnowTexture
{
CompTexture tex;
unsigned int width;
unsigned int height;
Bool loaded;
GLuint dList;
} SnowTexture;
typedef struct _SnowFlake
{
float x;
float y;
float z;
float xs;
float ys;
float zs;
float ra; //rotation angle
float rs; //rotation speed
SnowTexture *tex;
} SnowFlake;
static void InitiateSnowFlake(SnowScreen * ss, SnowFlake * sf);
static void setSnowflakeTexture(SnowScreen * ss, SnowFlake * sf);
static void beginRendering(SnowScreen * ss, CompScreen * s, int output);
static void setupDisplayList(SnowScreen * ss);
static void snowThink(SnowScreen * ss, SnowFlake * sf);
static void snowMove(SnowFlake * sf);
struct _SnowScreen
{
CompScreen *s;
Bool active;
CompTimeoutHandle timeoutHandle;
//PreparePaintScreenProc preparePaintScreen;
//DonePaintScreenProc donePaintScreen;
PaintScreenProc paintScreen;
//PaintTransformedScreenProc paintTransformedScreen;
//ApplyScreenTransformProc applyScreenTransform;
//PaintBackgroundProc paintBackground;
PaintWindowProc paintWindow;
DrawWindowProc drawWindow;
//AddWindowGeometryProc addWindowGeometry;
//DrawWindowGeometryProc drawWindowGeometry;
DrawWindowTextureProc drawWindowTexture;
//DamageWindowRectProc damageWindowRect;
//FocusWindowProc focusWindow;
SnowTexture *snowTex;
int snowTexturesLoaded;
GLuint displayList;
SnowFlake allSnowFlakes[MAX_SNOWFLAKES];
};
static void snowThink(SnowScreen * ss, SnowFlake * sf)
{
if (sf->y >= ss->s->height + boxing
|| sf->x <= -boxing
|| sf->y >= ss->s->width + boxing
|| sf->z <= -(depth / 500.0) || sf->z >= 1)
{
InitiateSnowFlake(ss, sf);
}
snowMove(sf);
}
static void snowMove(SnowFlake * sf)
{
float tmp = 1.0f / (100.0f - snowSpeed);
sf->x += (sf->xs * (float)snowUpdateDelay) * tmp;
sf->y += (sf->ys * (float)snowUpdateDelay) * tmp;
sf->z += (sf->zs * (float)snowUpdateDelay) * tmp;
sf->ra += ((float)snowUpdateDelay) / (10.0f - sf->rs);
}
static Bool stepSnowPositions(void *sc)
{
CompScreen *s = sc;
SNOW_SCREEN(s);
if (!ss->active)
return True;
int i = 0;
SnowFlake *snowFlake = ss->allSnowFlakes;
for (i = 0; i < numFlakes; i++)
snowThink(ss, snowFlake++);
if (ss->active && !onTop)
{
CompWindow *w;
for (w = s->windows; w; w = w->next)
{
if (w->type & CompWindowTypeDesktopMask)
{
addWindowDamage(w);
}
}
}
else if (ss->active)
damageScreen(s);
return True;
}
static Bool
snowToggle(CompDisplay * d, CompAction * action, CompActionState state,
CompOption * option, int nOption)
{
CompScreen *s;
Window xid;
xid = getIntOptionNamed(option, nOption, "root", 0);
s = findScreenAtDisplay(d, xid);
if (s)
{
SNOW_SCREEN(s);
ss->active = !ss->active;
if (!ss->active)
damageScreen(s);
}
return TRUE;
}
// ------------------------------------------------- HELPER FUNCTIONS ----------------------------------------------------
int GetRand(int min, int max);
int GetRand(int min, int max)
{
return (rand() % (max - min + 1) + min);
}
float mmrand(int min, int max, float divisor);
float mmrand(int min, int max, float divisor)
{
return ((float)GetRand(min, max)) / divisor;
};
// ------------------------------------------------- RENDERING ----------------------------------------------------
static void setupDisplayList(SnowScreen * ss)
{
// ----------------- untextured list
ss->displayList = glGenLists(1);
glNewList(ss->displayList, GL_COMPILE);
glBegin(GL_QUADS);
glColor4f(1.0, 1.0, 1.0, 1.0);
glVertex3f(0, 0, -0.0);
glColor4f(1.0, 1.0, 1.0, 1.0);
glVertex3f(0, snowSize, -0.0);
glColor4f(1.0, 1.0, 1.0, 1.0);
glVertex3f(snowSize, snowSize, -0.0);
glColor4f(1.0, 1.0, 1.0, 1.0);
glVertex3f(snowSize, 0, -0.0);
glEnd();
glEndList();
}
static void beginRendering(SnowScreen * ss, CompScreen * s, int output)
{
glPushMatrix();
glLoadIdentity();
prepareXCoords(s, output, -DEFAULT_Z_CAMERA);
if (useBlending)
{
glEnable(GL_BLEND);
}
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
if (displayListNeedsUpdating)
{
setupDisplayList(ss);
displayListNeedsUpdating = FALSE;
}
glColor4f(1.0, 1.0, 1.0, 1.0);
if (ss->snowTexturesLoaded && useTextures)
{
int j = 0;
for (j = 0; j < ss->snowTexturesLoaded; j++)
{
enableTexture(ss->s, &ss->snowTex[j].tex,
COMP_TEXTURE_FILTER_GOOD);
int i = 0;
SnowFlake *snowFlake = ss->allSnowFlakes;
for (i = 0; i < numFlakes; i++)
{
if (snowFlake->tex == &ss->snowTex[j])
{
glTranslatef(snowFlake->x, snowFlake->y, snowFlake->z);
if (snowRotate)
glRotatef(snowFlake->ra, 0, 0, 1);
glCallList(ss->snowTex[j].dList);
if (snowRotate)
glRotatef(-snowFlake->ra, 0, 0, 1);
glTranslatef(-snowFlake->x, -snowFlake->y, -snowFlake->z);
}
snowFlake++;
}
disableTexture(ss->s, &ss->snowTex[j].tex);
}
}
else if (!ss->snowTexturesLoaded || !useTextures)
{
int i = 0;
SnowFlake *snowFlake = ss->allSnowFlakes;
for (i = 0; i < numFlakes; i++)
{
glTranslatef(snowFlake->x, snowFlake->y, snowFlake->z);
glRotatef(snowFlake->ra, 0, 0, 1);
glCallList(ss->displayList);
glRotatef(-snowFlake->ra, 0, 0, 1);
glTranslatef(-snowFlake->x, -snowFlake->y, -snowFlake->z);
snowFlake++;
}
}
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
if (useBlending)
{
glDisable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
glPopMatrix();
}
// ------------------------------------------------- FUNCTIONS ----------------------------------------------------
/*static void snowPreparePaintScreen(CompScreen * s, int msSinceLastPaint)
{
SNOW_SCREEN(s);
UNWRAP(ss, s, preparePaintScreen);
(*s->preparePaintScreen) (s, msSinceLastPaint);
WRAP(ss, s, preparePaintScreen, snowPreparePaintScreen);
}*/
/*static void snowDonePaintScreen(CompScreen * s)
{
SNOW_SCREEN(s);
UNWRAP(ss, s, donePaintScreen);
(*s->donePaintScreen) (s);
WRAP(ss, s, donePaintScreen, snowDonePaintScreen);
}*/
static Bool
snowPaintScreen(CompScreen * s, const ScreenPaintAttrib * sa,
Region region, int output, unsigned int mask)
{
Bool status;
SNOW_SCREEN(s);
if (!onTop && ss->active)
{
// This line is essential. Without it the snow will be rendered above (some) other windows.
mask |= PAINT_SCREEN_ORDER_BACK_TO_FRONT_MASK;
}
UNWRAP(ss, s, paintScreen);
status = (*s->paintScreen) (s, sa, region, output, mask);
WRAP(ss, s, paintScreen, snowPaintScreen);
if (onTop && ss->active)
beginRendering(ss, s, output);
return status;
}
static Bool
snowPaintWindow(CompWindow * w, const WindowPaintAttrib * attrib,
Region region, unsigned int mask)
{
int status = TRUE;
SNOW_SCREEN(w->screen);
// First draw Window as usual
UNWRAP(ss, w->screen, paintWindow);
status = (*w->screen->paintWindow) (w, attrib, region, mask);
WRAP(ss, w->screen, paintWindow, snowPaintWindow);
// Check whether this is the Desktop Window
if (w->type & CompWindowTypeDesktopMask && ss->active && !onTop)
{
beginRendering(ss, w->screen, outputDeviceForWindow(w));
}
return status;
}
static void InitiateSnowFlake(SnowScreen * ss, SnowFlake * sf)
{
//TODO: possibly place snowflakes based on FOV, instead of a cube.
SNOW_DISPLAY(ss->s->display);
CompOption *o = &sd->opt[SNOW_DISPLAY_OPTION_SNOW_DIRECTION];
if (strcmp(snowDirections[0], o->value.s) == 0)
{
sf->x = mmrand(-boxing, ss->s->width + boxing, 1);
sf->xs = mmrand(-1, 1, 500);
sf->y = mmrand(-300, 0, 1);
sf->ys = mmrand(1, 3, 1);
}
else if (strcmp(snowDirections[1], o->value.s) == 0)
{
sf->x = mmrand(-boxing, ss->s->width + boxing, 1);
sf->xs = mmrand(-1, 1, 500);
sf->y = mmrand(ss->s->height, ss->s->height + 300, 1);
sf->ys = -mmrand(1, 3, 1);
}
else if (strcmp(snowDirections[2], o->value.s) == 0)
{
sf->x = mmrand(ss->s->width, ss->s->width + 300, 1);
sf->xs = -mmrand(1, 3, 1);
sf->y = mmrand(-boxing, ss->s->height + boxing, 1);
sf->ys = mmrand(-1, 1, 500);
}
else if (strcmp(snowDirections[3], o->value.s) == 0)
{
sf->x = mmrand(-300, 0, 1);
sf->xs = mmrand(1, 3, 1);
sf->y = mmrand(-boxing, ss->s->height + boxing, 1);
sf->ys = mmrand(-1, 1, 500);
}
sf->z = mmrand(-depth, 0.1, 5000);
sf->zs = mmrand(-1000, 1000, 500000);
sf->ra = mmrand(-1000, 1000, 50);
sf->rs = mmrand(-1000, 1000, 1000);
}
static void setSnowflakeTexture(SnowScreen * ss, SnowFlake * sf)
{
if (ss->snowTexturesLoaded)
sf->tex = &ss->snowTex[rand() % ss->snowTexturesLoaded];
}
static void updateSnowTextures(CompScreen * s)
{
SNOW_SCREEN(s);
SNOW_DISPLAY(s->display);
int i = 0;
for (i = 0; i < ss->snowTexturesLoaded; i++)
{
finiTexture(s, &ss->snowTex[i].tex);
glDeleteLists(ss->snowTex[i].dList, 1);
}
if (ss->snowTexturesLoaded)
free(ss->snowTex);
ss->snowTexturesLoaded = 0;
ss->snowTex = calloc(1, sizeof(SnowTexture) * sd->snowTexNFiles);
int count = 0;
for (i = 0; i < sd->snowTexNFiles; i++)
{
ss->snowTex[count].loaded =
readImageToTexture(s, &ss->snowTex[count].tex,
sd->snowTexFiles[i].s,
&ss->snowTex[count].width,
&ss->snowTex[count].height);
if (!ss->snowTex[count].loaded)
{
printf("[Snow]: Texture not found : %s\n", sd->snowTexFiles[i].s);
continue;
}
printf("[Snow]: Loaded Texture %s\n", sd->snowTexFiles[i].s);
CompMatrix *mat = &ss->snowTex[count].tex.matrix;
SnowTexture *sTex = &ss->snowTex[count];
sTex->dList = glGenLists(1);
glNewList(sTex->dList, GL_COMPILE);
glBegin(GL_QUADS);
glTexCoord2f(COMP_TEX_COORD_X(mat, 0), COMP_TEX_COORD_Y(mat, 0));
glVertex2f(0, 0);
glTexCoord2f(COMP_TEX_COORD_X(mat, 0),
COMP_TEX_COORD_Y(mat, sTex->height));
glVertex2f(0, snowSize * sTex->height / sTex->width);
glTexCoord2f(COMP_TEX_COORD_X(mat, sTex->width),
COMP_TEX_COORD_Y(mat, sTex->height));
glVertex2f(snowSize, snowSize * sTex->height / sTex->width);
glTexCoord2f(COMP_TEX_COORD_X(mat, sTex->width),
COMP_TEX_COORD_Y(mat, 0));
glVertex2f(snowSize, 0);
glEnd();
glEndList();
count++;
}
ss->snowTexturesLoaded = count;
if (count < sd->snowTexNFiles)
ss->snowTex = realloc(ss->snowTex, sizeof(SnowTexture) * count);
SnowFlake *snowFlake = ss->allSnowFlakes;
for (i = 0; i < MAX_SNOWFLAKES; i++)
{
setSnowflakeTexture(ss, snowFlake++);
}
}
static Bool snowInitScreen(CompPlugin * p, CompScreen * s)
{
SNOW_DISPLAY(s->display);
SnowScreen *ss = (SnowScreen *) calloc(1, sizeof(SnowScreen));
ss->s = s;
s->privates[sd->screenPrivateIndex].ptr = ss;
int i = 0;
SnowFlake *snowFlake = ss->allSnowFlakes;
for (i = 0; i < MAX_SNOWFLAKES; i++)
{
InitiateSnowFlake(ss, snowFlake);
setSnowflakeTexture(ss, snowFlake);
snowFlake++;
}
updateSnowTextures(s);
setupDisplayList(ss);
ss->active = FALSE;
addScreenAction(s, &sd->opt[SNOW_DISPLAY_OPTION_INITIATE].value.action);
WRAP(ss, s, paintScreen, snowPaintScreen);
//WRAP(ss, s, paintTransformedScreen, snowPaintTransformedScreen);
//WRAP(ss, s, preparePaintScreen, snowPreparePaintScreen);
//WRAP(ss, s, donePaintScreen, snowDonePaintScreen);
WRAP(ss, s, paintWindow, snowPaintWindow);
ss->timeoutHandle = compAddTimeout(snowUpdateDelay, stepSnowPositions, s);
return TRUE;
}
static void snowFiniScreen(CompPlugin * p, CompScreen * s)
{
SNOW_SCREEN(s);
SNOW_DISPLAY(s->display);
compRemoveTimeout(ss->timeoutHandle);
int i = 0;
for (i = 0; i < ss->snowTexturesLoaded; i++)
{
finiTexture(s, &ss->snowTex[i].tex);
glDeleteLists(ss->snowTex[i].dList, 1);
}
if (ss->snowTexturesLoaded)
free(ss->snowTex);
//Restore the original function
UNWRAP(ss, s, paintScreen);
//UNWRAP(ss, s, paintTransformedScreen);
//UNWRAP(ss, s, preparePaintScreen);
//UNWRAP(ss, s, donePaintScreen);
UNWRAP(ss, s, paintWindow);
removeScreenAction(s,
&sd->opt[SNOW_DISPLAY_OPTION_INITIATE].value.action);
//Free the pointer
free(ss);
}
static Bool
snowSetDisplayOption(CompDisplay * display, char *name,
CompOptionValue * value)
{
CompOption *o;
int index;
SNOW_DISPLAY(display);
o = compFindOption(sd->opt, NUM_OPTIONS(sd), name, &index);
if (!o)
return FALSE;
switch (index)
{
case SNOW_DISPLAY_OPTION_NUM_SNOWFLAKES:
if (compSetFloatOption(o, value))
{
numFlakes =
(int)sd->opt[SNOW_DISPLAY_OPTION_NUM_SNOWFLAKES].value.f;
return TRUE;
}
break;
case SNOW_DISPLAY_OPTION_SNOW_DIRECTION:
if (compSetStringOption(o, value))
{
return TRUE;
}
break;
case SNOW_DISPLAY_OPTION_SNOW_SIZE:
if (compSetFloatOption(o, value))
{
snowSize = sd->opt[SNOW_DISPLAY_OPTION_SNOW_SIZE].value.f;
displayListNeedsUpdating = TRUE;
CompScreen *s = display->screens;
updateSnowTextures(s);
return TRUE;
}
break;
case SNOW_DISPLAY_OPTION_SNOW_SPEED:
if (compSetFloatOption(o, value))
{
snowSpeed = sd->opt[SNOW_DISPLAY_OPTION_SNOW_SPEED].value.f;
return TRUE;
}
break;
case SNOW_DISPLAY_OPTION_SNOW_UPDATE_DELAY:
if (compSetIntOption(o, value))
{
CompScreen *s = display->screens;
SNOW_SCREEN(s);
snowUpdateDelay =
sd->opt[SNOW_DISPLAY_OPTION_SNOW_UPDATE_DELAY].value.i;
if (ss->timeoutHandle)
compRemoveTimeout(ss->timeoutHandle);
ss->timeoutHandle =
compAddTimeout(snowUpdateDelay, stepSnowPositions, s);
return TRUE;
}
case SNOW_DISPLAY_OPTION_SCREEN_BOXING:
if (compSetFloatOption(o, value))
{
boxing = sd->opt[SNOW_DISPLAY_OPTION_SCREEN_BOXING].value.f;
return TRUE;
}
break;
case SNOW_DISPLAY_OPTION_SCREEN_DEPTH:
if (compSetFloatOption(o, value))
{
depth = sd->opt[SNOW_DISPLAY_OPTION_SCREEN_DEPTH].value.f;
return TRUE;
}
break;
case SNOW_DISPLAY_OPTION_SNOW_TEXTURES:
if (compSetOptionList(o, value))
{
CompScreen *s = display->screens;
sd->snowTexFiles =
sd->opt[SNOW_DISPLAY_OPTION_SNOW_TEXTURES].value.list.
value;
sd->snowTexNFiles =
sd->opt[SNOW_DISPLAY_OPTION_SNOW_TEXTURES].value.list.
nValue;
updateSnowTextures(s);
return TRUE;
}
break;
case SNOW_DISPLAY_OPTION_INITIATE:
if (setDisplayAction(display, o, value))
return TRUE;
break;
case SNOW_DISPLAY_OPTION_ON_TOP:
if (compSetBoolOption(o, value))
{
onTop = sd->opt[SNOW_DISPLAY_OPTION_ON_TOP].value.b;
return TRUE;
}
break;
case SNOW_DISPLAY_OPTION_ROTATION:
if (compSetBoolOption(o, value))
{
snowRotate = sd->opt[SNOW_DISPLAY_OPTION_ROTATION].value.b;
return TRUE;
}
break;
case SNOW_DISPLAY_OPTION_USE_BLENDING:
if (compSetBoolOption(o, value))
{
useBlending = sd->opt[SNOW_DISPLAY_OPTION_USE_BLENDING].value.b;
return TRUE;
}
case SNOW_DISPLAY_OPTION_USE_TEXTURES:
if (compSetBoolOption(o, value))
{
useTextures = sd->opt[SNOW_DISPLAY_OPTION_USE_TEXTURES].value.b;
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
static void snowDisplayInitOptions(SnowDisplay * sd)
{
CompOption *o;
o = &sd->opt[SNOW_DISPLAY_OPTION_NUM_SNOWFLAKES];
o->advanced = False;
o->name = "num_snowflakes";
o->group = N_("Settings");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Number of Snowflakes");
o->longDesc = N_("Number of Snowflakes");
o->type = CompOptionTypeFloat;
o->value.f = SNOW_DISPLAY_OPTION_NUM_SNOWFLAKES_DEFAULT;
o->rest.f.min = 0;
o->rest.f.max = 10000;
o->rest.f.precision = 1;
o = &sd->opt[SNOW_DISPLAY_OPTION_SNOW_SIZE];
o->advanced = False;
o->name = "snow_size";
o->group = N_("Settings");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Size of snowflakes");
o->longDesc = N_("Size of snowflakes");
o->type = CompOptionTypeFloat;
o->value.f = SNOW_DISPLAY_OPTION_SNOW_SIZE_DEFAULT;
o->rest.f.min = 0;
o->rest.f.max = 50;
o->rest.f.precision = 0.1;
o = &sd->opt[SNOW_DISPLAY_OPTION_SNOW_SPEED];
o->advanced = False;
o->name = "snow_speed";
o->group = N_("Settings");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Speed of falling snow");
o->longDesc = N_("Speed of falling snow");
o->type = CompOptionTypeFloat;
o->value.f = SNOW_DISPLAY_OPTION_SNOW_SPEED_DEFAULT;
o->rest.f.min = 0;
o->rest.f.max = 100;
o->rest.f.precision = 1;
o = &sd->opt[SNOW_DISPLAY_OPTION_SNOW_UPDATE_DELAY];
o->advanced = False;
o->name = "snow_update_delay";
o->group = N_("Settings");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Update Delay");
o->longDesc =
N_
("Delay in ms between screen updates. Deacreasing this value may make snow fall more smoothly, but will also increase CPU usage.");
o->type = CompOptionTypeInt;
o->value.i = SNOW_DISPLAY_OPTION_SNOW_UPDATE_DELAY_DEFAULT;
o->rest.i.min = 10;
o->rest.i.max = 200;
o = &sd->opt[SNOW_DISPLAY_OPTION_SCREEN_BOXING];
o->advanced = False;
o->name = "screen_boxing";
o->group = N_("Settings");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Screen Boxing");
o->longDesc =
N_
("How far outside the screen resolution snowflakes can be before being removed. Needed because of FOV.");
o->type = CompOptionTypeFloat;
o->value.f = SNOW_DISPLAY_OPTION_SCREEN_BOXING_DEFAULT;
o->rest.f.min = -2000;
o->rest.f.max = 2000;
o->rest.f.precision = 1;
o = &sd->opt[SNOW_DISPLAY_OPTION_SCREEN_DEPTH];
o->advanced = False;
o->name = "screen_depth";
o->group = N_("Settings");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Screen Depth");
o->longDesc =
N_
("How deep into the screen snowflakes can be drawn before being removed.");
o->type = CompOptionTypeFloat;
o->value.f = SNOW_DISPLAY_OPTION_SCREEN_DEPTH_DEFAULT;
o->rest.f.min = 0;
o->rest.f.max = SNOW_DISPLAY_OPTION_SCREEN_DEPTH_DEFAULT * 2;
o->rest.f.precision = 1;
o = &sd->opt[SNOW_DISPLAY_OPTION_SNOW_TEXTURES];
o->advanced = False;
o->name = "snow_textures";
o->group = N_("Textures");
o->subGroup = N_("");
o->displayHints = "file;image;pngonly;";
o->shortDesc = N_("Snow Textures");
o->longDesc = N_("Snow textures");
o->type = CompOptionTypeList;
o->value.list.type = CompOptionTypeString;
o->value.list.nValue = N_SNOW_TEXTURES;
o->value.list.value = malloc(sizeof(CompOptionValue) * N_SNOW_TEXTURES);
int i = 0;
for (i = 0; i < N_SNOW_TEXTURES; i++)
o->value.list.value[i].s = strdup(snowTextures[i]);
o->rest.s.string = 0;
o->rest.s.nString = 0;
o = &sd->opt[SNOW_DISPLAY_OPTION_INITIATE];
o->advanced = False;
o->name = "Initiate";
o->group = N_("Key Bindings");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("snow toggle key");
o->longDesc = N_("snow toggle key");
o->type = CompOptionTypeAction;
o->value.action.initiate = snowToggle;
o->value.action.terminate = 0;
o->value.action.bell = FALSE;
o->value.action.type = CompBindingTypeKey;
o->value.action.state = CompActionStateInitKey;
o->value.action.state |= CompActionStateInitButton;
o->value.action.key.modifiers = SNOW_DISPLAY_OPTION_INITIATE_MOD;
o->value.action.key.keysym =
XStringToKeysym(SNOW_DISPLAY_OPTION_INITIATE_KEY);
o = &sd->opt[SNOW_DISPLAY_OPTION_ON_TOP];
o->advanced = False;
o->name = "snow_over_windows";
o->group = N_("Settings");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Snow over windows.");
o->longDesc = N_("Snow is drawn above windows.");
o->type = CompOptionTypeBool;
o->value.b = SNOW_DISPLAY_OPTION_ON_TOP_DEFAULT;
o = &sd->opt[SNOW_DISPLAY_OPTION_ROTATION];
o->advanced = False;
o->name = "snow_rotation";
o->group = N_("Settings");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Rotate flakes");
o->longDesc = N_("Flakes rotate when checked.");
o->type = CompOptionTypeBool;
o->value.b = SNOW_DISPLAY_OPTION_ROTATION_DEFAULT;
o = &sd->opt[SNOW_DISPLAY_OPTION_SNOW_DIRECTION];
o->advanced = False;
o->name = "snow_direction";
o->group = N_("Settings");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Snow Direction");
o->longDesc = N_("Select direction in which the snow should fly.");
o->type = CompOptionTypeString;
o->value.s =
strdup(snowDirections[SNOW_DISPLAY_OPTION_DIRECTION_DEFAULT]);
o->rest.s.string = snowDirections;
o->rest.s.nString = NUM_SNOW_DIRECTIONS;
o = &sd->opt[SNOW_DISPLAY_OPTION_USE_BLENDING];
o->advanced = False;
o->name = "use_blending";
o->group = N_("Debug");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Enable Blending");
o->longDesc = N_("Enables alpha blending of snowflakes");
o->type = CompOptionTypeBool;
o->value.b = SNOW_DISPLAY_OPTION_USE_BLENDING_DEFAULT;
o = &sd->opt[SNOW_DISPLAY_OPTION_USE_TEXTURES];
o->advanced = False;
o->name = "use_textures";
o->group = N_("Debug");
o->subGroup = N_("");
o->displayHints = "";
o->shortDesc = N_("Enable Textures");
o->longDesc =
N_
("Enables textured snowflakes. Otherwise color gradients are used.");
o->type = CompOptionTypeBool;
o->value.b = SNOW_DISPLAY_OPTION_USE_TEXTURES_DEFAULT;
}
static CompOption *snowGetDisplayOptions(CompDisplay * display, int *count)
{
if (display)
{
SNOW_DISPLAY(display);
*count = NUM_OPTIONS(sd);
return sd->opt;
}
else
{
SnowDisplay *sd = malloc(sizeof(SnowDisplay));
snowDisplayInitOptions(sd);
*count = NUM_OPTIONS(sd);
return sd->opt;
}
}
static Bool snowInitDisplay(CompPlugin * p, CompDisplay * d)
{
//Generate a snow display
SnowDisplay *sd = (SnowDisplay *) malloc(sizeof(SnowDisplay));
//Allocate a private index
sd->screenPrivateIndex = allocateScreenPrivateIndex(d);
//Check if its valid
if (sd->screenPrivateIndex < 0)
{
free(sd);
return FALSE;
}
numFlakes = SNOW_DISPLAY_OPTION_NUM_SNOWFLAKES_DEFAULT;
snowRotate = SNOW_DISPLAY_OPTION_ROTATION_DEFAULT;
snowSize = SNOW_DISPLAY_OPTION_SNOW_SIZE_DEFAULT;
snowSpeed = SNOW_DISPLAY_OPTION_SNOW_SPEED_DEFAULT;
snowUpdateDelay = SNOW_DISPLAY_OPTION_SNOW_UPDATE_DELAY_DEFAULT;
boxing = SNOW_DISPLAY_OPTION_SCREEN_BOXING_DEFAULT;
depth = SNOW_DISPLAY_OPTION_SCREEN_DEPTH_DEFAULT;
onTop = SNOW_DISPLAY_OPTION_ON_TOP_DEFAULT;
displayListNeedsUpdating = FALSE;
useBlending = SNOW_DISPLAY_OPTION_USE_BLENDING_DEFAULT;
useTextures = SNOW_DISPLAY_OPTION_USE_TEXTURES_DEFAULT;
snowDisplayInitOptions(sd);
sd->snowTexFiles =
sd->opt[SNOW_DISPLAY_OPTION_SNOW_TEXTURES].value.list.value;
sd->snowTexNFiles =
sd->opt[SNOW_DISPLAY_OPTION_SNOW_TEXTURES].value.list.nValue;
//Record the display
d->privates[displayPrivateIndex].ptr = sd;
return TRUE;
}
static void snowFiniDisplay(CompPlugin * p, CompDisplay * d)
{
SNOW_DISPLAY(d);
//Free the private index
freeScreenPrivateIndex(d, sd->screenPrivateIndex);
//Free the pointer
free(sd);
}
static Bool snowInit(CompPlugin * p)
{
displayPrivateIndex = allocateDisplayPrivateIndex();
if (displayPrivateIndex < 0)
return FALSE;
return TRUE;
}
static void snowFini(CompPlugin * p)
{
if (displayPrivateIndex >= 0)
freeDisplayPrivateIndex(displayPrivateIndex);
}
CompPluginDep snowDeps[] = {
{CompPluginRuleAfterCategory, "imageformat"}
,
};
CompPluginVTable snowVTable = {
"snow",
N_("Snow"),
N_("XSnow for Beryl"),
snowInit,
snowFini,
snowInitDisplay,
snowFiniDisplay,
snowInitScreen,
snowFiniScreen,
0,
0,
snowGetDisplayOptions,
snowSetDisplayOption,
0, /*snowGetScreenOptions */
0, /*snowSetScreenOption */
snowDeps,
sizeof(snowDeps) / sizeof(snowDeps[0]),
0,
0,
BERYL_ABI_INFO,
"beryl-plugins-unsupported",
"misc",
0,
0,
False,
};
CompPluginVTable *getCompPluginInfo(void)
{
return &snowVTable;
}
syntax highlighted by Code2HTML, v. 0.9.1