Back to index

kdeartwork  4.3.2
Defines | Functions
xs_colors.c File Reference
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xresource.h>
#include "xs_visual.h"
#include "xs_yarandom.h"
#include "xs_hsv.h"
#include "xs_colors.h"

Go to the source code of this file.

Defines

#define MAXPOINTS   50 /* yeah, so I'm lazy */

Functions

void free_colors (Display *dpy, Colormap cmap, XColor *colors, int ncolors)
void allocate_writable_colors (Display *dpy, Colormap cmap, unsigned long *pixels, int *ncolorsP)
void make_color_ramp (Display *dpy, Colormap cmap, int h1, double s1, double v1, int h2, double s2, double v2, XColor *colors, int *ncolorsP, Bool closed_p, Bool allocate_p, Bool writable_p)
static void make_color_path (Display *dpy, Colormap cmap, int npoints, int *h, double *s, double *v, XColor *colors, int *ncolorsP, Bool allocate_p, Bool writable_p)
void make_color_loop (Display *dpy, Colormap cmap, int h0, double s0, double v0, int h1, double s1, double v1, int h2, double s2, double v2, XColor *colors, int *ncolorsP, Bool allocate_p, Bool writable_p)
static void complain (int wanted_colors, int got_colors, Bool wanted_writable, Bool got_writable)
void make_smooth_colormap (Display *dpy, Visual *visual, Colormap cmap, XColor *colors, int *ncolorsP, Bool allocate_p, Bool *writable_pP, Bool verbose_p)
void make_uniform_colormap (Display *dpy, Visual *visual, Colormap cmap, XColor *colors, int *ncolorsP, Bool allocate_p, Bool *writable_pP, Bool verbose_p)
void make_random_colormap (Display *dpy, Visual *visual, Colormap cmap, XColor *colors, int *ncolorsP, Bool bright_p, Bool allocate_p, Bool *writable_pP, Bool verbose_p)
void rotate_colors (Display *dpy, Colormap cmap, XColor *colors, int ncolors, int distance)

Define Documentation

#define MAXPOINTS   50 /* yeah, so I'm lazy */

Definition at line 184 of file xs_colors.c.


Function Documentation

void allocate_writable_colors ( Display *  dpy,
Colormap  cmap,
unsigned long *  pixels,
int *  ncolorsP 
)

Definition at line 49 of file xs_colors.c.

{
  int desired = *ncolorsP;
  int got = 0;
  int requested = desired;
  unsigned long *new_pixels = pixels;

  *ncolorsP = 0;
  while (got < desired
        && requested > 0)
    {
      if (desired - got < requested)
       requested = desired - got;

      if (XAllocColorCells (dpy, cmap, False, 0, 0, new_pixels, requested))
       {
         /* Got all the pixels we asked for. */
         new_pixels += requested;
         got += requested;
       }
      else
       {
         /* We didn't get all/any of the pixels we asked for.  This time, ask
            for half as many.  (If we do get all that we ask for, we ask for
            the same number again next time, so we only do O(log(n)) server
            roundtrips.)
         */
         requested = requested / 2;
       }
    }
  *ncolorsP += got;
}

Here is the caller graph for this function:

static void complain ( int  wanted_colors,
int  got_colors,
Bool  wanted_writable,
Bool  got_writable 
) [static]

Definition at line 440 of file xs_colors.c.

{
  if (wanted_writable && !got_writable)
    fprintf(stderr,
           "%s: wanted %d writable colors; got %d read-only colors.\n",
           "colors (kscreensaver)", wanted_colors, got_colors);

  else if (wanted_colors > (got_colors + 10))
    /* don't bother complaining if we're within ten pixels. */
    fprintf(stderr, "%s: wanted %d%s colors; got %d.\n",
           "colors (kscreensaver)", wanted_colors, (got_writable ? " writable" : ""),
           got_colors);
}

Here is the caller graph for this function:

void free_colors ( Display *  dpy,
Colormap  cmap,
XColor *  colors,
int  ncolors 
)

