/** * * Beryl snow plugin * * snow.c * * Copyright (c) 2006 Eckhart P. * Copyright (c) 2006 Brian Jørgensen * * 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. for providing * a clean plugin template * Also thanks to the folks from #beryl-dev, especially Quinn_Storm * for helping me make this possible */ #include #include #include #include #include #include #include // ------------------------------------------------------------ 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; }