1 /* fuzzyflakes, Copyright (c) 2004
2 * Barry Dmytro <badcherry@mailc.net>
5 * ! - Added support for resizing
6 * ! - Added a color scheme generation algorithm
7 * ! Thanks to <ZoeB> from #vegans@irc.blitzed.org
8 * ! - Added random color generation
9 * ! - Fixed errors in the xml config file
10 * ! - Cleaned up a few inconsistencies in the code
11 * ! - Changed the default color to #EFBEA5
14 * ! -original creation
16 * Permission to use, copy, modify, distribute, and sell this software and its
17 * documentation for any purpose is hereby granted without fee, provided that
18 * the above copyright notice appear in all copies and that both that
19 * copyright notice and this permission notice appear in supporting
20 * documentation. No representations are made about the suitability of this
21 * software for any purpose. It is provided "as is" without express or
26 #include "screenhack.h"
28 /* I have need of 1/3 and 2/3 constants later on */
29 #define N1_3 0.3333333333
30 #define N2_3 0.6666666666
32 typedef struct _flake_var
41 /* Struct containing the atrributes to our flakes */
48 unsigned long BordColor;
49 unsigned long ForeColor;
50 unsigned long BackColor;
62 /* a dynamic array containing positions of all the flakes */
63 FlakeVariable ***Flakes;
65 unsigned long GCFlags;
69 XWindowAttributes XGWA;
78 *This gets the pixel resource for a color: #ffffff
81 FuzzyFlakesColorResource(char *Color)
85 if (!XParseColor(Flake.DisplayVar, Flake.XGWA.colormap, Color, &color))
87 fprintf(stderr, "%s: can't parse color %s", progname, Color);
90 if (!XAllocColor(Flake.DisplayVar, Flake.XGWA.colormap, &color))
92 fprintf(stderr, "%s: can't allocate color %s", progname, Color);
99 * This is a great color matching algorithm that I got from
100 * a friend of mine on #vegans@irc.blitzed.org
101 * She wrote it in PHP and I ported it over to C
102 * her site is http://beautifulfreak.net/
105 FuzzyFlakesColorHelper(void)
107 unsigned int iR, iG, iB;
108 unsigned int iR0, iG0, iB0;
109 unsigned int iR1, iG1, iB1;
111 float Max = 0, Min = 0, Lig, Sat;
112 float Hue, Hue0, Hue1;
120 /* First convert from hex to dec */
121 /* while splitting up the RGB values */
122 if (!XParseColor(Flake.DisplayVar, Flake.XGWA.colormap,
123 Flake.Colors.Back, &color))
125 fprintf(stderr, "%s: can't parse color %s", progname,
130 iG = color.green >> 8;
131 iB = color.blue >> 8;
133 /* Convert from int to float */
138 /* convert from 0-255 to 0-1 */
143 /* work out the lightness */
144 if (fR >= fG && fR >= fB)
146 if (fG >= fR && fG >= fB)
148 if (fB >= fR && fB >= fG)
151 if (fR <= fG && fR <= fB)
153 if (fG <= fR && fG <= fB)
155 if (fB <= fR && fB <= fG)
158 Lig = (Max + Min) / 2;
160 /* work out the saturation */
166 Sat = (Max - Min) / (Max + Min);
168 Sat = (Max - Min) / (2 - Max - Min);
172 * if our satration is too low we won't be
173 * able to see any objects
180 /* work out the hue */
182 Hue = (fG - fB) / (Max - Min);
184 Hue = 2 + (fB - fR) / (Max - Min);
186 Hue = 4 + (fR - fG) / (Max - Min);
190 /* fine two equidistant hues */
198 /* convert the colors into hex codes */
200 f2 = Lig * (1 + Sat);
202 f2 = (Lig + Sat) - (Lig * Sat);
206 fR0 = (Hue0 + 1) / 3;
207 fR1 = (Hue1 + 1) / 3;
210 fB0 = (Hue0 - 1) / 3;
211 fB1 = (Hue1 - 1) / 3;
240 nR0 = f1 + (f2 - f1) * 6 * fR0;
241 else if (2 * fR0 < 1)
243 else if (3 * fR0 < 2)
244 nR0 = f1 + (f2 - f1) * (N2_3 - fR0) * 6;
249 nG0 = f1 + (f2 - f1) * 6 * fG0;
250 else if (2 * fG0 < 1)
252 else if (3 * fG0 < 2)
253 nG0 = f1 + (f2 - f1) * (N2_3 - fG0) * 6;
258 nB0 = f1 + (f2 - f1) * 6 * fB0;
259 else if (2 * fB0 < 1)
261 else if (3 * fB0 < 2)
262 nB0 = f1 + (f2 - f1) * (N2_3 - fB0) * 6;
267 nR1 = f1 + (f2 - f1) * 6 * fR1;
268 else if (2 * fR1 < 1)
270 else if (3 * fR1 < 2)
271 nR1 = f1 + (f2 - f1) * (N2_3 - fR1) * 6;
276 nG1 = f1 + (f2 - f1) * 6 * fG1;
277 else if (2 * fG1 < 1)
279 else if (3 * fG1 < 2)
280 nG1 = f1 + (f2 - f1) * (N2_3 - fG1) * 6;
285 nB1 = f1 + (f2 - f1) * 6 * fB1;
286 else if (2 * fB1 < 1)
288 else if (3 * fB1 < 2)
289 nB1 = f1 + (f2 - f1) * (N2_3 - fB1) * 6;
293 /* at last convert them to a hex string */
302 Flake.Colors.Fore = malloc(sizeof(unsigned char) * 8);
303 Flake.Colors.Bord = malloc(sizeof(unsigned char) * 8);
305 sprintf(Flake.Colors.Fore, "#%02X%02X%02X", iR0, iG0, iB0);
306 sprintf(Flake.Colors.Bord, "#%02X%02X%02X", iR1, iG1, iB1);
312 FuzzyFlakesInit(Display * dpy, Window window)
315 XWindowAttributes xgwa;
318 XGetWindowAttributes(dpy, window, &xgwa);
319 cmap = xgwa.colormap;
321 Flake.DB.b = Flake.DB.ba = Flake.DB.bb = 0;
322 Flake.DB.dbuf = get_boolean_resource("doubleBuffer", "Boolean");
327 XCreatePixmap(dpy, window, xgwa.width, xgwa.height, xgwa.depth);
329 XCreatePixmap(dpy, window, xgwa.width, xgwa.height, xgwa.depth);
330 Flake.DB.b = Flake.DB.ba;
337 Flake.DisplayVar = dpy;
338 Flake.WindowVar = window;
339 Flake.Arms = get_integer_resource("arms", "Integer");
340 Flake.Thickness = get_integer_resource("thickness", "Integer");
341 Flake.BorderThickness = get_integer_resource("bthickness", "Integer");
342 Flake.Radius = get_integer_resource("radius", "Integer");
344 Flake.Density = get_integer_resource("density", "Integer");
345 Flake.Layers = get_integer_resource("layers", "Integer");
346 Flake.FallingSpeed = get_integer_resource("fallingspeed", "Integer");
347 Flake.Delay = get_integer_resource("delay", "Integer");
348 if (Flake.RandomColors == True)
349 Flake.RandomColors = get_boolean_resource("randomColors", "Boolean");
354 if (!Flake.Colors.Back)
356 Flake.Colors.Back = get_string_resource("color", "Color");
357 if (!FuzzyFlakesColorResource(Flake.Colors.Back))
359 fprintf(stderr, " reverting to random\n");
360 Flake.RandomColors = True;
363 if (Flake.RandomColors)
365 if (Flake.Colors.Back)
366 free(Flake.Colors.Back);
367 Flake.Colors.Back = malloc(sizeof(unsigned char) * 8);
368 sprintf(Flake.Colors.Back, "#%X%X%X%X%X%X", random() % 16,
369 random() % 16, random() % 16, random() % 16, random() % 16,
374 * Here we establish our colormap based on what is in
377 if (FuzzyFlakesColorHelper())
379 fprintf(stderr, " reverting to random\n");
380 if (Flake.Colors.Back)
381 free(Flake.Colors.Back);
382 Flake.Colors.Back = malloc(sizeof(unsigned char) * 8);
383 sprintf(Flake.Colors.Back, "#%X%X%X%X%X%X", random() % 16,
384 random() % 16, random() % 16, random() % 16, random() % 16,
386 FuzzyFlakesColorHelper();
389 Flake.ForeColor = FuzzyFlakesColorResource(Flake.Colors.Fore);
390 Flake.BackColor = FuzzyFlakesColorResource(Flake.Colors.Back);
391 Flake.BordColor = FuzzyFlakesColorResource(Flake.Colors.Bord);
393 Flake.GCValues.foreground = Flake.ForeColor;
394 Flake.GCValues.background = Flake.BackColor;
395 Flake.RandomColors = False;
398 Flake.GCValues.line_width = Flake.Thickness;
399 Flake.GCValues.line_style = LineSolid;
400 Flake.GCValues.cap_style = CapProjecting;
401 Flake.GCValues.join_style = JoinMiter;
402 Flake.GCFlags |= (GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle);
405 XCreateGC(Flake.DisplayVar, Flake.WindowVar, Flake.GCFlags,
408 Flake.Density = Flake.XGWA.width / 200 * Flake.Density;
409 Flake.Flakes = malloc(sizeof(FlakeVariable **) * Flake.Layers);
410 for (i = 1; i <= Flake.Layers; i++)
412 Flake.Flakes[i - 1] = malloc(sizeof(FlakeVariable *) * Flake.Density);
413 for (j = 0; j < Flake.Density; j++)
415 Flake.Flakes[i - 1][j] = malloc(sizeof(FlakeVariable));
416 Flake.Flakes[i - 1][j]->XPos = random() % Flake.XGWA.width;
417 Flake.Flakes[i - 1][j]->YPos = random() % Flake.XGWA.height;
418 Flake.Flakes[i - 1][j]->Angle = random() % 360 * (M_PI / 180);
419 Flake.Flakes[i - 1][j]->Ticks = random() % 360;
420 Flake.Flakes[i - 1][j]->XOffset = random() % Flake.XGWA.height;
426 FuzzyFlakesFreeFlake(void)
430 for (i = 1; i <= Flake.Layers; i++)
432 for (j = 0; j < Flake.Density; j++)
434 free(Flake.Flakes[i - 1][j]);
436 free(Flake.Flakes[i - 1]);
439 XFreePixmap(Flake.DisplayVar, Flake.DB.bb);
440 XFreePixmap(Flake.DisplayVar, Flake.DB.ba);
444 FuzzyFlakesResizeTest(void)
446 XWindowAttributes xgwa;
448 XGetWindowAttributes(Flake.DisplayVar, Flake.WindowVar, &xgwa);
449 if (Flake.XGWA.width != xgwa.width || Flake.XGWA.height != xgwa.height)
451 FuzzyFlakesFreeFlake();
452 FuzzyFlakesInit(Flake.DisplayVar, Flake.WindowVar);
457 FuzzyFlakesMove(void)
461 for (i = 1; i <= Flake.Layers; i++)
463 for (j = 0; j < Flake.Density; j++)
465 FlakeVariable *FlakeVar;
467 FlakeVar = Flake.Flakes[i - 1][j];
470 FlakeVar->YPos + ((double)Flake.FallingSpeed) / 10 / i;
474 FlakeVar->Ticks * (M_PI / 180) * ((double)Flake.FallingSpeed /
475 10))) * 10 + FlakeVar->XPos;
477 FlakeVar->Angle + 0.005 * ((double)Flake.FallingSpeed / 10);
478 if (FlakeVar->YPos - Flake.Radius > Flake.XGWA.height)
481 FlakeVar->YPos = 0 - Flake.Radius;
488 FuzzyFlakesDrawFlake(int XPos, int YPos, double AngleOffset, int Layer)
491 double x, y, Angle, Radius;
493 /* calculate the shrink factor debending on which layer we are drawing atm */
494 Radius = (double)(Flake.Radius - Layer * 5);
495 /* draw the flake one arm at a time */
496 for (i = 1; i <= Flake.Arms; i++)
500 Diameter = (Flake.BorderThickness * 2 + Flake.Thickness) / Layer;
501 /* compute the angle of this arm of the flake */
502 Angle = ((2 * M_PI) / Flake.Arms) * i + AngleOffset;
503 /* calculate the x and y dispositions for this arm */
504 y = (int)(sin(Angle) * Radius);
505 x = (int)(cos(Angle) * Radius);
506 /* draw the base for the arm */
507 Flake.GCValues.line_width = Diameter;
508 XFreeGC(Flake.DisplayVar, Flake.GCVar);
510 XCreateGC(Flake.DisplayVar, Flake.DB.b, Flake.GCFlags,
512 XSetForeground(Flake.DisplayVar, Flake.GCVar, Flake.BordColor);
513 XDrawLine(Flake.DisplayVar, Flake.DB.b, Flake.GCVar, XPos, YPos,
516 /* draw the flake one arm at a time */
517 for (i = 1; i <= Flake.Arms; i++)
519 /* compute the angle of this arm of the flake */
520 Angle = ((2 * M_PI) / Flake.Arms) * i + AngleOffset;
521 /* calculate the x and y dispositions for this arm */
522 y = (int)(sin(Angle) * Radius);
523 x = (int)(cos(Angle) * Radius);
524 /* draw the inside of the arm */
525 Flake.GCValues.line_width = Flake.Thickness / Layer;
526 XFreeGC(Flake.DisplayVar, Flake.GCVar);
528 XCreateGC(Flake.DisplayVar, Flake.DB.b, Flake.GCFlags,
530 XSetForeground(Flake.DisplayVar, Flake.GCVar, Flake.ForeColor);
531 XDrawLine(Flake.DisplayVar, Flake.DB.b, Flake.GCVar, XPos, YPos,
537 FuzzyFlakes(Display * dpy, Window window)
542 XSetForeground(Flake.DisplayVar, Flake.GCVar, Flake.BackColor);
543 XFillRectangle(Flake.DisplayVar, Flake.DB.b, Flake.GCVar, 0, 0,
544 Flake.XGWA.width, Flake.XGWA.height);
545 for (i = Flake.Layers; i >= 1; i--)
547 for (j = 0; j < Flake.Density; j++)
549 FuzzyFlakesDrawFlake(Flake.Flakes[i - 1][j]->TrueX,
550 Flake.Flakes[i - 1][j]->YPos,
551 Flake.Flakes[i - 1][j]->Angle, i);
557 char *progclass = "FuzzyFlakes";
568 "*doubleBuffer: True",
569 "*randomColors: False",
573 XrmOptionDescRec options[] = {
575 "-color", ".color", XrmoptionSepArg, 0},
577 "-arms", ".arms", XrmoptionSepArg, 0},
579 "-thickness", ".thickness", XrmoptionSepArg, 0},
581 "-bthickness", ".bthickness", XrmoptionSepArg, 0},
583 "-radius", ".radius", XrmoptionSepArg, 0},
585 "-layers", ".layers", XrmoptionSepArg, 0},
587 "-density", ".density", XrmoptionSepArg, 0},
589 "-speed", ".fallingspeed", XrmoptionSepArg, 0},
591 "-delay", ".delay", XrmoptionSepArg, 0},
593 "-db", ".doubleBuffer", XrmoptionNoArg, "True"},
595 "-no-db", ".doubleBuffer", XrmoptionNoArg, "False"},
597 "-random-colors", ".randomColors", XrmoptionNoArg, "True"},
603 screenhack(Display * dpy, Window window)
605 register int tick = 0;
607 /* This is needed even if it is going to be set to false */
608 Flake.RandomColors = True;
610 /* set up our colors amoung many other things */
611 FuzzyFlakesInit(dpy, window);
615 /* Test every 50 ticks for a screen resize */
619 FuzzyFlakesResizeTest();
622 FuzzyFlakes(dpy, Flake.DB.b);
625 XCopyArea(Flake.DisplayVar, Flake.DB.b, Flake.WindowVar,
626 Flake.GCVar, 0, 0, Flake.XGWA.width, Flake.XGWA.height,
629 (Flake.DB.b == Flake.DB.ba ? Flake.DB.bb : Flake.DB.ba);
631 screenhack_handle_events(dpy);