Definition at line 33 of file xs_colors.c.

{
  int i;
  if (ncolors > 0)
    {
      unsigned long *pixels = (unsigned long *)
       malloc(sizeof(*pixels) * ncolors);
      for (i = 0; i < ncolors; i++)
       pixels[i] = colors[i].pixel;
      XFreeColors (dpy, cmap, pixels, ncolors, 0L);
      free(pixels);
    }
}

Here is the caller graph for this function:

void make_color_loop ( Display *  dpy,
Colormap  cmap,
int  h0,
double  s0,
double  v0,
int  h1,
double  s1,
double  v1,
int  h2,
double  s2,
double  v2,
XColor *  colors,
int *  ncolorsP,
Bool  allocate_p,
Bool  writable_p 
)

Definition at line 419 of file xs_colors.c.

{
  int h[3];
  double s[3], v[3];
  h[0] = h0; h[1] = h1; h[2] = h2;
  s[0] = s0; s[1] = s1; s[2] = s2;
  v[0] = v0; v[1] = v1; v[2] = v2;
  make_color_path(dpy, cmap,
                3, h, s, v,
                colors, ncolorsP,
                allocate_p, writable_p);
}

Here is the call graph for this function:

static void make_color_path ( Display *  dpy,
Colormap  cmap,
int  npoints,
int *  h,
double *  s,
double *  v,
XColor *  colors,
int *  ncolorsP,
Bool  allocate_p,
Bool  writable_p 
) [static]

Definition at line 188 of file xs_colors.c.

{
  int i, j, k;
  int total_ncolors = *ncolorsP;

  int ncolors[MAXPOINTS];  /* number of pixels per edge */
  double dh[MAXPOINTS];    /* distance between pixels, per edge (0 - 360.0) */
  double ds[MAXPOINTS];    /* distance between pixels, per edge (0 - 1.0) */
  double dv[MAXPOINTS];    /* distance between pixels, per edge (0 - 1.0) */

  if (npoints == 0)
    {
      *ncolorsP = 0;
      return;
    }
  else if (npoints == 2)    /* using make_color_ramp() will be faster */
    {
      make_color_ramp (dpy, cmap,
                     h[0], s[0], v[0], h[1], s[1], v[1],
                     colors, ncolorsP,
                     True,  /* closed_p */
                     allocate_p, writable_p);
      return;
    }
  else if (npoints >= MAXPOINTS)
    {
      npoints = MAXPOINTS-1;
    }

 AGAIN:

  {
    double DH[MAXPOINTS];   /* Distance between H values in the shortest
                               direction around the circle, that is, the
                               distance between 10 and 350 is 20.
                               (Range is 0 - 360.0.)
                            */
    double edge[MAXPOINTS]; /* lengths of edges in unit HSV space. */
    double ratio[MAXPOINTS];       /* proportions of the edges (total 1.0) */
    double circum = 0;
    double one_point_oh = 0;       /* (debug) */

    for (i = 0; i < npoints; i++)
      {
       int j = (i+1) % npoints;
       double d = ((double) (h[i] - h[j])) / 360;
       if (d < 0) d = -d;
       if (d > 0.5) d = 0.5 - (d - 0.5);
       DH[i] = d;
      }

    for (i = 0; i < npoints; i++)
      {
       int j = (i+1) % npoints;
       edge[i] = sqrt((DH[i] * DH[j]) +
                     ((s[j] - s[i]) * (s[j] - s[i])) +
                     ((v[j] - v[i]) * (v[j] - v[i])));
       circum += edge[i];
      }

#ifdef DEBUG
    fprintf(stderr, "\ncolors:");
    for (i=0; i < npoints; i++)
      fprintf(stderr, " (%d, %.3f, %.3f)", h[i], s[i], v[i]);
    fprintf(stderr, "\nlengths:");
    for (i=0; i < npoints; i++)
      fprintf(stderr, " %.3f", edge[i]);
#endif /* DEBUG */

    if (circum < 0.0001)
      goto FAIL;

    for (i = 0; i < npoints; i++)
      {
       ratio[i] = edge[i] / circum;
       one_point_oh += ratio[i];
      }

#ifdef DEBUG
    fprintf(stderr, "\nratios:");
    for (i=0; i < npoints; i++)
      fprintf(stderr, " %.3f", ratio[i]);
#endif /* DEBUG */

    if (one_point_oh < 0.99999 || one_point_oh > 1.00001)
      abort();

    /* space the colors evenly along the circumference -- that means that the
       number of pixels on a edge is proportional to the length of that edge
       (relative to the lengths of the other edges.)
     */
    for (i = 0; i < npoints; i++)
      ncolors[i] = total_ncolors * ratio[i];


#ifdef DEBUG
    fprintf(stderr, "\npixels:");
    for (i=0; i < npoints; i++)
      fprintf(stderr, " %d", ncolors[i]);
    fprintf(stderr, "  (%d)\n", total_ncolors);
#endif /* DEBUG */

    for (i = 0; i < npoints; i++)
      {
       int j = (i+1) % npoints;

       if (ncolors[i] > 0)
         {
           dh[i] = 360 * (DH[i] / ncolors[i]);
           ds[i] = (s[j] - s[i]) / ncolors[i];
           dv[i] = (v[j] - v[i]) / ncolors[i];
         }
      }
  }

  memset (colors, 0, (*ncolorsP) * sizeof(*colors));

  k = 0;
  for (i = 0; i < npoints; i++)
    {
      int distance, direction;
      distance = h[(i+1) % npoints] - h[i];
      direction = (distance >= 0 ? -1 : 1);

      if (distance > 180)
       distance = 180 - (distance - 180);
      else if (distance < -180)
       distance = -(180 - ((-distance) - 180));
      else
       direction = -direction;

#ifdef DEBUG
      fprintf (stderr, "point %d: %3d %.2f %.2f\n",
              i, h[i], s[i], v[i]);
      fprintf(stderr, "  h[i]=%d  dh[i]=%.2f  ncolors[i]=%d\n",
             h[i], dh[i], ncolors[i]);
#endif /* DEBUG */
      for (j = 0; j < ncolors[i]; j++, k++)
       {
         double hh = (h[i] + (j * dh[i] * direction));
         if (hh < 0) hh += 360;
         else if (hh > 360) hh -= 0;
         colors[k].flags = DoRed|DoGreen|DoBlue;
         hsv_to_rgb ((int)
                    hh,
                    (s[i] + (j * ds[i])),
                    (v[i] + (j * dv[i])),
                    &colors[k].red, &colors[k].green, &colors[k].blue);
#ifdef DEBUG
         fprintf (stderr, "point %d+%d: %.2f %.2f %.2f  %04X %04X %04X\n",
                 i, j,
                 hh,
                 (s[i] + (j * ds[i])),
                 (v[i] + (j * dv[i])),
                 colors[k].red, colors[k].green, colors[k].blue);
#endif /* DEBUG */
       }
    }

  /* Floating-point round-off can make us decide to use fewer colors. */
  if (k < *ncolorsP)
    {
      *ncolorsP = k;
      if (k <= 0)
       return;
    }

  if (!allocate_p)
    return;

  if (writable_p)
    {
      unsigned long *pixels = (unsigned long *)
       malloc(sizeof(*pixels) * ((*ncolorsP) + 1));

      /* allocate_writable_colors() won't do here, because we need exactly this
        number of cells, or the color sequence we've chosen won't fit. */
      if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
       {
         free(pixels);
         goto FAIL;
       }

      for (i = 0; i < *ncolorsP; i++)
       colors[i].pixel = pixels[i];
      free (pixels);

      XStoreColors (dpy, cmap, colors, *ncolorsP);
    }
  else
    {
      for (i = 0; i < *ncolorsP; i++)
       {
         XColor color;
         color = colors[i];
         if (XAllocColor (dpy, cmap, &color))
           {
             colors[i].pixel = color.pixel;
           }
         else
           {
             free_colors (dpy, cmap, colors, i);
             goto FAIL;
           }
       }
    }

  return;

 FAIL:
  /* we weren't able to allocate all the colors we wanted;
     decrease the requested number and try again.
   */
  total_ncolors = (total_ncolors > 170 ? total_ncolors - 20 :
                 total_ncolors > 100 ? total_ncolors - 10 :
                 total_ncolors >  75 ? total_ncolors -  5 :
                 total_ncolors >  25 ? total_ncolors -  3 :
                 total_ncolors >  10 ? total_ncolors -  2 :
                 total_ncolors >   2 ? total_ncolors -  1 :
                 0);
  *ncolorsP = total_ncolors;
  if (total_ncolors > 0)
    goto AGAIN;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void make_color_ramp ( Display *  dpy,
Colormap  cmap,
int  h1,
double  s1,
double  v1,
int  h2,
double  s2,
double  v2,
XColor *  colors,
int *  ncolorsP,
Bool  closed_p,
Bool  allocate_p,
Bool  writable_p 
)

Definition at line 86 of file xs_colors.c.

{
  int i;
  int ncolors = *ncolorsP;
  double dh, ds, dv;        /* deltas */

 AGAIN:

  memset (colors, 0, (*ncolorsP) * sizeof(*colors));

  if (closed_p)
    ncolors = (ncolors / 2) + 1;

  /* Note: unlike other routines in this module, this function assumes that
     if h1 and h2 are more than 180 degrees apart, then the desired direction
     is always from h1 to h2 (rather than the shorter path.)  make_uniform
     depends on this.
   */
  dh = ((double)h2 - (double)h1) / ncolors;
  ds = (s2 - s1) / ncolors;
  dv = (v2 - v1) / ncolors;

  for (i = 0; i < ncolors; i++)
    {
      colors[i].flags = DoRed|DoGreen|DoBlue;
      hsv_to_rgb ((int) (h1 + (i*dh)), (s1 + (i*ds)), (v1 + (i*dv)),
                &colors[i].red, &colors[i].green, &colors[i].blue);
    }

  if (closed_p)
    for (i = ncolors; i < *ncolorsP; i++)
      colors[i] = colors[(*ncolorsP)-i];

  if (!allocate_p)
    return;

  if (writable_p)
    {
      unsigned long *pixels = (unsigned long *)
       malloc(sizeof(*pixels) * ((*ncolorsP) + 1));

      /* allocate_writable_colors() won't do here, because we need exactly this
        number of cells, or the color sequence we've chosen won't fit. */
      if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
       {
         free(pixels);
         goto FAIL;
       }

      for (i = 0; i < *ncolorsP; i++)
       colors[i].pixel = pixels[i];
      free (pixels);

      XStoreColors (dpy, cmap, colors, *ncolorsP);
    }
  else
    {
      for (i = 0; i < *ncolorsP; i++)
       {
         XColor color;
         color = colors[i];
         if (XAllocColor (dpy, cmap, &color))
           {
             colors[i].pixel = color.pixel;
           }
         else
           {
             free_colors (dpy, cmap, colors, i);
             goto FAIL;
           }
       }
    }

  return;

 FAIL:
  /* we weren't able to allocate all the colors we wanted;
     decrease the requested number and try again.
   */
  ncolors = (ncolors > 170 ? ncolors - 20 :
            ncolors > 100 ? ncolors - 10 :
            ncolors >  75 ? ncolors -  5 :
            ncolors >  25 ? ncolors -  3 :
            ncolors >  10 ? ncolors -  2 :
            ncolors >   2 ? ncolors -  1 :
            0);
  *ncolorsP = ncolors;
  if (ncolors > 0)
    goto AGAIN;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void make_random_colormap ( Display *  dpy,
Visual *  visual,
Colormap  cmap,
XColor *  colors,
int *  ncolorsP,
Bool  bright_p,
Bool  allocate_p,
Bool *  writable_pP,
Bool  verbose_p 
)

Definition at line 590 of file xs_colors.c.

{
  Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
  int ncolors = *ncolorsP;
  int i;
  Screen *screen = DefaultScreenOfDisplay(dpy); /* #### WRONG! */

  if (*ncolorsP <= 0) return;

  /* If this visual doesn't support writable cells, don't bother trying. */
  if (wanted_writable && !has_writable_cells(screen, visual))
    *writable_pP = False;

  for (i = 0; i < ncolors; i++)
    {
      colors[i].flags = DoRed|DoGreen|DoBlue;
      if (bright_p)
       {
         int H = random() % 360;                    /* range 0-360    */
         double S = ((double) (random()%70) + 30)/100.0;  /* range 30%-100% */
         double V = ((double) (random()%34) + 66)/100.0;  /* range 66%-100% */
         hsv_to_rgb (H, S, V,
                    &colors[i].red, &colors[i].green, &colors[i].blue);
       }
      else
       {
         colors[i].red   = random() % 0xFFFF;
         colors[i].green = random() % 0xFFFF;
         colors[i].blue  = random() % 0xFFFF;
       }
    }

  if (!allocate_p)
    return;

 RETRY_NON_WRITABLE:
  if (writable_pP && *writable_pP)
    {
      unsigned long *pixels = (unsigned long *)
       malloc(sizeof(*pixels) * (ncolors + 1));

      allocate_writable_colors (dpy, cmap, pixels, &ncolors);
      if (ncolors > 0)
       for (i = 0; i < ncolors; i++)
         colors[i].pixel = pixels[i];
      free (pixels);
      if (ncolors > 0)
       XStoreColors (dpy, cmap, colors, ncolors);
    }
  else
    {
      for (i = 0; i < ncolors; i++)
       {
         XColor color;
         color = colors[i];
         if (!XAllocColor (dpy, cmap, &color))
           break;
         colors[i].pixel = color.pixel;
       }
      ncolors = i;
    }

  /* If we tried for writable cells and got none, try for non-writable. */
  if (allocate_p && ncolors == 0 && writable_pP && *writable_pP)
    {
      ncolors = *ncolorsP;
      *writable_pP = False;
      goto RETRY_NON_WRITABLE;
    }

  if (verbose_p)
    complain(*ncolorsP, ncolors, wanted_writable,
            wanted_writable && *writable_pP);

  *ncolorsP = ncolors;
}

Here is the call graph for this function:

void make_smooth_colormap ( Display *  dpy,
Visual *  visual,
Colormap  cmap,
XColor *  colors,
int *  ncolorsP,
Bool  allocate_p,
Bool *  writable_pP,
Bool  verbose_p 
)

Definition at line 457 of file xs_colors.c.

{
  int npoints;
  int ncolors = *ncolorsP;
  Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
  int i;
  int h[MAXPOINTS];
  double s[MAXPOINTS];
  double v[MAXPOINTS];
  double total_s = 0;
  double total_v = 0;
  Screen *screen = DefaultScreenOfDisplay(dpy); /* #### WRONG! */

  if (*ncolorsP <= 0) return;

  {
    int n = random() % 20;
    if      (n <= 5)  npoints = 2; /* 30% of the time */
    else if (n <= 15) npoints = 3; /* 50% of the time */
    else if (n <= 18) npoints = 4; /* 15% of the time */
    else             npoints = 5;  /*  5% of the time */
  }

 REPICK_ALL_COLORS:
  for (i = 0; i < npoints; i++)
    {
    REPICK_THIS_COLOR:
      h[i] = random() % 360;
      s[i] = frand(1.0);
      v[i] = frand(0.8) + 0.2;

      /* Make sure that no two adjascent colors are *too* close together.
        If they are, try again.
       */
      if (i > 0)
       {
         int j = (i+1 == npoints) ? 0 : (i-1);
         double hi = ((double) h[i]) / 360;
         double hj = ((double) h[j]) / 360;
         double dh = hj - hi;
         double distance;
         if (dh < 0) dh = -dh;
         if (dh > 0.5) dh = 0.5 - (dh - 0.5);
         distance = sqrt ((dh * dh) +
                        ((s[j] - s[i]) * (s[j] - s[i])) +
                        ((v[j] - v[i]) * (v[j] - v[i])));
         if (distance < 0.2)
           goto REPICK_THIS_COLOR;
       }
      total_s += s[i];
      total_v += v[i];
    }

  /* If the average saturation or intensity are too low, repick the colors,
     so that we don't end up with a black-and-white or too-dark map.
   */
  if (total_s / npoints < 0.2)
    goto REPICK_ALL_COLORS;
  if (total_v / npoints < 0.3)
    goto REPICK_ALL_COLORS;

  /* If this visual doesn't support writable cells, don't bother trying.
   */
  if (wanted_writable && !has_writable_cells(screen, visual))
    *writable_pP = False;

 RETRY_NON_WRITABLE:
  make_color_path (dpy, cmap, npoints, h, s, v, colors, &ncolors,
                 allocate_p, (writable_pP && *writable_pP));

  /* If we tried for writable cells and got none, try for non-writable. */
  if (allocate_p && *ncolorsP == 0 && *writable_pP)
    {
      *writable_pP = False;
      goto RETRY_NON_WRITABLE;
    }

  if (verbose_p)
    complain(*ncolorsP, ncolors, wanted_writable,
            wanted_writable && *writable_pP);

  *ncolorsP = ncolors;
}

Here is the call graph for this function:

void make_uniform_colormap ( Display *  dpy,
Visual *  visual,
Colormap  cmap,
XColor *  colors,
int *  ncolorsP,
Bool  allocate_p,
Bool *  writable_pP,
Bool  verbose_p 
)

Definition at line 547 of file xs_colors.c.

{
  int ncolors = *ncolorsP;
  Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
  Screen *screen = DefaultScreenOfDisplay(dpy); /* #### WRONG! */

  double S = ((double) (random() % 34) + 66) / 100.0;   /* range 66%-100% */
  double V = ((double) (random() % 34) + 66) / 100.0;   /* range 66%-100% */

  if (*ncolorsP <= 0) return;

  /* If this visual doesn't support writable cells, don't bother trying. */
  if (wanted_writable && !has_writable_cells(screen, visual))
    *writable_pP = False;

 RETRY_NON_WRITABLE:
  make_color_ramp(dpy, cmap,
                0,   S, V,
                359, S, V,
                colors, &ncolors,
                False, True, wanted_writable);

  /* If we tried for writable cells and got none, try for non-writable. */
  if (allocate_p && *ncolorsP == 0 && writable_pP && *writable_pP)
    {
      ncolors = *ncolorsP;
      *writable_pP = False;
      goto RETRY_NON_WRITABLE;
    }

  if (verbose_p)
    complain(*ncolorsP, ncolors, wanted_writable,
            wanted_writable && *writable_pP);

  *ncolorsP = ncolors;
}

Here is the call graph for this function:

void rotate_colors ( Display *  dpy,
Colormap  cmap,
XColor *  colors,
int  ncolors,
int  distance 
)

Definition at line 674 of file xs_colors.c.

{
  int i;
  XColor *colors2 = (XColor *) malloc(sizeof(*colors2) * ncolors);
  if (ncolors < 2) return;
  distance = distance % ncolors;
  for (i = 0; i < ncolors; i++)
    {
      int j = i - distance;
      if (j >= ncolors) j -= ncolors;
      if (j < 0) j += ncolors;
      colors2[i] = colors[j];
      colors2[i].pixel = colors[i].pixel;
    }
  XStoreColors (dpy, cmap, colors2, ncolors);
  XFlush(dpy);
  memcpy(colors, colors2, sizeof(*colors) * ncolors);
  free(colors2);
}