Subject: vector buttons

From: Johannes Gajdosik <[email-masked]>
Date: Wed, 20 Mar 2002 20:49:18 +0100

Dear fvwm developers,

I am using fvwm2 since a couple of months and I am very pleased with it.
I liked the vector buttons very much and I was a little sad
because a vector button can only have 31 lines and because
these lines must always be connected to one another.
Therefore I would like to propose a new fwwm-feature.

This is the first open source project that I want to contribute,
so please be patient with me.
It would be a great honor if this feature could be introduced
in one of the next versions.
I am using it in version 2.4.6 and it works fine.

Yours,
Johannes Gajdosik

------------------------------------------------------

Feature description:

the man-page says:

> ...,num  is  a  number  of
> point  specifications  of  the form XxY@C.
> ...  C specifies a line color
> (0 - the shadow color, 1 - the highlight color, 2 -
> the  background  color,  3 - the foreground color).
> ... You can use up to 32 points in a line pattern.

The new feature is:
  1) You can use up to 1000 (or more?) points in a line pattern.
  2) special color C=-1: no line is drawn.
     This is different from color C=2, because a line of color C=2
     makes that all pixels of this line get the background color
     and so are erased.

The implementation affects 5 files.

-----------------------------------------------------

1) the man page:
The new text should be:
  ...  C specifies a line color
  (0 - the shadow color, 1 - the highlight color,
  2 - the  background  color,  3 - the foreground color,
  -1 - special meaning: this line is not drawn).
  ... You can use up to 1000 points in a line pattern.

------------------------------------------------------

2) screen.h
Instead of

>    struct vector_coords
>    {
>      int num;
>      int *x;
>      int *y;
>      unsigned long line_style;
>      unsigned long use_fgbg;
>    } vector;

I propose

     struct vector_coords
     {
       int num;
       struct vector_vertex {
         unsigned char x;
         unsigned char y;
         unsigned short color;
       } *vertices;
       unsigned long use_fgbg;
     } vector;

Please observe that in the old code every point needs 8 bytes,
in the new code only 4 bytes. Furthermore the color is not any more 
stored
in the bits of two unsigned long variables(line_style,use_fgbg),
but instead in just on variable(color), so the code becomes more 
readable.
The variable use_fgbg remains just because of an optimization when
drawing the button.

----------------------------------------------------------

3) fvwm.c

The functions LoadDefaultLeftButton and LoadDefaultRightButton
need to be adapted:

for example, instead of

>     v->line_style = 0;
>     v->x = (int *) safemalloc (sizeof(int) * v->num);
>     v->y = (int *) safemalloc (sizeof(int) * v->num);
>     v->x[0] = 22;
>     v->y[0] = 39;
>     v->line_style |= (1 << 0);
>     v->x[1] = 78;
>     v->y[1] = 39;
>     v->line_style |= (1 << 1);
>     v->x[2] = 78;
>     v->y[2] = 61;
>     v->x[3] = 22;
>     v->y[3] = 61;
>     v->x[4] = 22;
>     v->y[4] = 39;
>     v->line_style |= (1 << 4);

the code must be

      v->vertices = (struct vector_vertex *)
                    safemalloc (sizeof(struct vector_vertex) * v->num);
      v->vertices[0].x = 22;
      v->vertices[0].y = 39;
      v->vertices[0].color = 1;
      v->vertices[1].x = 78;
      v->vertices[1].y = 39;
      v->vertices[1].color = 1;
      v->vertices[2].x = 78;
      v->vertices[2].y = 61;
      v->vertices[2].color = 0;
      v->vertices[3].x = 22;
      v->vertices[3].y = 61;
      v->vertices[3].color = 0;
      v->vertices[4].x = 22;
      v->vertices[4].y = 39;
      v->vertices[4].color = 1;
      v->use_fgbg = 0;

------------------------------------------------

4) builtins.c

Instead of line 1423:

>     if (df->u.vector.x)
>       free (df->u.vector.x);
>     if (df->u.vector.y)
>       free (df->u.vector.y);

it must be

      if (df->u.vector.vertices)
        free (df->u.vector.vertices);

Instead of line 1515:

>    else if (strncasecmp(style,"Vector",6)==0 ||
>             (strlen(style)<=2 && isdigit(*style)))
>     {
>      /* normal coordinate list button style */
>      int i, num_coords, num, line_style;
>      struct vector_coords *vc = &df->u.vector;
> 
>      /* get number of points */
>      if (strncasecmp(style,"Vector",6)==0)
>      {
>        num = sscanf(s,"%d%n",&num_coords,&offset);
>        s += offset;
>      } else
>        num = sscanf(style,"%d",&num_coords);
> 
>      if((num != 1)||(num_coords>32)||(num_coords<2))
>      {
>        if (verbose)
>        {
>          fvwm_msg(
>            ERR,"ReadDecorFace", "Bad button style (2) in line: 
> %s",action);
>        }
>        return False;
>      }
> 
>      vc->num = num_coords;
>      vc->line_style = 0;
>      vc->use_fgbg = 0;
>      vc->x = (int *) safemalloc (sizeof (int) * num_coords);
>      vc->y = (int *) safemalloc (sizeof (int) * num_coords);
> 
> 
>      /* get the points */
>      for(i = 0; i < vc->num; ++i)
>      {
>        /* X x Y @ line_style */
>        num = sscanf(s,"%dx%d@%d%n",&vc->x[i],&vc->y[i],
>                     &line_style, &offset);
>        if(num != 3)
>        {
>          if (verbose)
>          {
>            fvwm_msg(
>              ERR, "ReadDecorFace", "Bad button style (3) in line %s", 
> action);
>          }
>          free(vc->x);
>          free(vc->y);
>          vc->x = NULL;
>          vc->y = NULL;
>          return False;
>        }
>        if (line_style % 2)
>        {
>          vc->line_style |= (1 << i);
>        }
>        if (line_style >= 2)
>        {
>          vc->use_fgbg |= (1 << i);
>        }
>        s += offset;
>      }
>      memset(&df->style, 0, sizeof(df->style));
>      DFS_FACE_TYPE(df->style) = VectorButton;
>    }

I propose

     else if (strncasecmp(style,"Vector",6)==0 ||
              (strlen(style)<=2 && isdigit(*style)))
     {
       /* normal coordinate list button style */
       int i, num_coords, num, x, y, line_style;
       struct vector_coords *vc = &df->u.vector;

       /* get number of points */
       if (strncasecmp(style,"Vector",6)==0)
       {
         num = sscanf(s,"%d%n",&num_coords,&offset);
         s += offset;
       } else
         num = sscanf(style,"%d",&num_coords);

       if((num != 1)||(num_coords>1000)||(num_coords<2))
       {
         if (verbose)
         {
           fvwm_msg(
             ERR,"ReadDecorFace", "Bad button style (2) in line: 
%s",action);
         }
         return False;
       }

       vc->num = num_coords;
       vc->use_fgbg = 0;
       vc->vertices = (struct vector_vertex *)
                      safemalloc (sizeof(struct vector_vertex) * 
num_coords);

       /* get the points */
       for(i = 0; i < vc->num; ++i)
       {
         /* X x Y @ line_style */
         num = sscanf(s,"%dx%d@%d%n", &x, &y, &line_style, &offset);
         vc->vertices[i].x = x;
         vc->vertices[i].y = y;
         vc->vertices[i].color = line_style;
         if(num != 3)
         {
           if (verbose)
           {
             fvwm_msg(
               ERR, "ReadDecorFace", "Bad button style (3) in line %s", 
action);
           }
           free(vc->vertices);
           vc->vertices = NULL;
                       vc->num = 0;
           return False;
         }
         if (line_style >= 2 && line_style < 4)
         {
           vc->use_fgbg = 1;
         }
         s += offset;
       }
       memset(&df->style, 0, sizeof(df->style));
       DFS_FACE_TYPE(df->style) = VectorButton;
     }

----------------------------------------------------

5) borders.c

Instead of

> static void DrawLinePattern(
>  Window win, GC ReliefGC, GC ShadowGC, Pixel fore_color, Pixel 
> back_color,
>  struct vector_coords *coords, int w, int h)
> {
>  int i;
> 
>  /* It is rare, so evaluate this only when needed */
>  GC fore_GC = NULL, back_GC = NULL;
>  if (coords->use_fgbg)
>  {
>    Globalgcv.foreground = fore_color;
>    Globalgcm = GCForeground;
>    XChangeGC(dpy, Scr.ScratchGC3, Globalgcm, &Globalgcv);
>    fore_GC = Scr.ScratchGC3;
>    Globalgcv.foreground = back_color;
>    XChangeGC(dpy, Scr.ScratchGC4, Globalgcm, &Globalgcv);
>    back_GC = Scr.ScratchGC4;
>  }
> 
>  for (i = 1; i < coords->num; ++i)
>  {
>      XDrawLine(dpy,win,
>                (coords->use_fgbg & (1 << i))
>                  ? (coords->line_style & (1 << i)) ? fore_GC : back_GC
>                  : (coords->line_style & (1 << i)) ? ReliefGC : 
> ShadowGC,
>                w * coords->x[i-1]/100,
>                h * coords->y[i-1]/100,
>                w * coords->x[i]/100,
>                h * coords->y[i]/100);
>  }
> }

I propose

static void DrawLinePattern(
   Window win, GC ReliefGC, GC ShadowGC, Pixel fore_color, Pixel 
back_color,
   struct vector_coords *coords, int w, int h)
{
   int i, prev_x, prev_y;
   GC gcs[4];
   gcs[0] = ShadowGC;
   gcs[1] = ReliefGC;
   gcs[2] = NULL;
   gcs[3] = NULL;
     /* It is rare, so evaluate this only when needed */
   if (coords->use_fgbg)
   {
     Globalgcv.foreground = fore_color;
     Globalgcm = GCForeground;
     XChangeGC(dpy, Scr.ScratchGC3, Globalgcm, &Globalgcv);
     gcs[3] = Scr.ScratchGC3;
     Globalgcv.foreground = back_color;
     XChangeGC(dpy, Scr.ScratchGC4, Globalgcm, &Globalgcv);
     gcs[2] = Scr.ScratchGC4;
   }
     /* safety check */
   if (coords->num <= 0) return;
     prev_x = w * coords->vertices->x/100;
   prev_y = h * coords->vertices->y/100;

   for (i = 1; i < coords->num; ++i)
   {
       struct vector_vertex *v = coords->vertices + i;
       int x = w * v->x/100;
       int y = h * v->y/100;
       if (v->color < 4) 
XDrawLine(dpy,win,gcs[v->color],prev_x,prev_y,x,y);
       prev_x = x;
       prev_y = y;
   }
}

Please notice that the newer version should be slightly faster
than the old one.

---

From: Dominik Vogt <[email-masked]>
Date: Wed, 20 Mar 2002 23:46:00 +0100

> I am using it in version 2.4.6 and it works fine.

Well, I see no real reason why the number of lines is hard coded
to a maximum of 32.  It can easily be changed.  I have comitted a
patch to the development branch.

If you want to submit fvwm patches, please make sure you base them
on the latest development code or at least the latest snapshot.
Also, please use the diff program to generate patches that can be
applied with the "patch" program.  Just copy all the files to a
file named old_name.orig:

  $ cp borders.c borders.c.orig

Make your modifications and the run diff:

  $ diff -u borders.c.orig borders.c

(or if your diff doesn't support the -u option, use -c instead).

We always appreciate optimizing the code.  On the other hand, the
new feature can be implemented with a very small change.  All you
have to do is skip the drawing command when a certain colour is
used.  I have applied a patch that uses colour 4 for this feature.

If you want help cleaning this ugly mess up a bit, please download
the latest snapshot or code from cvs first and redo your changes.
I am currently busy with exactly the files you modified too, so it
can become a bit difficult to keep the patches up to date.
Finally, if you do download the development code, don't expect
much of it.  It needs another week before window titles and window
shading work well again.

Yes, very good work.  I hope I didn't discourage you from
contributing that work is definitely helpful.

> The variable use_fgbg remains just because of an optimization when

Ah, forget it.  A few extra CPU cycles are not worth the effort.
DrawLinePattern() can calculate what it needs to know when it's
called.

Bye

Dominik ^_^  ^_^

 --
Dominik Vogt, [email-masked]
Reply-To: [email-masked]
--
Visit the official FVWM web page at <URL:http://www.fvwm.org/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked]